commit 14ff9d109f5322d25e350f7cc14a49eaad22bb11 Author: TermiNexus Date: Mon Aug 17 11:01:35 2026 +0800 从 TransPyC 主项目中分离 VRTE diff --git a/__builtin.py.bak b/__builtin.py.bak new file mode 100644 index 0000000..8795ba4 --- /dev/null +++ b/__builtin.py.bak @@ -0,0 +1,425 @@ +# GCC/Clang Built-in Function Declarations +# All functions are declared only (t.State equivalent to CExtern | CExport); implementations are provided by compiler/runtime +import t + + +# ============================================================ +# Random Number Generation (RDRAND / RDSEED) +# ============================================================ + +def __builtin_ia32_rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# Time-Stamp Counter (RDTSC / RDTSCP) +# ============================================================ + +def __builtin_ia32_rdtsc() -> t.CUInt64T | t.State: pass +def __builtin_ia32_rdtscp(p: t.CUInt32T | t.CPtr) -> t.CUInt64T | t.State: pass +def __builtin_ia32_rdpmc(counter: t.CUInt32T) -> t.CUInt64T | t.State: pass + + +# ============================================================ +# CPUID +# ============================================================ + +def __builtin_ia32_cpuid(level: t.CUInt32T, a: t.CUInt32T | t.CPtr, b: t.CUInt32T | t.CPtr, c: t.CUInt32T | t.CPtr, d: t.CUInt32T | t.CPtr) -> t.CUInt32T | t.State: pass +def __builtin_ia32_cpuid_count(level: t.CUInt32T, count: t.CUInt32T, a: t.CUInt32T | t.CPtr, b: t.CUInt32T | t.CPtr, c: t.CUInt32T | t.CPtr, d: t.CUInt32T | t.CPtr) -> t.CUInt32T | t.State: pass + + +# ============================================================ +# Memory Barriers (Fence) +# ============================================================ + +def __builtin_ia32_lfence() -> t.State: pass +def __builtin_ia32_mfence() -> t.State: pass +def __builtin_ia32_sfence() -> t.State: pass +def __builtin_ia32_pause() -> t.State: pass + + +# ============================================================ +# Bit Manipulation (POPCNT / BSF / BSR / TZCNT / LZCNT / BEXTR / PDEP / PEXT / ANDN) +# ============================================================ + +def __builtin_ia32_popcntsi(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_ia32_popcntdi(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_ia32_popcntqi(x: t.CUInt64T) -> t.CInt | t.State: pass + +def __builtin_ia32_bsfsi(src: t.CUInt32T, dst: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_bsrsi(src: t.CUInt32T, dst: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_bsfqi(src: t.CUInt64T, dst: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_bsrqi(src: t.CUInt64T, dst: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass + +def __builtin_ia32_tzcntsi(x: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_tzcntdi(x: t.CUInt64T) -> t.CUInt64T | t.State: pass +def __builtin_ia32_lzcntsi(x: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_lzcntdi(x: t.CUInt64T) -> t.CUInt64T | t.State: pass + +def __builtin_ia32_bextrsi(src: t.CUInt32T, start: t.CUInt32T, len: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_bextrdi(src: t.CUInt64T, start: t.CUInt32T, len: t.CUInt32T) -> t.CUInt64T | t.State: pass + +def __builtin_ia32_pdep_si(src: t.CUInt32T, mask: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_pext_si(src: t.CUInt32T, mask: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_pdep_di(src: t.CUInt64T, mask: t.CUInt64T) -> t.CUInt64T | t.State: pass +def __builtin_ia32_pext_di(src: t.CUInt64T, mask: t.CUInt64T) -> t.CUInt64T | t.State: pass + +def __builtin_ia32_andn_si(a: t.CUInt32T, b: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_andn_di(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T | t.State: pass + + +# ============================================================ +# Byte Swap (BSWAP) +# ============================================================ + +def __builtin_bswap16(x: t.CUInt16T) -> t.CUInt16T | t.State: pass +def __builtin_bswap32(x: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_bswap64(x: t.CUInt64T) -> t.CUInt64T | t.State: pass + + +# ============================================================ +# Cache Operations +# ============================================================ + +def __builtin_ia32_clflush(p: t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_clflushopt(p: t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_clwb(p: t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_clzero() -> t.State: pass + + +# ============================================================ +# Prefetch +# ============================================================ + +def __builtin_prefetch(addr: t.CConst | t.CPtr, rw: t.CInt = 0, locality: t.CInt = 3) -> t.State: pass +def __builtin_ia32_prefetch0(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_prefetch1(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_prefetch2(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_prefetchnta(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass + + +# ============================================================ +# Non-Temporal Stores +# ============================================================ + +def __builtin_ia32_movnti(p: t.CUInt32T | t.CPtr, val: t.CUInt32T) -> t.State: pass +def __builtin_ia32_movnti64(p: t.CUInt64T | t.CPtr, val: t.CUInt64T) -> t.State: pass +def __builtin_ia32_movntdq(p: t.CPtr, val: t.CPtr) -> t.State: pass +def __builtin_ia32_movntps(p: t.CFloat | t.CPtr, val: t.CFloat) -> t.State: pass +def __builtin_ia32_movntpd(p: t.CDouble | t.CPtr, val: t.CDouble) -> t.State: pass + + +# ============================================================ +# I/O Port Operations +# ============================================================ + +def __builtin_ia32_inb(port: t.CUInt16T) -> t.CUInt8T | t.State: pass +def __builtin_ia32_inw(port: t.CUInt16T) -> t.CUInt16T | t.State: pass +def __builtin_ia32_inl(port: t.CUInt16T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_outb(val: t.CUInt8T, port: t.CUInt16T) -> t.State: pass +def __builtin_ia32_outw(val: t.CUInt16T, port: t.CUInt16T) -> t.State: pass +def __builtin_ia32_outl(val: t.CUInt32T, port: t.CUInt16T) -> t.State: pass + + +# ============================================================ +# Model-Specific Registers (MSR) +# ============================================================ + +def __builtin_ia32_rdmsr(msr: t.CUInt32T, val: t.CUInt64T | t.CPtr) -> t.State: pass +def __builtin_ia32_wrmsr(msr: t.CUInt32T, val: t.CUInt64T) -> t.State: pass + + +# ============================================================ +# System Instructions +# ============================================================ + +def __builtin_ia32_hlt() -> t.State: pass +def __builtin_ia32_invd() -> t.State: pass +def __builtin_ia32_wbinvd() -> t.State: pass +def __builtin_ia32_invlpg(p: t.CPtr) -> t.State: pass +def __builtin_ia32_clts() -> t.State: pass +def __builtin_ia32_cli() -> t.State: pass +def __builtin_ia32_sti() -> t.State: pass +def __builtin_ia32_int3() -> t.State: pass +def __builtin_ia32_int(n: t.CUInt8T) -> t.State: pass +def __builtin_ia32_ud2() -> t.State: pass + + +# ============================================================ +# Descriptor Tables (GDT / IDT / LDT / TR) +# ============================================================ + +def __builtin_ia32_lgdt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_sgdt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_lidt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_sidt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_lldt(sel: t.CUInt32T) -> t.State: pass +def __builtin_ia32_sldt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_ltr(sel: t.CUInt32T) -> t.State: pass +def __builtin_ia32_str(p: t.CPtr) -> t.State: pass + + +# ============================================================ +# Control Registers (CR / MSW) +# ============================================================ + +def __builtin_ia32_lmsw(val: t.CUInt32T) -> t.State: pass +def __builtin_ia32_smsw(p: t.CPtr) -> t.State: pass + + +# ============================================================ +# Monitor / MWAIT +# ============================================================ + +def __builtin_ia32_monitor(p: t.CPtr, extensions: t.CUInt32T, hints: t.CUInt32T) -> t.State: pass +def __builtin_ia32_mwait(extensions: t.CUInt32T, hints: t.CUInt32T) -> t.State: pass + + +# ============================================================ +# XSAVE State Operations +# ============================================================ + +def __builtin_ia32_xsave(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xrstor(p: t.CConst | t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xsaveopt(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xsavec(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xrstors(p: t.CConst | t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xsaves(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass + + +# ============================================================ +# Generic Built-in Functions +# ============================================================ + +def __builtin_expect(exp: t.CLong, c: t.CLong) -> t.CLong | t.State: pass +def __builtin_unreachable() -> t.State: pass +def __builtin_trap() -> t.State: pass +def __builtin_abort() -> t.State: pass +def __builtin_assume_aligned(addr: t.CConst | t.CPtr, align: t.CSizeT, *args) -> t.CPtr | t.State: pass +def __builtin_constant_p(expr: t.CVoid) -> t.CInt | t.State: pass +def __builtin_types_compatible_p(t1: t.CVoid, t2: t.CVoid) -> t.CInt | t.State: pass +def __builtin_choose_expr(const_exp: t.CUInt32T, exp1: t.CVoid, exp2: t.CVoid) -> t.CPtr | t.State: pass +def __builtin_offsetof(typ: t.CVoid, member: t.CVoid) -> t.CSizeT | t.State: pass +def __builtin_function_start(func: t.CPtr) -> t.CPtr | t.State: pass + + +# ============================================================ +# Variable Arguments (VaList) +# ============================================================ + +def __builtin_va_start(va: t.CPtr, *args) -> t.State: pass +def __builtin_va_end(va: t.CPtr) -> t.State: pass +def __builtin_va_arg(va: t.CPtr, typ: t.CVoid) -> t.State: pass +def __builtin_va_copy(dst: t.CPtr, src: t.CConst | t.CPtr) -> t.State: pass + + +# ============================================================ +# Stack & Call Information +# ============================================================ + +def __builtin_return_address(level: t.CUInt32T) -> t.CPtr | t.State: pass +def __builtin_frame_address(level: t.CUInt32T) -> t.CPtr | t.State: pass +def __builtin_alloca(size: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_alloca_with_align(size: t.CSizeT, alignment: t.CSizeT) -> t.CPtr | t.State: pass + + +# ============================================================ +# Memory Operations +# ============================================================ + +def __builtin_memcpy(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memset(s: t.CPtr, c: t.CInt, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memmove(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memcmp(s1: t.CConst | t.CPtr, s2: t.CConst | t.CPtr, n: t.CSizeT) -> t.CInt | t.State: pass +def __builtin_mempcpy(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memchr(s: t.CConst | t.CPtr, c: t.CInt, n: t.CSizeT) -> t.CPtr | t.State: pass + + +# ============================================================ +# String Operations +# ============================================================ + +def __builtin_strcpy(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strncpy(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strcat(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strncat(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strlen(s: t.CChar | t.CConst | t.CPtr) -> t.CSizeT | t.State: pass +def __builtin_strcmp(s1: t.CChar | t.CConst | t.CPtr, s2: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.State: pass +def __builtin_strncmp(s1: t.CChar | t.CConst | t.CPtr, s2: t.CChar | t.CConst | t.CPtr, n: t.CSizeT) -> t.CInt | t.State: pass +def __builtin_strchr(s: t.CChar | t.CConst | t.CPtr, c: t.CInt) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strrchr(s: t.CChar | t.CConst | t.CPtr, c: t.CInt) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strstr(haystack: t.CChar | t.CConst | t.CPtr, needle: t.CChar | t.CConst | t.CPtr) -> t.CChar | t.CPtr | t.State: pass + + +# ============================================================ +# Math Built-in Functions +# ============================================================ + +def __builtin_sqrt(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_sqrtf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_sqrtl(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_powf(x: t.CFloat, y: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_sin(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_sinf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_cos(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_cosf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_tan(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_tanf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_atan(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_exp(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_log(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_log2(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_log10(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_fabs(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_fabsf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_abs(x: t.CInt) -> t.CInt | t.State: pass +def __builtin_labs(x: t.CLong) -> t.CLong | t.State: pass +def __builtin_llabs(x: t.CInt64T) -> t.CInt64T | t.State: pass +def __builtin_fma(x: t.CDouble, y: t.CDouble, z: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_floor(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_ceil(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_trunc(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_round(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_nearbyint(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_rint(x: t.CDouble) -> t.CDouble | t.State: pass + + +# ============================================================ +# Bit Counting Builtins +# ============================================================ + +def __builtin_ffs(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_clz(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_ctz(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_popcount(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_parity(x: t.CUInt32T) -> t.CInt | t.State: pass + +def __builtin_ffsl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_clzl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_ctzl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_popcountl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_parityl(x: t.CULong) -> t.CInt | t.State: pass + +def __builtin_ffsll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_clzll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_ctzll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_popcountll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_parityll(x: t.CUInt64T) -> t.CInt | t.State: pass + + +# ============================================================ +# Object Size Checking +# ============================================================ + +def __builtin_object_size(ptr: t.CConst | t.CPtr, typ: t.CInt) -> t.CSizeT | t.State: pass +def __builtin_dynamic_object_size(ptr: t.CConst | t.CPtr, typ: t.CInt) -> t.CSizeT | t.State: pass + +def __builtin___memcpy_chk(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___memmove_chk(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___memset_chk(s: t.CPtr, c: t.CInt, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___mempcpy_chk(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___strcpy_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___strncpy_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___strcat_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___strncat_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___snprintf_chk(s: t.CChar | t.CPtr, maxlen: t.CSizeT, flag: t.CInt, slen: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.State: pass +def __builtin___sprintf_chk(s: t.CChar | t.CPtr, flag: t.CInt, slen: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.State: pass + + +# ============================================================ +# Floating-Point Classification +# ============================================================ + +def __builtin_isnan(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isinf(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isinf_sign(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isfinite(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isnormal(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_signbit(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isgreater(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isgreaterequal(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isless(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_islessequal(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_islessgreater(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isunordered(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass + + +# ============================================================ +# Special Floating-Point Values +# ============================================================ + +def __builtin_nan(s: t.CChar | t.CConst | t.CPtr) -> t.CDouble | t.State: pass +def __builtin_nanf(s: t.CChar | t.CConst | t.CPtr) -> t.CFloat | t.State: pass +def __builtin_nanl(s: t.CChar | t.CConst | t.CPtr) -> t.CDouble | t.State: pass +def __builtin_nans(s: t.CChar | t.CConst | t.CPtr) -> t.CDouble | t.State: pass +def __builtin_nansf(s: t.CChar | t.CConst | t.CPtr) -> t.CFloat | t.State: pass +def __builtin_inf() -> t.CDouble | t.State: pass +def __builtin_inff() -> t.CFloat | t.State: pass +def __builtin_infl() -> t.CDouble | t.State: pass +def __builtin_huge_val() -> t.CDouble | t.State: pass +def __builtin_huge_valf() -> t.CFloat | t.State: pass +def __builtin_huge_vall() -> t.CDouble | t.State: pass +def __builtin_inf_sign() -> t.CInt | t.State: pass + + +# ============================================================ +# Type Conversion & Overflow Checking +# ============================================================ + +def __builtin_add_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_sub_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_mul_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_sadd_overflow(a: t.CInt64T, b: t.CInt64T, res: t.CInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_ssub_overflow(a: t.CInt64T, b: t.CInt64T, res: t.CInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_smul_overflow(a: t.CInt64T, b: t.CInt64T, res: t.CInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_uadd_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_usub_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_umul_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass + + +# ============================================================ +# MMX / SSE State Management +# ============================================================ + +def __builtin_ia32_emms() -> t.State: pass +def __builtin_ia32_femms() -> t.State: pass + + +# ============================================================ +# Enqueue Commands (ENQCMD) +# ============================================================ + +def __builtin_ia32_enqcmd(dst: t.CPtr, src: t.CConst | t.CPtr) -> t.CBool | t.State: pass +def __builtin_ia32_enqcmds(dst: t.CPtr, src: t.CConst | t.CPtr) -> t.CBool | t.State: pass + + +# ============================================================ +# User-Level Monitor & Wait (UMWAIT / UMONITOR / TPAUSE) +# ============================================================ + +def __builtin_ia32_umonitor(p: t.CPtr) -> t.State: pass +def __builtin_ia32_umwait(extensions: t.CUInt32T, counter: t.CUInt64T) -> t.CUInt8T | t.State: pass +def __builtin_ia32_tpause(extensions: t.CUInt32T, counter: t.CUInt64T) -> t.CUInt8T | t.State: pass + + +# ============================================================ +# Access Control (CLAC / STAC) +# ============================================================ + +def __builtin_ia32_clac() -> t.State: pass +def __builtin_ia32_stac() -> t.State: pass + + +# ============================================================ +# TLB Invalidation (INVLPG Variants) +# ============================================================ + +def __builtin_ia32_invlpgb(aux: t.CUInt64T, pcid: t.CUInt64T) -> t.State: pass +def __builtin_ia32_tlbsync() -> t.State: pass \ No newline at end of file diff --git a/_dict.vp b/_dict.vp new file mode 100644 index 0000000..b8002e2 --- /dev/null +++ b/_dict.vp @@ -0,0 +1,271 @@ +import t, c +import memhub +import string +import json +from stdint import * + +# Variant type tags (consistent with _variant.py) +VARIANT_NONE: t.CDefine = 0 # Untyped / null value +VARIANT_INT: t.CDefine = 1 # int (i64) +VARIANT_FLOAT: t.CDefine = 2 # float (f32) +VARIANT_DOUBLE: t.CDefine = 3 # double (f64) +VARIANT_STR: t.CDefine = 4 # str (i8*) +VARIANT_DICT: t.CDefine = 5 # dict* +VARIANT_LIST: t.CDefine = 6 # list* +VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32) +VARIANT_PTR: t.CDefine = 8 # Custom pointer type + +# Variant structure size: vtype(i32, 4 bytes) + padding(4 bytes) + ptr(i8*, 8 bytes) = 16 bytes +_VARIANT_SIZE: t.CDefine = 16 + + +class dict: + """Heap-allocated dynamic dictionary container based on mbuddy allocator. + Key type is fixed to str (i8*), values are stored as Variant (type tag + untyped pointer). + Supports nested dict/list structures and JSON serialization. + + Usage: + mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size) + d: dict = dict(mb) + d.set_int("x", 42) + p: t.CPtr = d["x"] + v: int = c.Deref(p) + + # Nested dict + inner: dict = dict(mb) + inner.set_int("a", 1) + d.set_dict("sub", inner) + sub: dict = c.Deref(d["sub"]) + av: int = c.Deref(sub["a"]) + """ + __keys__: t.CPtr + __values__: t.CPtr + __count__: t.CSizeT = 0 + __capacity__: t.CSizeT = 8 + __mbuddy__: memhub.MemBuddy | t.CPtr + __iter_index__: t.CSizeT = 0 + + def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: + # Heap allocation for dict object + return mb.alloc(dict.__sizeof__()) + + def __init__(self, mb: memhub.MemBuddy | t.CPtr): + self.__mbuddy__ = mb + self.__keys__ = mb.alloc(self.__capacity__ * 8) + self.__values__ = mb.alloc(self.__capacity__ * _VARIANT_SIZE) + + def __len__(self) -> t.CSizeT: + return self.__count__ + + def _find(self, key: str) -> t.CSizeT: + """Find index of target key; returns __count__ if not found""" + for i in range(self.__count__): + key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + i * 8) + if string.strcmp(key_ptr[0], key) == 0: return i + return self.__count__ + + def __getitem__(self, key: str) -> t.CPtr: + """Return untyped pointer to value. Use c.Deref to resolve the actual value. + Example: p: t.CPtr = d["x"]; v: int = c.Deref(p)""" + idx: t.CSizeT = self._find(key) + if idx >= self.__count__: return None + # Variant.ptr is located at offset 8 within Variant structure + val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8) + return val_ptr[0] + + def __setitem__(self, key: str, val: t.CNeedPtr): + """Store value as VARIANT_PTR. Address is automatically resolved via t.CNeedPtr. + Note: Lifecycle of the data pointed to by val is managed by caller. + Use typed methods such as set_int / set_str for persistent storage.""" + self._set_variant_raw(key, VARIANT_PTR, val) + + def _set_variant_raw(self, key: str, vtype: t.CInt, ptr: t.CPtr): + """Internal method: store Variant entry (vtype + ptr). No automatic address resolution.""" + idx: t.CSizeT = self._find(key) + if idx < self.__count__: + # Update existing key + vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE) + vtype_ptr[0] = vtype + val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8) + val_ptr[0] = ptr + return + if self.__count__ >= self.__capacity__: + new_cap: t.CSizeT = self.__capacity__ * 2 + new_keys: t.CPtr = self.__mbuddy__.alloc(new_cap * 8) + new_values: t.CPtr = self.__mbuddy__.alloc(new_cap * _VARIANT_SIZE) + if new_keys is None or new_values is None: return + string.memcpy(new_keys, self.__keys__, self.__count__ * 8) + string.memcpy(new_values, self.__values__, self.__count__ * _VARIANT_SIZE) + self.__keys__ = new_keys + self.__values__ = new_values + self.__capacity__ = new_cap + key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + self.__count__ * 8) + key_ptr[0] = key + vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE) + vtype_ptr[0] = vtype + val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE + 8) + val_ptr[0] = ptr + self.__count__ += 1 + + # ============================================================ + # Typed setters — allocate persistent storage inside __mbuddy__ + # ============================================================ + + def set_int(self, key: str, val: int): + """Store integer value (VARIANT_INT). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + int_ptr: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + int_ptr[0] = val + self._set_variant_raw(key, VARIANT_INT, storage) + + def set_str(self, key: str, val: str): + """Store string value (VARIANT_STR). Raw string pointer is stored directly.""" + self._set_variant_raw(key, VARIANT_STR, val) + + def set_float(self, key: str, val: float): + """Store float value (VARIANT_FLOAT). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + float_ptr: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + float_ptr[0] = val + self._set_variant_raw(key, VARIANT_FLOAT, storage) + + def set_double(self, key: str, val: t.CDouble): + """Store double value (VARIANT_DOUBLE). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + dbl_ptr: t.CDouble | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + dbl_ptr[0] = val + self._set_variant_raw(key, VARIANT_DOUBLE, storage) + + def set_dict(self, key: str, val: dict | t.CPtr): + """Store nested dictionary pointer (VARIANT_DICT).""" + self._set_variant_raw(key, VARIANT_DICT, val) + + def set_list(self, key: str, val: t.CPtr): + """Store nested list pointer (VARIANT_LIST).""" + self._set_variant_raw(key, VARIANT_LIST, val) + + def set_bool(self, key: str, val: t.CInt): + """Store boolean value (VARIANT_BOOL). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + bool_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + bool_ptr[0] = val + self._set_variant_raw(key, VARIANT_BOOL, storage) + + # ============================================================ + # Query methods + # ============================================================ + + def get_vtype(self, key: str) -> t.CInt: + """Return Variant type tag associated with specified key.""" + idx: t.CSizeT = self._find(key) + if idx >= self.__count__: + return VARIANT_NONE + vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE, t.CPtr) + return vtype_ptr[0] + + def get(self, key: str, default: t.CPtr) -> t.CPtr: + """Return value pointer; return default pointer if key does not exist.""" + idx: t.CSizeT = self._find(key) + if idx >= self.__count__: + return default + val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8, t.CPtr) + return val_ptr[0] + + def contains(self, key: str) -> t.CInt: + """Check whether target key exists.""" + idx: t.CSizeT = self._find(key) + if idx < self.__count__: + return 1 + return 0 + + def __iter__(self) -> dict | t.CPtr: + self.__iter_index__ = 0 + return self + + def __next__(self) -> str: + if self.__iter_index__ >= self.__count__: + raise StopIteration + idx: t.CSizeT = self.__iter_index__ + self.__iter_index__ = idx + 1 + key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + idx * 8, t.CPtr) + return key_ptr[0] + + # ============================================================ + # JSON utilities: serialization / deserialization via includes/json library + # ============================================================ + + def to_json(self, pool: memhub.MemManager | t.CPtr) -> json.JsonValue | t.CPtr: + """Convert dict instance to JsonValue object (JSON_OBJECT). + Automatically select corresponding JSON value type according to Variant tag.""" + obj: json.JsonValue | t.CPtr = json.object(pool) + i: t.CSizeT = 0 + while i < self.__count__: + key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + i * 8, t.CPtr) + vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE, t.CPtr) + val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE + 8, t.CPtr) + vt: t.CInt = vtype_ptr[0] + vp: t.CPtr = val_ptr[0] + jv: json.JsonValue | t.CPtr = json.null(pool) + if jv != None: + if vt == VARIANT_INT: + jv.vtype = 2 # JSON_INT + ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.int_val = ip[0] + elif vt == VARIANT_STR: + jv.vtype = 4 # JSON_STRING + jv.str_val = vp + elif vt == VARIANT_BOOL: + jv.vtype = 1 # JSON_BOOL + bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.bool_val = bp[0] + elif vt == VARIANT_FLOAT: + jv.vtype = 3 # JSON_FLOAT + fp: float | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.float_val = fp[0] + elif vt == VARIANT_PTR: + # Fallback: treat raw pointer as integer + jv.vtype = 2 # JSON_INT + ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.int_val = ip[0] + json.object_set(pool, obj, key_ptr[0], jv) + i += 1 + return obj + + def from_json(self, pool: memhub.MemManager | t.CPtr, root: json.JsonValue | t.CPtr): + """Populate dict from JsonValue object. + Extract values and store them as matching Variant types based on JSON type tag.""" + if root == None: + return + if root.vtype != 6: # JSON_OBJECT + return + cur: json.JsonValue | t.CPtr = root.child + while cur != None: + if cur.key != None: + if cur.vtype == 2: # JSON_INT + storage: t.CPtr = self.__mbuddy__.alloc(8) + ip: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + ip[0] = cur.int_val + self._set_variant_raw(cur.key, VARIANT_INT, storage) + elif cur.vtype == 4: # JSON_STRING + self._set_variant_raw(cur.key, VARIANT_STR, cur.str_val) + elif cur.vtype == 1: # JSON_BOOL + storage: t.CPtr = self.__mbuddy__.alloc(8) + bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + bp[0] = cur.bool_val + self._set_variant_raw(cur.key, VARIANT_BOOL, storage) + elif cur.vtype == 3: # JSON_FLOAT + storage: t.CPtr = self.__mbuddy__.alloc(8) + fp: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + fp[0] = cur.float_val + self._set_variant_raw(cur.key, VARIANT_FLOAT, storage) + cur = cur.next + + def dumps(self, pool: memhub.MemManager | t.CPtr) -> str: + """Serialize dict to JSON string.""" + obj: json.JsonValue | t.CPtr = self.to_json(pool) + return json.write(pool, obj, False) + + def loads(self, pool: memhub.MemManager | t.CPtr, json_str: str): + """Parse JSON string and populate dict instance.""" + root: json.JsonValue | t.CPtr = json.parse(pool, json_str) + self.from_json(pool, root) diff --git a/_fakeduck.vp b/_fakeduck.vp new file mode 100644 index 0000000..2f45393 --- /dev/null +++ b/_fakeduck.vp @@ -0,0 +1,320 @@ +import t +import memhub +import string + + +class _Type: + def type_id(self) -> int: + return 99 + + +class _str: + # Compile-time metadata: declares that this class attempts to retrieve the __mbuddy__ field from the with context + # (optional; no error will be raised if the field cannot be located) + __requires__: list[str] = ['__mbuddy__'] + __data__: str + __mbuddy__: memhub.MemBuddy | t.CPtr + + def upper(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def lower(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def capitalize(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + first: bool = True + for i, ch in enumerate(src): + if first: + first = False + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + buf[i] = ch + else: + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def swapcase(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def title(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + prev_alpha: bool = False + for i, ch in enumerate(src): + cur_alpha: bool = False + if ch >= 65: + if ch <= 90: + cur_alpha = True + else: + if ch >= 97: + if ch <= 122: + cur_alpha = True + if cur_alpha: + if prev_alpha: + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + else: + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + buf[i] = ch + else: + buf[i] = ch + prev_alpha = cur_alpha + buf[length] = 0 + return str(buf) + + def casefold(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def isupper(self) -> bool: + src: str = self.__data__ + has_alpha: bool = False + for ch in src: + if ch >= 65: + if ch <= 90: + has_alpha = True + else: + if ch >= 97: + if ch <= 122: + return False + return has_alpha + + def islower(self) -> bool: + src: str = self.__data__ + has_alpha: bool = False + for ch in src: + if ch >= 97: + if ch <= 122: + has_alpha = True + if ch >= 65: + if ch <= 90: + return False + return has_alpha + + def isalpha(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + cur_alpha: bool = False + if ch >= 65: + if ch <= 90: + cur_alpha = True + else: + if ch >= 97: + if ch <= 122: + cur_alpha = True + if not cur_alpha: + return False + return has_char + + def isdigit(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + if ch >= 48: + if ch > 57: + return False + else: + return False + return has_char + + def isalnum(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + ok: bool = False + if ch >= 48: + if ch <= 57: + ok = True + if not ok: + if ch >= 65: + if ch <= 90: + ok = True + else: + if ch >= 97: + if ch <= 122: + ok = True + if not ok: + return False + return has_char + + def isspace(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + is_space: bool = False + if ch == 32 or ch == 9 or ch == 10 or ch == 13 or ch == 11 or ch == 12: + is_space = True + if not is_space: + return False + return has_char + + def isascii(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + if ch > 127: return False + return has_char + + def istitle(self) -> bool: + src: str = self.__data__ + has_char: bool = False + prev_alpha: bool = False + for ch in src: + has_char = True + cur_alpha: bool = False + if ch >= 65: + if ch <= 90: + cur_alpha = True + else: + if ch >= 97: + if ch <= 122: + cur_alpha = True + if cur_alpha: + if not prev_alpha: + if ch >= 97: + if ch <= 122: + return False + else: + if ch >= 65: + if ch <= 90: + return False + prev_alpha = cur_alpha + return has_char + + def split(self, delimiter: str) -> list[str]: + result = list[str](self.__mbuddy__) + src: str = self.__data__ + length: t.CSizeT = len(src) + delim_len: t.CSizeT = string.strlen(delimiter) + start: t.CSizeT = 0 + i: t.CSizeT = 0 + cur: str = src + sub_len: t.CSizeT = 0 + sub: bytes = None + src_off: bytes = None + term: bytes = None + if delim_len == 0: + sub_len = length + sub = self.__mbuddy__.alloc(sub_len + 1) + if sub != None: + src_off = bytes(t.CUInt64T(src) + start) + string.memcpy(sub, src_off, sub_len) + term = sub + term[sub_len] = 0 + result.append(str(sub)) + return result + while i + delim_len <= length: + if string.strncmp(cur, delimiter, delim_len) == 0: + sub_len = i - start + sub = self.__mbuddy__.alloc(sub_len + 1) + if sub != None: + src_off = bytes(t.CUInt64T(src) + start) + string.memcpy(sub, src_off, sub_len) + term = sub + term[sub_len] = 0 + result.append(str(sub)) + start = i + delim_len + cur += delim_len + i += delim_len + else: + cur += 1 + i += 1 + sub_len = length - start + sub = self.__mbuddy__.alloc(sub_len + 1) + if sub != None: + src_off = bytes(t.CUInt64T(src) + start) + string.memcpy(sub, src_off, sub_len) + term = sub + term[sub_len] = 0 + result.append(str(sub)) + return result diff --git a/_list.vp b/_list.vp new file mode 100644 index 0000000..5e60cf6 --- /dev/null +++ b/_list.vp @@ -0,0 +1,90 @@ +import t, c +import memhub +import string +from stdint import * + + +class list[T]: + """Heap-allocated dynamic list container backed by memhub.MemManager polymorphic allocator. + + Usage: + pool: memhub.MemManager = memhub.MemBuddy(arena, arena_size) + nums: list[int] = list[int](pool) + nums.append(42) + x: int = nums.get(0) + + For pointer types (e.g. AST | t.CPtr), pass elem_size=8 to avoid object slicing: + lst: list[AST | t.CPtr] = list[AST | t.CPtr](pool, 8) + """ + __data__: t.CVoid | t.CPtr + __count__: t.CSizeT + __capacity__: t.CSizeT + __pool__: memhub.MemManager | t.CPtr + __elem_size__: t.CSizeT + __iter_index__: t.CSizeT + + def __new__(self, pool: memhub.MemManager | t.CPtr, elem_size: t.CSizeT = 0): + ret = pool.alloc(48) + return ret + + def __init__(self, pool: memhub.MemManager | t.CPtr, elem_size: t.CSizeT = 0): + self.__pool__ = pool + self.__count__ = 0 + self.__capacity__ = 8 + if elem_size == 0: + self.__elem_size__ = T.__sizeof__() + else: + self.__elem_size__ = elem_size + self.__data__ = pool.alloc(self.__capacity__ * self.__elem_size__) + self.__iter_index__ = 0 + + def __len__(self) -> t.CSizeT: + return self.__count__ + + def append(self, item: T): + if self.__count__ >= self.__capacity__: + new_cap: t.CSizeT = self.__capacity__ * 2 + new_data: t.CPtr = self.__pool__.alloc(new_cap * self.__elem_size__) + if new_data == None: return + string.memcpy(new_data, self.__data__, self.__count__ * self.__elem_size__) + self.__data__ = new_data + self.__capacity__ = new_cap + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + self.__count__ * self.__elem_size__) + elem_ptr[0] = item + self.__count__ += 1 + + def get(self, index: t.CSizeT) -> T: + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + return elem_ptr[0] + + def __getitem__(self, index: t.CSizeT) -> T: + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + return elem_ptr[0] + + def set(self, index: t.CSizeT, value: T): + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + elem_ptr[0] = value + + def __setitem__(self, index: t.CSizeT, value: T): + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + elem_ptr[0] = value + + def pop(self) -> T: + self.__count__ -= 1 + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + self.__count__ * self.__elem_size__) + return elem_ptr[0] + + def clear(self): + self.__count__ = 0 + + def __iter__(self) -> list[T] | t.CPtr: + self.__iter_index__ = 0 + return self + + def __next__(self) -> T: + if self.__iter_index__ >= self.__count__: + raise StopIteration + idx: t.CSizeT = self.__iter_index__ + self.__iter_index__ = idx + 1 + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + idx * self.__elem_size__) + return elem_ptr[0] diff --git a/_variant.vp b/_variant.vp new file mode 100644 index 0000000..31273dc --- /dev/null +++ b/_variant.vp @@ -0,0 +1,64 @@ +import t, c +from stdint import * + +# Variant type tags (fixed enumeration + custom pointer type) +VARIANT_NONE: t.CDefine = 0 # Untyped / null value +VARIANT_INT: t.CDefine = 1 # int (i64) +VARIANT_FLOAT: t.CDefine = 2 # float (f32) +VARIANT_DOUBLE: t.CDefine = 3 # double (f64) +VARIANT_STR: t.CDefine = 4 # str (i8*) +VARIANT_DICT: t.CDefine = 5 # dict* +VARIANT_LIST: t.CDefine = 6 # list* +VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32) +VARIANT_PTR: t.CDefine = 8 # Custom pointer type + + +class Variant: + """Generic variant type storing a type tag and untyped pointer. + Used for universal object storage inside dict/list, supports nesting and JSON serialization. + + Usage: + v: Variant = Variant(VARIANT_INT, t.CNeedPtr(42)) + v2: Variant = Variant(VARIANT_STR, t.CNeedPtr("hello")) + + # Retrieve value + ptr: t.CPtr = v.ptr + i: int = c.Deref(ptr) + """ + vtype: int + ptr: t.CPtr + + def __init__(self, vtype: int, val: t.CNeedPtr): + """Construct Variant instance. + t.CNeedPtr automatically obtains address of val (non-pointer values will be allocated on stack and stored). + Note: The lifecycle of val is managed by the caller; Variant only stores a pointer reference. + """ + self.vtype = vtype + self.ptr = val + + def is_none(self) -> int: + return self.vtype == VARIANT_NONE + + def is_int(self) -> int: + return self.vtype == VARIANT_INT + + def is_float(self) -> int: + return self.vtype == VARIANT_FLOAT + + def is_double(self) -> int: + return self.vtype == VARIANT_DOUBLE + + def is_str(self) -> int: + return self.vtype == VARIANT_STR + + def is_dict(self) -> int: + return self.vtype == VARIANT_DICT + + def is_list(self) -> int: + return self.vtype == VARIANT_LIST + + def is_bool(self) -> int: + return self.vtype == VARIANT_BOOL + + def is_ptr(self) -> int: + return self.vtype == VARIANT_PTR diff --git a/_withcontent.vp b/_withcontent.vp new file mode 100644 index 0000000..4bd7bd7 --- /dev/null +++ b/_withcontent.vp @@ -0,0 +1,75 @@ +import t, c +from stdint import * +from w32.win32process import TlsAlloc, TlsGetValue, TlsSetValue +import stdlib +import stdio +import string + + +# Maximum provider stack depth (compiler verifies sufficiency; increase if needed) +_MAX_PROVIDER_DEPTH: t.CDefine = 32 + + +@t.Object +class _ProviderStack: + """Provider stack, stores pairs of field names and pointers.""" + names: t.CArray[VOIDPTR, 32] + ptrs: t.CArray[VOIDPTR, 32] + top: UINT64 + + +# TLS index (global; all threads share the same index) +_tls_index: ULONG = 0 + + +@t.TLS +def _init_tls(): + """Initialize TLS index (executes once; subsequent calls are skipped).""" + global _tls_index + # 双保险:TPV 已正式实现 @t.TLS(函数级一次性守卫,首次执行后置 + # __tls_init_done 标志,后续调用直接返回),此判重守卫保留以兼容 + # 尚未重建的旧 TPV.exe。_tls_index 初始为 0(TlsAlloc 成功不会返回 0)。 + if _tls_index == 0: + _tls_index = TlsAlloc() + + +def _get_stack() -> _ProviderStack | t.CPtr: + """Obtain current thread's provider stack. Allocate one if none exists.""" + _init_tls() + stack: _ProviderStack | t.CPtr = TlsGetValue(_tls_index) + if stack == None: + stack = stdlib.malloc(_ProviderStack.__sizeof__()) + string.memset(stack, 0, _ProviderStack.__sizeof__()) + TlsSetValue(_tls_index, stack) + return stack + + +def _push_provider(field_name: str, ptr: t.CPtr): + """Push a provider (field_name, ptr) onto the stack.""" + stack: _ProviderStack | t.CPtr = _get_stack() + if stack.top >= _MAX_PROVIDER_DEPTH: + stdio.printf("[with] ERROR: provider stack overflow (depth=%lu, max=%d), field '%s' not injected\n", stack.top, _MAX_PROVIDER_DEPTH, field_name) + return + stack.names[stack.top] = field_name + stack.ptrs[stack.top] = ptr + stack.top = stack.top + 1 + + +def _pop_provider(): + """Pop the top provider entry from the stack.""" + stack: _ProviderStack | t.CPtr = _get_stack() + if stack.top > 0: + stack.top = stack.top - 1 + + +def _find_provider(field_name: str) -> t.CPtr: + """Search for matching field_name starting from stack top. + Return associated pointer, or NULL if no match found.""" + stack: _ProviderStack | t.CPtr = _get_stack() + for i in range(stack.top - 1, -1, -1): + # 字段名用 strcmp 内容比较:编译器对每次 create_global_string 生成 + # 独立的字符串常量(TPV 不去重),push/find 的指针地址不同, + # 指针 == 永假会导致 provider 匹配失败(__mbuddy__ 注入不上)。 + if string.strcmp((str)(stack.names[i]), field_name) == 0: + return stack.ptrs[i] + return None \ No newline at end of file diff --git a/argparse.vp b/argparse.vp new file mode 100644 index 0000000..1e8bdd7 --- /dev/null +++ b/argparse.vp @@ -0,0 +1,460 @@ +import t, c +import string +import memhub +import stdio +import hashtable + + +# ============================================================ +# argparse.vp — Command line argument parsing library, inspired by Python argparse +# +# Usage: +# argparse._mbuddy = mb +# parser = argparse.ArgumentParser("myprog", "A test", pool=mb) +# parser.add_argument("--input", "-i", arg_type=argparse.STRING, +# required=True, help="input file") +# parser.add_argument("--count", "-c", arg_type=argparse.INT, +# default=0, help="repeat count") +# parser.add_argument("--verbose", "-v", action=argparse.STORE_TRUE, +# help="verbose mode") +# parser.add_argument("output", arg_type=argparse.STRING, +# help="output path") +# args = parser.parse_args(argc, argv) +# if args is not None: +# inp: str = args.get_str("input") +# cnt: int = args.get_int("count") +# verb: bool = args.get_bool("verbose") +# out: str = args.get_str("output") +# argparse.release(args) +# ============================================================ + +# Type constants +STRING: t.CDefine = 0 +INT: t.CDefine = 1 +BOOL: t.CDefine = 2 + +# Action constants +STORE: t.CDefine = 0 +STORE_TRUE: t.CDefine = 1 +STORE_FALSE: t.CDefine = 2 +COUNT: t.CDefine = 3 + +# Limits +MAX_ARGS: t.CDefine = 32 + +# Module-level membuddy pointer (assigned inside main by user) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================ +# Argument — Argument definition structure +# ============================================================ + +class Argument: + name: str # "--input" or positional "output" + short_name: str # "-i" or null + help_text: str # Help description text + arg_type: int # STRING, INT, BOOL + action: int # STORE, STORE_TRUE, STORE_FALSE, COUNT + default_int: int # Default value for integer types + default_str: str # Default value for string types + required: bool # Whether this argument is mandatory + is_positional: bool # True for positional parameters + dest: str # Lookup key ("--input" → "input") + + +# ============================================================ +# ParsedArgs — Parsing result container +# ============================================================ + +class ParsedArgs: + _ht: hashtable.HashTable | t.CPtr + __mbuddy__: memhub.MemBuddy | t.CPtr + + def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: + return mb.alloc(16) + + def __init__(self, mb: memhub.MemBuddy | t.CPtr): + self.__mbuddy__ = mb + self._ht = hashtable.HashTable(mb) + + def get_str(self, name: str) -> str: + """Fetch string value. Returns None if key not found.""" + if self._ht.__contains__(name) == 0: + return None + r: str = self._ht[name] + return r + + def get_int(self, name: str) -> int: + """Fetch integer value. Returns 0 if key not found.""" + if self._ht.__contains__(name) == 0: + return 0 + ptr: t.CPtr = self._ht[name] + return c.Deref(t.CInt(t.CUInt64T(ptr), t.CPtr)) + + def get_bool(self, name: str) -> bool: + """Fetch boolean value. Returns false if key not found.""" + if self._ht.__contains__(name) == 0: + return False + ptr: t.CPtr = self._ht[name] + return c.Deref(t.CInt(t.CUInt64T(ptr), t.CPtr)) != 0 + + def has(self, name: str) -> bool: + """Check whether specified key exists.""" + return self._ht.__contains__(name) != 0 + + def _set_str(self, name: str, val: str): + self._ht.set_str(name, val) + + def _set_int(self, name: str, val: int): + self._ht.set_int(name, val) + + def _set_bool(self, name: str, val: bool): + if val: + self._ht.set_int(name, 1) + else: + self._ht.set_int(name, 0) + + +# ============================================================ +# ArgumentParser — Command line argument parser +# ============================================================ + +class ArgumentParser: + _prog: str + _description: str + _args: Argument | t.CPtr + _arg_count: int + __mbuddy__: memhub.MemBuddy | t.CPtr + + def __new__(self, prog: str = "", description: str = "", + pool: memhub.MemBuddy | t.CPtr = None) -> t.CPtr: + mb: memhub.MemBuddy | t.CPtr = pool + if mb is None: + mb = _mbuddy + ret: t.CPtr = mb.alloc(40) + return ret + + def __init__(self, prog: str = "", description: str = "", + pool: memhub.MemBuddy | t.CPtr = None): + mb: memhub.MemBuddy | t.CPtr = pool + if mb is None: + mb = _mbuddy + self.__mbuddy__ = mb + self._prog = prog + self._description = description + self._arg_count = 0 + self._args = mb.alloc(MAX_ARGS * Argument.__sizeof__()) + + def add_argument(self, name: str = "", short: str = None, + arg_type: int = 0, default: int = 0, + default_str: str = None, required: bool = False, + action: int = 0, help: str = None): + """Register a command line argument. + + Args: + name: Argument name ("--input" or positional "output") + short: Short option ("-i"), optional + arg_type: Data type (STRING/INT/BOOL) + default: Default integer value + default_str: Default string value + required: Mandatory flag + action: Action mode (STORE/STORE_TRUE/STORE_FALSE/COUNT) + help: Help description text + """ + if self._arg_count >= MAX_ARGS: + return + idx: int = self._arg_count + arg: Argument | t.CPtr = t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__()) + arg.name = name + arg.short_name = short + arg.help_text = help + arg.arg_type = arg_type + arg.action = action + arg.default_int = default + arg.default_str = default_str + arg.required = required + # Determine positional flag + if name is not None and name[0] != '-': + arg.is_positional = True + arg.dest = name + else: + arg.is_positional = False + if name is not None and name[0] == '-' and name[1] == '-': + arg.dest = name + 2 + else: + arg.dest = name + 1 + self._arg_count = idx + 1 + + def _get_arg(self, idx: int) -> Argument | t.CPtr: + return t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__()) + + def _find_long(self, token: str) -> int: + """Exact match for long option name""" + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if string.strcmp(arg.name, token) == 0: + return i + i += 1 + return -1 + + def _find_long_prefix(self, token: str) -> int: + """Match prefix for --name=value syntax""" + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + name_len: int = string.strlen(arg.name) + if string.strncmp(token, arg.name, name_len) == 0: + if token[name_len] == '=': + return i + i += 1 + return -1 + + def _find_short(self, token: str) -> int: + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.short_name is not None: + if string.strcmp(arg.short_name, token) == 0: + return i + i += 1 + return -1 + + def _find_positional(self, pos_idx: int) -> int: + count: int = 0 + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.is_positional: + if count == pos_idx: + return i + count += 1 + i += 1 + return -1 + + def _store_value(self, args: ParsedArgs | t.CPtr, + arg: Argument | t.CPtr, value: str): + if arg.arg_type == INT: + args._set_int(arg.dest, string.atoi(value)) + elif arg.arg_type == STRING: + args._set_str(arg.dest, value) + elif arg.arg_type == BOOL: + v: int = string.atoi(value) + args._set_bool(arg.dest, v != 0) + + def _apply_action(self, args: ParsedArgs | t.CPtr, arg: Argument | t.CPtr): + if arg.action == STORE_TRUE: + args._set_bool(arg.dest, True) + elif arg.action == STORE_FALSE: + args._set_bool(arg.dest, False) + elif arg.action == COUNT: + cur: int = args.get_int(arg.dest) + args._set_int(arg.dest, cur + 1) + + def parse_args(self, argc: int, argv: str | t.CPtr) -> ParsedArgs | t.CPtr: + """Parse command line arguments. + + Args: + argc: Argument count + argv: Argument array (char**, argv[0] = program name) + Returns: + Pointer to ParsedArgs; returns None on failure + """ + if self.__mbuddy__ is None: + return None + + args: ParsedArgs | t.CPtr = ParsedArgs(self.__mbuddy__) + if args is None: + return None + # Initialize default values + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.action == STORE: + if arg.arg_type == INT: + args._set_int(arg.dest, arg.default_int) + elif arg.arg_type == STRING: + args._set_str(arg.dest, arg.default_str) + elif arg.action == STORE_TRUE: + args._set_bool(arg.dest, False) + elif arg.action == STORE_FALSE: + args._set_bool(arg.dest, True) + elif arg.action == COUNT: + args._set_int(arg.dest, 0) + i += 1 + + # Traverse argv + idx: int = 1 + pos_idx: int = 0 + token: str = None + found: int = 0 + arg: Argument | t.CPtr = None + value: str = None + entry: str | t.CPtr = None + + while idx < argc: + entry = t.CPtr(t.CUInt64T(argv) + idx * 8) + token = entry[0] + if token is None: + break + + # "--" terminator: all subsequent tokens become positional arguments + if token[0] == '-' and token[1] == '-' and token[2] == 0: + idx += 1 + while idx < argc: + entry = t.CPtr(t.CUInt64T(argv) + idx * 8) + token = entry[0] + found = self._find_positional(pos_idx) + if found < 0: + stdio.printf("error: unexpected argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + self._store_value(args, arg, token) + pos_idx += 1 + idx += 1 + break + + # Long option --name or --name=value + if token[0] == '-' and token[1] == '-': + has_eq: bool = False + p: str = token + while p[0] != 0: + if p[0] == '=': + has_eq = True + break + p += 1 + + if has_eq: + # --name=value syntax + found = self._find_long_prefix(token) + if found < 0: + stdio.printf("error: unrecognized argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + arg_name_len: int = string.strlen(arg.name) + value = token + arg_name_len + 1 + self._store_value(args, arg, value) + idx += 1 + else: + # --name with value in next token or flag action + found = self._find_long(token) + if found < 0: + stdio.printf("error: unrecognized argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + if arg.action == STORE: + if idx + 1 >= argc: + stdio.printf("error: %s requires a value\n", arg.name) + release(args) + return None + entry = t.CPtr(t.CUInt64T(argv) + (idx + 1) * 8) + value = entry[0] + self._store_value(args, arg, value) + idx += 2 + else: + self._apply_action(args, arg) + idx += 1 + + # Short option -x + elif token[0] == '-': + found = self._find_short(token) + if found < 0: + stdio.printf("error: unrecognized argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + if arg.action == STORE: + if idx + 1 >= argc: + stdio.printf("error: %s requires a value\n", arg.name) + release(args) + return None + entry = t.CPtr(t.CUInt64T(argv) + (idx + 1) * 8) + value = entry[0] + self._store_value(args, arg, value) + idx += 2 + else: + self._apply_action(args, arg) + idx += 1 + + # Positional argument + else: + found = self._find_positional(pos_idx) + if found < 0: + stdio.printf("error: unexpected argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + self._store_value(args, arg, token) + pos_idx += 1 + idx += 1 + + # Validate required arguments + i = 0 + while i < self._arg_count: + arg = self._get_arg(i) + if arg.required: + if not args.has(arg.dest): + stdio.printf("error: missing required argument '%s'\n", arg.name) + release(args) + return None + i += 1 + + return args + + def print_help(self): + """Print complete help message""" + stdio.printf("usage: %s [options]\n", self._prog) + if self._description is not None and self._description[0] != 0: + stdio.printf("\n%s\n", self._description) + stdio.printf("\npositional arguments:\n") + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.is_positional: + ht: str = arg.help_text + if ht is None: + ht = "" + stdio.printf(" %-20s %s\n", arg.name, ht) + i += 1 + stdio.printf("\noptional arguments:\n") + i = 0 + while i < self._arg_count: + arg = self._get_arg(i) + if not arg.is_positional: + ht: str = arg.help_text + if ht is None: + ht = "" + if arg.short_name is not None: + stdio.printf(" %s, %-18s %s\n", arg.short_name, arg.name, ht) + else: + stdio.printf(" %-22s %s\n", arg.name, ht) + i += 1 + + def print_usage(self): + """Print brief usage summary""" + stdio.printf("usage: %s [options]\n", self._prog) + + +# ============================================================ +# release — Release ParsedArgs and all internal resources +# ============================================================ + +def release(args: ParsedArgs | t.CPtr): + """Free ParsedArgs object and its inner HashTable resources.""" + if args is None: + return + if args.__mbuddy__ is None: + return + if args._ht is not None: + # 用临时变量拆分链式属性访问,避免 args._ht.__slots__ 跨模块类型推断失败 + # 注意:类型注解必须用 hashtable.HashTable(带模块前缀), + # 否则编译器无法解析 HashTable 类型,导致 ht.__slots__ 属性访问失败 + ht: hashtable.HashTable | t.CPtr = args._ht + if ht.__slots__ is not None: + args.__mbuddy__.free(ht.__slots__) + args.__mbuddy__.free(t.CVoid(t.CUInt64T(ht), t.CPtr)) + args.__mbuddy__.free(t.CVoid(t.CUInt64T(args), t.CPtr)) diff --git a/asm.vp b/asm.vp new file mode 100644 index 0000000..ef64063 --- /dev/null +++ b/asm.vp @@ -0,0 +1,153 @@ +import t, c + + +def cli(): + c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def sti(): + c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def hlt(): + c.Asm("hlt", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def nop(): + c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def pause(): + c.Asm("pause", op=[t.ASM_DESCR.CLOBBER_MEMORY]) + +def inb(port: t.CUInt16T) -> t.CUInt8T: + value: t.CUInt32T + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + in al, dx + movzx eax, al""", + out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], + op =[t.ASM_DESCR.CLOBBER_RDX]) + return t.CUInt8T(value) + +def outb(port: t.CUInt16T, value: t.CUInt8T): + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)} + out dx, al""", + op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) + + +def inw(port: t.CUInt16T) -> t.CUInt16T: + value: t.CUInt32T + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + in ax, dx + movzx eax, ax""", + out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], + op =[t.ASM_DESCR.CLOBBER_RDX]) + return t.CUInt16T(value) + +def outw(port: t.CUInt16T, value: t.CUInt16T): + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)} + out dx, ax""", + op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) + +def inl(port: t.CUInt16T) -> t.CUInt32T: + value: t.CUInt32T + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + in eax, dx""", + out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], + op =[t.ASM_DESCR.CLOBBER_RDX]) + return value + +def outl(port: t.CUInt16T, value: t.CUInt32T): + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)} + out dx, eax""", + op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) + +def io_wait(): + c.Asm(f"mov dx, 0x80; out dx, al", + op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_DX]) + +def pushall() -> t.CInline | t.CVoid: + c.Asm(f""" + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15""", + [t.ASM_DESCR.CLOBBER_MEMORY] + ) + +def popall() -> t.CInline | t.CVoid: + c.Asm(f""" + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax""", + [t.ASM_DESCR.CLOBBER_MEMORY] + ) + +def cpu_switch_context(old_stack: t.CUInt64T | t.CPtr, new_stack: t.CUInt64T): + c.Asm(f""" + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + mov [{c.AsmInp(old_stack, t.ASM_DESCR.REG_ANY)}], rsp + mov rsp, {c.AsmInp(new_stack, t.ASM_DESCR.REG_ANY)} + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax""", + op=[t.ASM_DESCR.CLOBBER_MEMORY]) + +def BSSClean(): + c.Asm( + "lea rdi, [rip + __bss_start]\n" + "lea rcx, [rip + __bss_end]\n" + "sub rcx, rdi\n" + "xor eax, eax\n" + "cld\n" + "rep stosb", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX] + ) diff --git a/ast/__init__.vp b/ast/__init__.vp new file mode 100644 index 0000000..5f2a60a --- /dev/null +++ b/ast/__init__.vp @@ -0,0 +1,115 @@ +import t, c +from stdint import * +import memhub +import string + +# Import submodule +from .tokens import ( + Token, TokenType, Keyword, TokOp, _init_tables, +) +# Common Section: Base Classes, Enums, Constants, Helper Functions, Dump +from .base import ( + AST, Stmt, ExprNode, ASTKind, ASTCtx, OpKind, ASTFlag, + # Constants + CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR, + FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR, + # Helper Functions + _init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list, + _binop_from_op, _augop_from_op, _cmpop_from_op, + _emit, _emit_str, _emit_int, _dump_list, + dump, _op_name, +) +# Statement Nodes: Module, Expression, Interactive, FunctionType +from .stmts import ( + # Module Layer + Module, Expression, Interactive, FunctionType, + # Statement + FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign, + For, While, If, With, Raise, Try, Assert, Global, Nonlocal, + Pass, Break, Continue, Expr, Import, ImportFrom, Match, +) +# Expression Nodes: BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set +from .exprs import ( + # Expression Layer + BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set, + ListComp, SetComp, DictComp, GeneratorExp, + Await, Yield, YieldFrom, FormattedValue, JoinedStr, + Constant, NamedExpr, Attribute, Subscript, Starred, Name, + List, Tuple, Slice, + Call, Compare, OpNode, +) +# Auxiliary Nodes +from .astaux import ( + ExceptHandler, Arguments, Arg, Keyword, Alias, WithItem, + Comprehension, +) +# Pattern Matching +from .match import ( + MatchCase, MatchValue, MatchSingleton, MatchSequence, + MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr, +) +# from .visitor import ASTVisitor +from .lexer import Lexer, _lexer_init, tokenize, new_lexer +from .parser import Parser, _parser_init, parse_tokens, new_parser +from .parser import _parse_test +from .parser import _dbg_lookup_lit_val, _dbg_lit_found +from .parser import get_parse_err_line, get_parse_err_col, get_parse_err_msg + +# ============================================================ +# Global Memory Pool Pointer (follows project rules: declare _mbuddy) +# User initializes in main: ast._mbuddy = memhub.MemBuddy(arena, size) +# ============================================================ +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================ +# Common API: parse +# ============================================================ + +def parse(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr: + """Parse Python source code, return the AST Module node. + + Parameters: + src: NUL source code string, terminated with NUL + pool: memhub.MemManager instance, to allocate AST nodes + + Returns: + AST Module node, or None + """ + if src is None or pool is None: + return None + _init_tables(pool) + lx: Lexer | t.CPtr = new_lexer(pool) + if lx is None: + return None + _lexer_init(lx, src, pool) + tokens: Token | t.CPtr = tokenize(lx) + if tokens is None: + return None + tree: AST | t.CPtr = parse_tokens(pool, tokens) + return tree + + +def parse_expression(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr: + """Parse a single expression, return the Expression node. + + Parameters: + src: NUL expression string, terminated with NUL + pool: memhub.MemManager instance, to allocate AST nodes + + Returns: + Expression node, or None + """ + if src is None or pool is None: + return None + _init_tables(pool) + lx: Lexer | t.CPtr = new_lexer(pool) + if lx is None: return None + _lexer_init(lx, src, pool) + tokens: Token | t.CPtr = tokenize(lx) + if tokens is None: return None + ps: Parser | t.CPtr = new_parser(pool) + if ps is None: return None + _parser_init(ps, tokens, pool) + body: AST | t.CPtr = _parse_test(ps) + return Expression(pool, body) diff --git a/ast/astaux.vp b/ast/astaux.vp new file mode 100644 index 0000000..3c51a00 --- /dev/null +++ b/ast/astaux.vp @@ -0,0 +1,337 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, ASTKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, +) + + +# ============================================================ +# ExceptHandler Node +# ============================================================ + +class ExceptHandler(AST): + """ExceptHandler(type: AST, name: str)""" + type: AST | t.CPtr + name: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + type: AST | t.CPtr, name: str): + ptr: ExceptHandler | t.CPtr = pool.alloc(ExceptHandler.__sizeof__()) + if ptr: + string.memset(ptr, 0, ExceptHandler.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + type: AST | t.CPtr, name: str): + _init_ast(self, pool, 0, 0) + self.type = type + self.name = _copy_str(pool, name) + + def kind(self) -> t.CInt: + return ASTKind.ExceptHandler + + def type_name(self) -> str: + return "ExceptHandler" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ExceptHandler(type=") + if self.type is not None: + pos = self.type.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Arguments Node +# ============================================================ + +class Arguments(AST): + """Arguments(args: list[AST | CPtr], vararg: AST, kwarg: AST, + defaults: list[AST | CPtr], kw_defaults: list[AST | CPtr])""" + args: list[AST | t.CPtr] | t.CPtr + vararg: AST | t.CPtr + kwarg: AST | t.CPtr + defaults: list[AST | t.CPtr] | t.CPtr + kw_defaults: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + vararg: AST | t.CPtr, kwarg: AST | t.CPtr, + defaults: list[AST | t.CPtr] | t.CPtr, + kw_defaults: list[AST | t.CPtr] | t.CPtr): + ptr: Arguments | t.CPtr = pool.alloc(Arguments.__sizeof__()) + if ptr: + string.memset(ptr, 0, Arguments.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + vararg: AST | t.CPtr, kwarg: AST | t.CPtr, + defaults: list[AST | t.CPtr] | t.CPtr, + kw_defaults: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.args = args + self.vararg = vararg + self.kwarg = kwarg + self.defaults = defaults + self.kw_defaults = kw_defaults + _set_parent_list(args, self) + _set_parent_list(defaults, self) + _set_parent_list(kw_defaults, self) + + def kind(self) -> t.CInt: + return ASTKind.Arguments + + def type_name(self) -> str: + return "Arguments" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Arguments(args=") + pos = _dump_list(self.args, buf, size, pos) + pos = _emit(buf, size, pos, ", vararg=") + if self.vararg is not None: + pos = self.vararg.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", kwarg=") + if self.kwarg is not None: + pos = self.kwarg.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", defaults=") + pos = _dump_list(self.defaults, buf, size, pos) + pos = _emit(buf, size, pos, ", kw_defaults=") + pos = _dump_list(self.kw_defaults, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Arg Node +# ============================================================ + +class Arg(AST): + """Arg(arg: str, annotation: AST)""" + arg: str + annotation: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + arg: str, annotation: AST | t.CPtr): + ptr: Arg | t.CPtr = pool.alloc(Arg.__sizeof__()) + if ptr: + string.memset(ptr, 0, Arg.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + arg: str, annotation: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.arg = _copy_str(pool, arg) + self.annotation = annotation + + def kind(self) -> t.CInt: + return ASTKind.Arg + + def type_name(self) -> str: + return "Arg" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Arg(arg='") + pos = _emit_str(buf, size, pos, self.arg) + pos = _emit(buf, size, pos, "', annotation=") + if self.annotation is not None: + pos = self.annotation.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Keyword Node +# ============================================================ + +class Keyword(AST): + """Keyword(arg: str, value: AST)""" + arg: str + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + arg: str, value: AST | t.CPtr): + ptr: Keyword | t.CPtr = pool.alloc(Keyword.__sizeof__()) + if ptr: + string.memset(ptr, 0, Keyword.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + arg: str, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.arg = _copy_str(pool, arg) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Keyword + + def type_name(self) -> str: + return "Keyword" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Keyword(arg='") + pos = _emit_str(buf, size, pos, self.arg) + pos = _emit(buf, size, pos, "', value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Alias Node +# ============================================================ + +class Alias(AST): + """Alias(name: str, asname: str)""" + name: str + asname: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + name: str, asname: str): + ptr: Alias | t.CPtr = pool.alloc(Alias.__sizeof__()) + if ptr: + string.memset(ptr, 0, Alias.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + name: str, asname: str): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + self.asname = _copy_str(pool, asname) + + def kind(self) -> t.CInt: + return ASTKind.Alias + + def type_name(self) -> str: + return "Alias" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Alias(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', asname='") + pos = _emit_str(buf, size, pos, self.asname) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# WithItem Node +# ============================================================ + +class WithItem(AST): + """WithItem(context_expr: AST, optional_vars: AST)""" + context_expr: AST | t.CPtr + optional_vars: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr): + ptr: WithItem | t.CPtr = pool.alloc(WithItem.__sizeof__()) + if ptr: + string.memset(ptr, 0, WithItem.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.context_expr = context_expr + self.optional_vars = optional_vars + + def kind(self) -> t.CInt: + return ASTKind.WithItem + + def type_name(self) -> str: + return "WithItem" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "WithItem(context_expr=") + if self.context_expr is not None: + pos = self.context_expr.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", optional_vars=") + if self.optional_vars is not None: + pos = self.optional_vars.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Comprehension Node +# ============================================================ + +class Comprehension(AST): + """Comprehension(target: AST, iter: AST, ifs: list[AST | CPtr], is_async: CInt)""" + target: AST | t.CPtr + iter: AST | t.CPtr + ifs: list[AST | t.CPtr] | t.CPtr + is_async: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt): + ptr: Comprehension | t.CPtr = pool.alloc(Comprehension.__sizeof__()) + if ptr: + string.memset(ptr, 0, Comprehension.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt): + _init_ast(self, pool, 0, 0) + self.target = target + self.iter = iter + self.ifs = ifs + self.is_async = is_async + _set_parent_list(ifs, self) + + def kind(self) -> t.CInt: + return ASTKind.Comprehension + + def type_name(self) -> str: + return "Comprehension" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Comprehension(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", iter=") + if self.iter is not None: + pos = self.iter.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ifs=") + pos = _dump_list(self.ifs, buf, size, pos) + pos = _emit(buf, size, pos, ", is_async=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.is_async)) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/base.vp b/ast/base.vp new file mode 100644 index 0000000..fcf145e --- /dev/null +++ b/ast/base.vp @@ -0,0 +1,504 @@ +import t, c +from stdint import * +import memhub +import string +import viperlib +from .tokens import TokOp + + +# ============================================================ +# ASTKind - Node type enum (kind() virtual function return value) +# ============================================================ + +class ASTKind(t.CEnum): + # Core 15 nodes + Module: t.State + FunctionDef: t.State + ClassDef: t.State + Assign: t.State + If: t.State + For: t.State + While: t.State + Return: t.State + Expr: t.State + Name: t.State + Constant: t.State + BinOp: t.State + UnaryOp: t.State + Call: t.State + Compare: t.State + # Module Layer + Expression: t.State + Interactive: t.State + FunctionType: t.State + # Statement + Delete: t.State + AugAssign: t.State + AnnAssign: t.State + With: t.State + Raise: t.State + Try: t.State + Assert: t.State + Global: t.State + Nonlocal: t.State + Pass: t.State + Break: t.State + Continue: t.State + Import: t.State + ImportFrom: t.State + Match: t.State + # Expression Layer + BoolOp: t.State + Lambda: t.State + IfExp: t.State + Dict: t.State + Set: t.State + ListComp: t.State + SetComp: t.State + DictComp: t.State + GeneratorExp: t.State + Await: t.State + Yield: t.State + YieldFrom: t.State + FormattedValue: t.State + JoinedStr: t.State + Attribute: t.State + Subscript: t.State + Starred: t.State + List: t.State + Tuple: t.State + Slice: t.State + NamedExpr: t.State + # Auxiliary Nodes + ExceptHandler: t.State + Arguments: t.State + Arg: t.State + Keyword: t.State + Alias: t.State + WithItem: t.State + Comprehension: t.State + OpNode: t.State + # Pattern Matching + MatchCase: t.State + MatchValue: t.State + MatchSingleton: t.State + MatchSequence: t.State + MatchMapping: t.State + MatchClass: t.State + MatchStar: t.State + MatchAs: t.State + MatchOr: t.State + + +# ============================================================ +# ASTCtx - Name context (Load/Store/Del) +# ============================================================ + +class ASTCtx(t.CEnum): + Load: t.State + Store: t.State + Del: t.State + + +# ============================================================ +# OpKind - Operator enum (BinOp/UnaryOp/Compare) +# ============================================================ + +class OpKind(t.CEnum): + # Binary arithmetic operators + Add: t.State + Sub: t.State + Mult: t.State + MatMult: t.State + Div: t.State + Mod: t.State + Pow: t.State + LShift: t.State + RShift: t.State + BitOr: t.State + BitXor: t.State + BitAnd: t.State + FloorDiv: t.State + # Boolean operators + And: t.State + Or: t.State + # Comparison operators + Eq: t.State + Ne: t.State + Lt: t.State + Le: t.State + Gt: t.State + Ge: t.State + Is: t.State + IsNot: t.State + In: t.State + NotIn: t.State + # Unary operators + Not: t.State + UAdd: t.State + USub: t.State + Invert: t.State + # None + NoneOp: t.State + + +# Constant subtype identifiers +CONST_INT: t.CDefine = 1 +CONST_FLOAT: t.CDefine = 2 +CONST_STR: t.CDefine = 3 +CONST_BOOL: t.CDefine = 4 +CONST_NONE: t.CDefine = 5 +CONST_CHAR: t.CDefine = 6 + +# Node flags +FLAG_IS_ASYNC: t.CDefine = 1 +FLAG_SIMPLE: t.CDefine = 2 +FLAG_HAS_STAR: t.CDefine = 4 +FLAG_IS_EXTERN: t.CDefine = 8 + + +# ============================================================ +# ASTFlag - Node flags enum +# ============================================================ + +class ASTFlag(t.CEnum): + IsAsync: t.State + Simple: t.State + HasStar: t.State + + +# ============================================================ +# Helper Functions +# ============================================================ + +def _copy_str(pool: memhub.MemManager | t.CPtr, src: str) -> str: + """Allocate and copy a C string from pool.""" + if src is None: return None + slen: t.CSizeT = string.strlen(src) + buf: str = pool.alloc(slen + 1) + if buf is None: return None + string.memcpy(buf, src, slen + 1) + return buf + + +def _set_pos(node: AST | t.CPtr, lineno: t.CInt, col_offset: t.CInt, + end_lineno: t.CInt, end_col_offset: t.CInt): + if node is None: return + node.lineno = lineno + node.col_offset = col_offset + node.end_lineno = end_lineno + node.end_col_offset = end_col_offset + + +def _inherit_pos(node: AST | t.CPtr, ref: AST | t.CPtr): + if node is None or ref is None: return + node.lineno = ref.lineno + node.col_offset = ref.col_offset + node.end_lineno = ref.end_lineno + node.end_col_offset = ref.end_col_offset + + +def _init_ast(node: AST | t.CPtr, pool: memhub.MemManager | t.CPtr, + lineno: t.CInt, col: t.CInt): + """Initialize AST base fields.""" + node.parent = None + node.pool = pool + node.lineno = lineno + node.col_offset = col + node.end_lineno = lineno + node.end_col_offset = col + node.children = None + + +def _set_parent_list(lst: list[AST | t.CPtr] | t.CPtr, parent: AST | t.CPtr): + """Set list children parent pointers.""" + if lst is None: return + n: t.CSizeT = lst.__len__() + i: t.CSizeT = 0 + while i < n: + child: AST | t.CPtr = lst.get(i) + if child is not None: + child.parent = parent + i += 1 + + +def _append_child(lst: list[AST | t.CPtr] | t.CPtr, node: AST | t.CPtr, + pool: memhub.MemManager | t.CPtr): + """Append child nodes to a list (module-level function, to avoid conflicts with the AST.append method name). + + Call this function within the AST.append method to bypass the compiler mistaking list.append for a virtual function call to AST.append when doing type inference.""" + if lst is None or node is None: + return + lst.append(node) + + +# ============================================================ +# Operator Mapping: TokOp -> OpKind +# ============================================================ + +def _binop_from_op(op_id: t.CInt) -> t.CInt: + if op_id == TokOp.Plus: return OpKind.Add + if op_id == TokOp.Minus: return OpKind.Sub + if op_id == TokOp.Star: return OpKind.Mult + if op_id == TokOp.At: return OpKind.MatMult + if op_id == TokOp.Slash: return OpKind.Div + if op_id == TokOp.Percent: return OpKind.Mod + if op_id == TokOp.StarStar: return OpKind.Pow + if op_id == TokOp.LtLt: return OpKind.LShift + if op_id == TokOp.GtGt: return OpKind.RShift + if op_id == TokOp.VBar: return OpKind.BitOr + if op_id == TokOp.Caret: return OpKind.BitXor + if op_id == TokOp.Amp: return OpKind.BitAnd + if op_id == TokOp.DSlash: return OpKind.FloorDiv + return OpKind.NoneOp + + +def _augop_from_op(op_id: t.CInt) -> t.CInt: + if op_id == TokOp.PlusEq: return OpKind.Add + if op_id == TokOp.MinusEq: return OpKind.Sub + if op_id == TokOp.StarEq: return OpKind.Mult + if op_id == TokOp.AtEq: return OpKind.MatMult + if op_id == TokOp.SlashEq: return OpKind.Div + if op_id == TokOp.PercentEq: return OpKind.Mod + if op_id == TokOp.StarEqEq: return OpKind.Pow + if op_id == TokOp.LtLtEq: return OpKind.LShift + if op_id == TokOp.GtGtEq: return OpKind.RShift + if op_id == TokOp.VBarEq: return OpKind.BitOr + if op_id == TokOp.CaretEq: return OpKind.BitXor + if op_id == TokOp.AmpEq: return OpKind.BitAnd + if op_id == TokOp.DSlashEq: return OpKind.FloorDiv + return OpKind.NoneOp + + +def _cmpop_from_op(op_id: t.CInt) -> t.CInt: + if op_id == TokOp.EqEq: return OpKind.Eq + if op_id == TokOp.ExclaimEq: return OpKind.Ne + if op_id == TokOp.Less: return OpKind.Lt + if op_id == TokOp.LessEq: return OpKind.Le + if op_id == TokOp.Greater: return OpKind.Gt + if op_id == TokOp.GreaterEq: return OpKind.Ge + return OpKind.NoneOp + + +# ============================================================ +# dump Helper Functions +# ============================================================ + +def _emit(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT, + text: str) -> t.CSizeT: + """Append literal to buf+pos.""" + if buf is None or pos >= size: + return pos + cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos) + rem: t.CSizeT = size - pos + n: t.CInt = viperlib.snprintf(cur, rem, "%s", text) + if n < 0: + return pos + return pos + t.CSizeT(n) + + +def _emit_str(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT, + text: str) -> t.CSizeT: + """Append a string value to buf pos (using %s format)""" + if buf is None or pos >= size: + return pos + cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos) + rem: t.CSizeT = size - pos + n: t.CInt = viperlib.snprintf(cur, rem, "%s", text) + if n < 0: + return pos + return pos + t.CSizeT(n) + + +def _emit_int(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT, + val: t.CInt64T) -> t.CSizeT: + """Append an integer value to buf pos (using %lld format).""" + if buf is None or pos >= size: + return pos + cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos) + rem: t.CSizeT = size - pos + n: t.CInt = viperlib.snprintf(cur, rem, "%lld", val) + if n < 0: + return pos + return pos + t.CSizeT(n) + + +def _op_name(op: t.CInt) -> str: + """Return the string name of an OpKind.""" + if op == OpKind.Add: return "Add" + if op == OpKind.Sub: return "Sub" + if op == OpKind.Mult: return "Mult" + if op == OpKind.MatMult: return "MatMult" + if op == OpKind.Div: return "Div" + if op == OpKind.Mod: return "Mod" + if op == OpKind.Pow: return "Pow" + if op == OpKind.LShift: return "LShift" + if op == OpKind.RShift: return "RShift" + if op == OpKind.BitOr: return "BitOr" + if op == OpKind.BitXor: return "BitXor" + if op == OpKind.BitAnd: return "BitAnd" + if op == OpKind.FloorDiv: return "FloorDiv" + if op == OpKind.And: return "And" + if op == OpKind.Or: return "Or" + if op == OpKind.Eq: return "Eq" + if op == OpKind.Ne: return "Ne" + if op == OpKind.Lt: return "Lt" + if op == OpKind.Le: return "Le" + if op == OpKind.Gt: return "Gt" + if op == OpKind.Ge: return "Ge" + if op == OpKind.Is: return "Is" + if op == OpKind.IsNot: return "IsNot" + if op == OpKind.In: return "In" + if op == OpKind.NotIn: return "NotIn" + if op == OpKind.Not: return "Not" + if op == OpKind.UAdd: return "UAdd" + if op == OpKind.USub: return "USub" + if op == OpKind.Invert: return "Invert" + return "NoneOp" + + +def _dump_list(lst: list[AST | t.CPtr] | t.CPtr, buf: t.CChar | t.CPtr, + size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT: + """Traverse a list[AST | CPtr] container, polymorphically dump each element.""" + if lst is None: + pos = _emit(buf, size, pos, "[]") + return pos + pos = _emit(buf, size, pos, "[") + n: t.CSizeT = lst.__len__() + i: t.CSizeT = 0 + while i < n: + if i > 0: + pos = _emit(buf, size, pos, ", ") + child: AST | t.CPtr = lst.get(i) + if child is not None: + pos = child.dump(buf, size, pos) + i += 1 + pos = _emit(buf, size, pos, "]") + return pos + + +def _dump_op_list(lst: t.CPtr, buf: t.CChar | t.CPtr, + size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT: + """Traverse a list[CInt] (OpKind values), output a list of op names.""" + if lst is None: + pos = _emit(buf, size, pos, "[]") + return pos + ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(lst) + pos = _emit(buf, size, pos, "[") + n: t.CSizeT = ops_list.__len__() + i: t.CSizeT = 0 + while i < n: + if i > 0: + pos = _emit(buf, size, pos, ", ") + op: t.CInt = ops_list.get(i) + pos = _emit(buf, size, pos, _op_name(op)) + i += 1 + pos = _emit(buf, size, pos, "]") + return pos + + +# ============================================================ +# AST - Polymorphic Base Class + +# @t.CVTable enables vtable, supporting virtual functions like kind()/type_name()/dump()/accept() +# Child nodes are stored in a list[AST | CPtr] container (O(1) random access, more efficient than linked lists) +# The parent field maintains a pointer to the parent (used for upward traversal) +# ============================================================ + +@t.CVTable +class AST: + """AST node base class. All specific node classes inherit from this. + + Fields: + parent: Pointer to the parent node (for upward traversal) + pool: Allocator (used for allocating child nodes/strings) + lineno/col_offset: Starting position + end_lineno/end_col_offset: Ending position + children: List of child nodes (body block, added via append) + """ + parent: AST | t.CPtr + pool: memhub.MemManager | t.CPtr + lineno: t.CInt + col_offset: t.CInt + end_lineno: t.CInt + end_col_offset: t.CInt + children: list[AST | t.CPtr] | t.CPtr + + def kind(self) -> t.CInt: + """Returns the node type (ASTKind value), overridden by subclasses""" + return 0 + + def type_name(self) -> str: + """Return the node type name, subclasses override""" + return "AST" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + """Polymorphic dump: subclasses override to define custom format. Returns the written pos""" + return pos + + def accept(self, visitor: t.CPtr): + """Visitor pattern entry point: subclasses override to dispatch to ASTVisitor in the visitor pattern. + Current implementation is empty. override this method to dispatch to visitor.visit_X(self)""" + pass + + def append(self, node: AST | t.CPtr): + """Append node to the children list. + + Used for parser to build statement blocks: module.append(stmt), if_node.append(stmt), etc. + The children list is lazily initialized on first call. + + Note: list[AST|CPtr] is currently stored by value (compiler limitation), so you must set + node.parent before appending, so the parent in the copy is correct.""" + if self is None or node is None: + return + if self.children is None: + self.children = list[AST | t.CPtr](self.pool, 8) + node.parent = self + _append_child(self.children, node, self.pool) + + +# ============================================================ +# Stmt - Statement Base Class +# +# 所有语句节点(Assign/If/For/While/Return/...)继承 Stmt。 +# isinstance(node, ast.Stmt) 可在运行时区分"语句"与"表达式" +# (依赖 TPV isinstance 子类集合判定 + 三层 vtable 继承)。 +# 不 override kind()(继承 AST 的 0),具体节点各自返回 ASTKind 值。 +# ============================================================ + +@t.CVTable +class Stmt(AST): + """语句节点基类(Assign/If/For/While/Return/...)""" + + +# ============================================================ +# ExprNode - Expression Base Class +# +# 所有表达式节点(Name/Constant/Call/BinOp/...)继承 ExprNode。 +# isinstance(node, ast.ExprNode) 可在运行时区分"表达式"与"语句"。 +# +# 命名说明:不能叫 Expr——ASTKind.Expr(base.vp L23)与 stmts.vp 的 +# Expr 类已是"表达式语句"(Expression Statement)的既有语义。 +# ============================================================ + +@t.CVTable +class ExprNode(AST): + """表达式节点基类(Name/Constant/Call/BinOp/...)""" + + +# ============================================================ +# Module dump function (for ast.dump(node, buf, size)) +# ============================================================ + +def dump(node: AST | t.CPtr, buf: t.CChar | t.CPtr, size: t.CSizeT): + """Serialize AST node to buf (with capacity size)""" + if node is None or buf is None or size == 0: + return + buf[0] = '\0' + final_pos: t.CSizeT = node.dump(buf, size, 0) + # NUL-terminate to prevent printf overflow + if final_pos < size: + buf[final_pos] = '\0' + else: + buf[size - 1] = '\0' diff --git a/ast/exprs.vp b/ast/exprs.vp new file mode 100644 index 0000000..366fffc --- /dev/null +++ b/ast/exprs.vp @@ -0,0 +1,1239 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, ExprNode, ASTKind, ASTCtx, OpKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, _dump_op_list, _op_name, + CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR +) + + +# ============================================================ +# Name node +# ============================================================ + +class Name(ExprNode): + """Name(id: str, ctx: ASTCtx)""" + id: str + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + id: str, ctx: t.CInt): + ptr: Name | t.CPtr = pool.alloc(Name.__sizeof__()) + if ptr: + string.memset(ptr, 0, Name.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + id: str, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.id = _copy_str(pool, id) + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Name + + def type_name(self) -> str: + return "Name" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Name(id='") + pos = _emit_str(buf, size, pos, self.id) + pos = _emit(buf, size, pos, "', ctx=") + if self.ctx == ASTCtx.Load: + pos = _emit(buf, size, pos, "Load") + elif self.ctx == ASTCtx.Store: + pos = _emit(buf, size, pos, "Store") + else: + pos = _emit(buf, size, pos, "Del") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Constant nodes (subtype marked by const_kind) +# ============================================================ + +class Constant(ExprNode): + """Constant(int_val/float_val/str_val, const_kind)""" + int_val: t.CInt64T + float_val: t.CDouble + str_val: str + const_kind: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + const_kind: t.CInt, int_val: t.CInt64T, + float_val: t.CDouble, str_val: str, + lineno: t.CInt, col: t.CInt): + ptr: Constant | t.CPtr = pool.alloc(Constant.__sizeof__()) + if ptr: + string.memset(ptr, 0, Constant.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + const_kind: t.CInt, int_val: t.CInt64T, + float_val: t.CDouble, str_val: str, + lineno: t.CInt, col: t.CInt): + _init_ast(self, pool, lineno, col) + self.const_kind = const_kind + self.int_val = int_val + self.float_val = float_val + if str_val is not None: + self.str_val = _copy_str(pool, str_val) + else: + self.str_val = None + + def kind(self) -> t.CInt: + return ASTKind.Constant + + def type_name(self) -> str: + return "Constant" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Constant(value=") + if self.const_kind == CONST_INT: + pos = _emit_int(buf, size, pos, self.int_val) + elif self.const_kind == CONST_FLOAT: + pos = _emit(buf, size, pos, "") + elif self.const_kind == CONST_STR: + pos = _emit(buf, size, pos, "'") + if self.str_val is not None: + pos = _emit_str(buf, size, pos, self.str_val) + else: + pos = _emit(buf, size, pos, "(null)") + pos = _emit(buf, size, pos, "'") + elif self.const_kind == CONST_CHAR: + # Single character → display as character ASCII value + pos = _emit(buf, size, pos, "char(") + pos = _emit_int(buf, size, pos, self.int_val) + pos = _emit(buf, size, pos, ")") + elif self.const_kind == CONST_BOOL: + if self.int_val != 0: + pos = _emit(buf, size, pos, "True") + else: + pos = _emit(buf, size, pos, "False") + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# BinOp Node +# ============================================================ + +class BinOp(ExprNode): + """BinOp(left: AST, op: OpKind, right: AST)""" + left: AST | t.CPtr + op: t.CInt + right: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, op: t.CInt, right: AST | t.CPtr): + ptr: BinOp | t.CPtr = pool.alloc(BinOp.__sizeof__()) + if ptr: + string.memset(ptr, 0, BinOp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, op: t.CInt, right: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.left = left + self.op = op + self.right = right + + def kind(self) -> t.CInt: + return ASTKind.BinOp + + def type_name(self) -> str: + return "BinOp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "BinOp(left=") + if self.left is not None: + pos = self.left.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", right=") + if self.right is not None: + pos = self.right.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# UnaryOp Node +# ============================================================ + +class UnaryOp(ExprNode): + """UnaryOp(op: OpKind, operand: AST)""" + op: t.CInt + operand: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, operand: AST | t.CPtr): + ptr: UnaryOp | t.CPtr = pool.alloc(UnaryOp.__sizeof__()) + if ptr: + string.memset(ptr, 0, UnaryOp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, operand: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.op = op + self.operand = operand + + def kind(self) -> t.CInt: + return ASTKind.UnaryOp + + def type_name(self) -> str: + return "UnaryOp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "UnaryOp(op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", operand=") + if self.operand is not None: + pos = self.operand.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Compare Node +# ============================================================ + +class Compare(ExprNode): + """Compare(left: AST, ops: list[CInt], comparators: list[AST | CPtr])""" + left: AST | t.CPtr + ops: t.CPtr + comparators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, + ops: t.CPtr, + comparators: list[AST | t.CPtr] | t.CPtr): + ptr: Compare | t.CPtr = pool.alloc(Compare.__sizeof__()) + if ptr: + string.memset(ptr, 0, Compare.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, + ops: t.CPtr, + comparators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.left = left + self.ops = ops + self.comparators = comparators + _set_parent_list(comparators, self) + + def kind(self) -> t.CInt: + return ASTKind.Compare + + def type_name(self) -> str: + return "Compare" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Compare(left=") + if self.left is not None: + pos = self.left.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ops=") + pos = _dump_op_list(self.ops, buf, size, pos) + pos = _emit(buf, size, pos, ", comparators=") + pos = _dump_list(self.comparators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Call Node +# ============================================================ + +class Call(ExprNode): + """Call(func: AST, args: list[AST | CPtr], keywords: list[AST | CPtr])""" + func: AST | t.CPtr + args: list[AST | t.CPtr] | t.CPtr + keywords: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + func: AST | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr): + ptr: Call | t.CPtr = pool.alloc(Call.__sizeof__()) + if ptr: + string.memset(ptr, 0, Call.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + func: AST | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.func = func + self.args = args + self.keywords = keywords + _set_parent_list(args, self) + _set_parent_list(keywords, self) + + def kind(self) -> t.CInt: + return ASTKind.Call + + def type_name(self) -> str: + return "Call" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Call(func=") + if self.func is not None: + pos = self.func.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", args=") + pos = _dump_list(self.args, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# BoolOp Node +# ============================================================ + +class BoolOp(ExprNode): + """BoolOp(op: CInt, values: list[AST | CPtr])""" + op: t.CInt + values: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, + values: list[AST | t.CPtr] | t.CPtr): + ptr: BoolOp | t.CPtr = pool.alloc(BoolOp.__sizeof__()) + if ptr: + string.memset(ptr, 0, BoolOp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, + values: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.op = op + self.values = values + _set_parent_list(values, self) + + def kind(self) -> t.CInt: + return ASTKind.BoolOp + + def type_name(self) -> str: + return "BoolOp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "BoolOp(op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", values=") + pos = _dump_list(self.values, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Lambda Node +# ============================================================ + +class Lambda(ExprNode): + """Lambda(args: AST, body: AST)""" + args: AST | t.CPtr + body: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + args: AST | t.CPtr, body: AST | t.CPtr): + ptr: Lambda | t.CPtr = pool.alloc(Lambda.__sizeof__()) + if ptr: + string.memset(ptr, 0, Lambda.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + args: AST | t.CPtr, body: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.args = args + self.body = body + + def kind(self) -> t.CInt: + return ASTKind.Lambda + + def type_name(self) -> str: + return "Lambda" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Lambda(args=") + if self.args is not None: + pos = self.args.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# IfExp Node +# ============================================================ + +class IfExp(ExprNode): + """IfExp(test: AST, body: AST, orelse: AST)""" + test: AST | t.CPtr + body: AST | t.CPtr + orelse: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, body: AST | t.CPtr, + orelse: AST | t.CPtr): + ptr: IfExp | t.CPtr = pool.alloc(IfExp.__sizeof__()) + if ptr: + string.memset(ptr, 0, IfExp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, body: AST | t.CPtr, + orelse: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.body = body + self.orelse = orelse + + def kind(self) -> t.CInt: + return ASTKind.IfExp + + def type_name(self) -> str: + return "IfExp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "IfExp(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", orelse=") + if self.orelse is not None: + pos = self.orelse.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Dict Node +# ============================================================ + +class Dict(ExprNode): + """Dict(keys: list[AST | CPtr], values: list[AST | CPtr])""" + keys: list[AST | t.CPtr] | t.CPtr + values: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + ptr: Dict | t.CPtr = pool.alloc(Dict.__sizeof__()) + if ptr: + string.memset(ptr, 0, Dict.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.keys = keys + self.values = values + _set_parent_list(keys, self) + _set_parent_list(values, self) + + def kind(self) -> t.CInt: + return ASTKind.Dict + + def type_name(self) -> str: + return "Dict" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Dict(keys=") + pos = _dump_list(self.keys, buf, size, pos) + pos = _emit(buf, size, pos, ", values=") + pos = _dump_list(self.values, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Set Node +# ============================================================ + +class Set(ExprNode): + """Set(elts: list[AST | CPtr])""" + elts: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr): + ptr: Set | t.CPtr = pool.alloc(Set.__sizeof__()) + if ptr: + string.memset(ptr, 0, Set.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elts = elts + _set_parent_list(elts, self) + + def kind(self) -> t.CInt: + return ASTKind.Set + + def type_name(self) -> str: + return "Set" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Set(elts=") + pos = _dump_list(self.elts, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# ListComp Node +# ============================================================ + +class ListComp(ExprNode): + """ListComp(elt: AST, generators: list[AST | CPtr])""" + elt: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: ListComp | t.CPtr = pool.alloc(ListComp.__sizeof__()) + if ptr: + string.memset(ptr, 0, ListComp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elt = elt + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.ListComp + + def type_name(self) -> str: + return "ListComp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ListComp(elt=") + if self.elt is not None: + pos = self.elt.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# SetComp Node +# ============================================================ + +class SetComp(ExprNode): + """SetComp(elt: AST, generators: list[AST | CPtr])""" + elt: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: SetComp | t.CPtr = pool.alloc(SetComp.__sizeof__()) + if ptr: + string.memset(ptr, 0, SetComp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elt = elt + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.SetComp + + def type_name(self) -> str: + return "SetComp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "SetComp(elt=") + if self.elt is not None: + pos = self.elt.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# DictComp Node +# ============================================================ + +class DictComp(ExprNode): + """DictComp(key: AST, value: AST, generators: list[AST | CPtr])""" + key: AST | t.CPtr + value: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + key: AST | t.CPtr, value: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: DictComp | t.CPtr = pool.alloc(DictComp.__sizeof__()) + if ptr: + string.memset(ptr, 0, DictComp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + key: AST | t.CPtr, value: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.key = key + self.value = value + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.DictComp + + def type_name(self) -> str: + return "DictComp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "DictComp(key=") + if self.key is not None: + pos = self.key.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# GeneratorExp Node +# ============================================================ + +class GeneratorExp(ExprNode): + """GeneratorExp(elt: AST, generators: list[AST | CPtr])""" + elt: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: GeneratorExp | t.CPtr = pool.alloc(GeneratorExp.__sizeof__()) + if ptr: + string.memset(ptr, 0, GeneratorExp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elt = elt + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.GeneratorExp + + def type_name(self) -> str: + return "GeneratorExp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "GeneratorExp(elt=") + if self.elt is not None: + pos = self.elt.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Await Node +# ============================================================ + +class Await(ExprNode): + """Await(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Await | t.CPtr = pool.alloc(Await.__sizeof__()) + if ptr: + string.memset(ptr, 0, Await.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Await + + def type_name(self) -> str: + return "Await" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Await(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Yield Node +# ============================================================ + +class Yield(ExprNode): + """Yield(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Yield | t.CPtr = pool.alloc(Yield.__sizeof__()) + if ptr: + string.memset(ptr, 0, Yield.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Yield + + def type_name(self) -> str: + return "Yield" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Yield(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# YieldFrom Node +# ============================================================ + +class YieldFrom(ExprNode): + """YieldFrom(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: YieldFrom | t.CPtr = pool.alloc(YieldFrom.__sizeof__()) + if ptr: + string.memset(ptr, 0, YieldFrom.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.YieldFrom + + def type_name(self) -> str: + return "YieldFrom" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "YieldFrom(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# FormattedValue Node +# ============================================================ + +class FormattedValue(ExprNode): + """FormattedValue(value: AST, conversion: CInt, format_spec: AST)""" + value: AST | t.CPtr + conversion: t.CInt + format_spec: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, conversion: t.CInt, + format_spec: AST | t.CPtr): + ptr: FormattedValue | t.CPtr = pool.alloc(FormattedValue.__sizeof__()) + if ptr: + string.memset(ptr, 0, FormattedValue.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, conversion: t.CInt, + format_spec: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + self.conversion = conversion + self.format_spec = format_spec + + def kind(self) -> t.CInt: + return ASTKind.FormattedValue + + def type_name(self) -> str: + return "FormattedValue" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "FormattedValue(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", conversion=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.conversion)) + pos = _emit(buf, size, pos, ", format_spec=") + if self.format_spec is not None: + pos = self.format_spec.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# JoinedStr Node +# ============================================================ + +class JoinedStr(ExprNode): + """JoinedStr(values: list[AST | CPtr])""" + values: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + ptr: JoinedStr | t.CPtr = pool.alloc(JoinedStr.__sizeof__()) + if ptr: + string.memset(ptr, 0, JoinedStr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.values = values + _set_parent_list(values, self) + + def kind(self) -> t.CInt: + return ASTKind.JoinedStr + + def type_name(self) -> str: + return "JoinedStr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "JoinedStr(values=") + pos = _dump_list(self.values, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Attribute Node +# ============================================================ + +class Attribute(ExprNode): + """Attribute(value: AST, attr: str, ctx: CInt)""" + value: AST | t.CPtr + attr: str + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, attr: str, ctx: t.CInt): + ptr: Attribute | t.CPtr = pool.alloc(Attribute.__sizeof__()) + if ptr: + string.memset(ptr, 0, Attribute.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, attr: str, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.value = value + self.attr = _copy_str(pool, attr) + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Attribute + + def type_name(self) -> str: + return "Attribute" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Attribute(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", attr='") + pos = _emit_str(buf, size, pos, self.attr) + pos = _emit(buf, size, pos, "', ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Subscript Node +# ============================================================ + +class Subscript(ExprNode): + """Subscript(value: AST, slice: AST, ctx: CInt)""" + value: AST | t.CPtr + slice: AST | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, slice: AST | t.CPtr, ctx: t.CInt): + ptr: Subscript | t.CPtr = pool.alloc(Subscript.__sizeof__()) + if ptr: + string.memset(ptr, 0, Subscript.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, slice: AST | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.value = value + self.slice = slice + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Subscript + + def type_name(self) -> str: + return "Subscript" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Subscript(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", slice=") + if self.slice is not None: + pos = self.slice.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Starred Node +# ============================================================ + +class Starred(ExprNode): + """Starred(value: AST, ctx: CInt)""" + value: AST | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, ctx: t.CInt): + ptr: Starred | t.CPtr = pool.alloc(Starred.__sizeof__()) + if ptr: + string.memset(ptr, 0, Starred.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.value = value + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Starred + + def type_name(self) -> str: + return "Starred" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Starred(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# List Node +# ============================================================ + +class List(ExprNode): + """List(elts: list[AST | CPtr], ctx: CInt)""" + elts: list[AST | t.CPtr] | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + ptr: List | t.CPtr = pool.alloc(List.__sizeof__()) + if ptr: + string.memset(ptr, 0, List.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.elts = elts + self.ctx = ctx + _set_parent_list(elts, self) + + def kind(self) -> t.CInt: + return ASTKind.List + + def type_name(self) -> str: + return "List" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "List(elts=") + pos = _dump_list(self.elts, buf, size, pos) + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Tuple Node +# ============================================================ + +class Tuple(ExprNode): + """Tuple(elts: list[AST | CPtr], ctx: CInt)""" + elts: list[AST | t.CPtr] | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + ptr: Tuple | t.CPtr = pool.alloc(Tuple.__sizeof__()) + if ptr: + string.memset(ptr, 0, Tuple.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.elts = elts + self.ctx = ctx + _set_parent_list(elts, self) + + def kind(self) -> t.CInt: + return ASTKind.Tuple + + def type_name(self) -> str: + return "Tuple" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Tuple(elts=") + pos = _dump_list(self.elts, buf, size, pos) + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Slice Node +# ============================================================ + +class Slice(ExprNode): + """Slice(lower: AST, upper: AST, step: AST)""" + lower: AST | t.CPtr + upper: AST | t.CPtr + step: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + lower: AST | t.CPtr, upper: AST | t.CPtr, + step: AST | t.CPtr): + ptr: Slice | t.CPtr = pool.alloc(Slice.__sizeof__()) + if ptr: + string.memset(ptr, 0, Slice.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + lower: AST | t.CPtr, upper: AST | t.CPtr, + step: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.lower = lower + self.upper = upper + self.step = step + + def kind(self) -> t.CInt: + return ASTKind.Slice + + def type_name(self) -> str: + return "Slice" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Slice(lower=") + if self.lower is not None: + pos = self.lower.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", upper=") + if self.upper is not None: + pos = self.upper.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", step=") + if self.step is not None: + pos = self.step.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# NamedExpr Node +# ============================================================ + +class NamedExpr(ExprNode): + """NamedExpr(target: AST, value: AST)""" + target: AST | t.CPtr + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, value: AST | t.CPtr): + ptr: NamedExpr | t.CPtr = pool.alloc(NamedExpr.__sizeof__()) + if ptr: + string.memset(ptr, 0, NamedExpr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.target = target + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.NamedExpr + + def type_name(self) -> str: + return "NamedExpr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "NamedExpr(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# OpNode Node +# ============================================================ + +class OpNode(AST): + """OpNode(op: CInt)""" + op: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, op: t.CInt): + ptr: OpNode | t.CPtr = pool.alloc(OpNode.__sizeof__()) + if ptr: + string.memset(ptr, 0, OpNode.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, op: t.CInt): + _init_ast(self, pool, 0, 0) + self.op = op + + def kind(self) -> t.CInt: + return ASTKind.OpNode + + def type_name(self) -> str: + return "OpNode" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "OpNode(op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/lexer.vp b/ast/lexer.vp new file mode 100644 index 0000000..2b82bb8 --- /dev/null +++ b/ast/lexer.vp @@ -0,0 +1,773 @@ +import t, c +from stdint import * +import memhub +import string +from .tokens import ( + Token, TokenType, TokOp, _init_tables, _kw_lookup, _op_head, + OpEntry, new_token, token_set_str, token_set_str_literal, +) + + +# Maximum Indentation Stack Depth +LEXER_MAX_INDENT: t.CDefine = 256 + + +# ============================================================ +# Lexer State Structure +# ============================================================ +class Lexer: + src: str # Source code (NUL-terminated) + pos: t.CSizeT # Current position + len: t.CSizeT # Source code length + lineno: t.CInt # Current line number (1-based) + col: t.CInt # Current column number (0-based) + pool: memhub.MemManager | t.CPtr # Memory pool + indent_stack: t.CInt | t.CPtr # Indent stack (int array, allocated from pool) + indent_top: t.CInt # Stack top (-1 for empty stack) + paren_depth: t.CInt # Paren depth (>0 for no TokenType.NewLine) + tokens_head: Token | t.CPtr # token list head + tokens_tail: Token | t.CPtr # token list tail + at_line_start: t.CInt # 1=line start (need indent) + error_count: t.CInt # Error count + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Lexer | t.CPtr = pool.alloc(Lexer.__sizeof__()) + if ptr: + string.memset(ptr, 0, Lexer.__sizeof__()) + return ptr + + +def new_lexer(pool: memhub.MemManager | t.CPtr) -> Lexer | t.CPtr: + """Allocate from the pool and return a Lexer (cross-module safe wrapper)""" + return Lexer(pool) + + +def _lexer_init(lx: Lexer | t.CPtr, src: str, + pool: memhub.MemManager | t.CPtr): + """Initialize Lexer""" + if lx == None: return + lx.src = src + lx.pos = 0 + lx.len = string.strlen(src) if src != None else 0 + lx.lineno = 1 + lx.col = 0 + lx.pool = pool + # Allocate indentation stack + lx.indent_stack = pool.alloc(LEXER_MAX_INDENT * 8) + if lx.indent_stack != None: + string.memset(lx.indent_stack, 0, LEXER_MAX_INDENT * 8) + lx.indent_top = -1 + # Push 0 (base indent) + if lx.indent_stack != None: + lx.indent_stack[0] = 0 + lx.indent_top = 0 + lx.paren_depth = 0 + lx.tokens_head = None + lx.tokens_tail = None + lx.at_line_start = 1 + lx.error_count = 0 + _init_tables(pool) + + +# ============================================================ +# Auxiliary Functions +# ============================================================ + +def _peek(lx: Lexer | t.CPtr, offset: t.CSizeT) -> t.CChar: + """Peek character at position pos+offset, return '\0' if out of bounds""" + p: t.CSizeT = lx.pos + offset + if p >= lx.len: + return '\0' + return lx.src[p] + + +def _peek_cur(lx: Lexer | t.CPtr) -> t.CChar: + if lx.pos >= lx.len: + return '\0' + return lx.src[lx.pos] + + +def _advance(lx: Lexer | t.CPtr) -> t.CChar: + """Advance one character, return the character""" + if lx.pos >= lx.len: + return '\0' + ch: t.CChar = lx.src[lx.pos] + lx.pos += 1 + if ch == '\n': + lx.lineno += 1 + lx.col = 0 + else: + lx.col += 1 + return ch + + +def _is_alpha(ch: t.CChar) -> t.CInt: + if ch >= 'a' and ch <= 'z': return 1 + if ch >= 'A' and ch <= 'Z': return 1 + if ch == '_': return 1 + return 0 + + +def _is_digit(ch: t.CChar) -> t.CInt: + if ch >= '0' and ch <= '9': return 1 + return 0 + + +def _is_alnum(ch: t.CChar) -> t.CInt: + if _is_alpha(ch): return 1 + if _is_digit(ch): return 1 + return 0 + + +def _is_hex(ch: t.CChar) -> t.CInt: + if ch >= '0' and ch <= '9': return 1 + if ch >= 'a' and ch <= 'f': return 1 + if ch >= 'A' and ch <= 'F': return 1 + return 0 + + +def _is_space(ch: t.CChar) -> t.CInt: + if ch == ' ': return 1 + if ch == '\t': return 1 + if ch == '\f': return 1 + if ch == '\v': return 1 + if ch == '\r': return 1 + return 0 + + +def _emit(lx: Lexer | t.CPtr, tok: Token | t.CPtr): + """Append token to token list""" + if tok == None: return + if lx.tokens_head == None: + lx.tokens_head = tok + lx.tokens_tail = tok + else: + lx.tokens_tail.next = tok + lx.tokens_tail = tok + + +def _make_op_token(lx: Lexer | t.CPtr, op_id: t.CInt, length: t.CInt, + lineno: t.CInt, col: t.CInt) -> Token | t.CPtr: + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Op, lineno, col) + if tok == None: return None + tok.op_subtype = op_id + tok.end_col_offset = col + length + return tok + + +# ============================================================ +# Indent Handling +# ============================================================ + +def _handle_indent(lx: Lexer | t.CPtr): + """Handle line start indent, generate TokenType.Indent/TokenType.Dedent. + Skip empty lines and comment lines.""" + # Skip empty lines and comment lines + while lx.pos < lx.len: + # Save line start position for non-empty lines + line_start_pos: t.CSizeT = lx.pos + line_start_col: t.CInt = lx.col + # Skip whitespace, not across lines + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == ' ' or ch == '\t' or ch == '\f' or ch == '\v': + lx.pos += 1 + lx.col += 1 + elif ch == '\r': + # CRLF line end \r, skip \n to trigger empty line processing + lx.pos += 1 + else: + break + if lx.pos >= lx.len: + break + ch = lx.src[lx.pos] + if ch == '\n': + # Empty line, skip + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + if ch == '\r': + # CRLF line end \r, skip \n to trigger empty line processing + lx.pos += 1 + if lx.pos < lx.len and lx.src[lx.pos] == '\n': + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + if ch == '#': + # Comment line, skip to end of line + while lx.pos < lx.len and lx.src[lx.pos] != '\n': + lx.pos += 1 + continue + # Non-empty line: backtrack to line start to allow indent calculation + lx.pos = line_start_pos + lx.col = line_start_col + break + + if lx.pos >= lx.len: + # End of file, no indent to handle + lx.at_line_start = 0 + return + + # Calculate current line indent + indent: t.CInt = 0 + save_pos: t.CSizeT = lx.pos + save_col: t.CInt = lx.col + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == ' ': + indent += 1 + lx.pos += 1 + lx.col += 1 + elif ch == '\t': + indent += 8 - (indent % 8) + lx.pos += 1 + lx.col += 1 + else: + break + + # If line end (empty line), skip indent calculation + if lx.pos < lx.len: + ch = lx.src[lx.pos] + if ch == '\n' or ch == '\r' or ch == '#': + # Empty line or comment line, backtrack position to allow loop to handle indent + lx.pos = save_pos + lx.col = save_col + lx.at_line_start = 0 + return + + # Compare indent with top of indent stack + top_indent: t.CInt = lx.indent_stack[lx.indent_top] + if indent > top_indent: + # TokenType.Indent + if lx.indent_top + 1 >= LEXER_MAX_INDENT: + lx.error_count += 1 + return + lx.indent_top += 1 + lx.indent_stack[lx.indent_top] = indent + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Indent, lx.lineno, 0) + _emit(lx, tok) + else: + while indent < lx.indent_stack[lx.indent_top] and lx.indent_top > 0: + lx.indent_top -= 1 + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0) + _emit(lx, tok) + lx.at_line_start = 0 + + +# ============================================================ +# Identifier/Keyword Handling +# ============================================================ + +def _read_name(lx: Lexer | t.CPtr): + start: t.CSizeT = lx.pos + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_alnum(ch): + lx.pos += 1 + lx.col += 1 + else: + break + length: t.CSizeT = lx.pos - start + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Name, start_lineno, start_col) + if tok == None: return + token_set_str(lx.pool, tok, lx.src, start, length) + tok.end_lineno = lx.lineno + tok.end_col_offset = start_col + t.CInt(length) + # Look up keyword if any + kw_id: t.CInt = _kw_lookup(tok.str_val) + if kw_id: + tok.kw_subtype = kw_id + _emit(lx, tok) + + +# ============================================================ +# Number Handling +# ============================================================ + +def _read_number(lx: Lexer | t.CPtr): + start: t.CSizeT = lx.pos + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + is_float: t.CInt = 0 + is_complex: t.CInt = 0 + + ch0: t.CChar = lx.src[lx.pos] + # Handle 0x/0o/0b prefix + if ch0 == '0' and lx.pos + 1 < lx.len: + ch1: t.CChar = lx.src[lx.pos + 1] + if ch1 == 'x' or ch1 == 'X': + lx.pos += 2 + lx.col += 2 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_hex(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + _emit_number(lx, start, start_lineno, start_col, 0, 0, 0) + return + if ch1 == 'o' or ch1 == 'O': + lx.pos += 2 + lx.col += 2 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch >= '0' and ch <= '7': + lx.pos += 1 + lx.col += 1 + elif ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + _emit_number(lx, start, start_lineno, start_col, 0, 0, 0) + return + if ch1 == 'b' or ch1 == 'B': + lx.pos += 2 + lx.col += 2 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == '0' or ch == '1' or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + _emit_number(lx, start, start_lineno, start_col, 0, 0, 0) + return + + # Decimal integer/float + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_digit(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + + # Decimal part + if lx.pos < lx.len and lx.src[lx.pos] == '.': + is_float = 1 + lx.pos += 1 + lx.col += 1 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_digit(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + + # Exponent part + if lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == 'e' or ch == 'E': + is_float = 1 + lx.pos += 1 + lx.col += 1 + if lx.pos < lx.len: + ch = lx.src[lx.pos] + if ch == '+' or ch == '-': + lx.pos += 1 + lx.col += 1 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_digit(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + + # Complex suffix part + if lx.pos < lx.len and lx.src[lx.pos] == 'j': + is_complex = 1 + is_float = 1 + lx.pos += 1 + lx.col += 1 + + _emit_number(lx, start, start_lineno, start_col, is_float, is_complex, 0) + + +def _emit_number(lx: Lexer | t.CPtr, start: t.CSizeT, + start_lineno: t.CInt, start_col: t.CInt, + is_float: t.CInt, is_complex: t.CInt, is_hex: t.CInt): + length: t.CSizeT = lx.pos - start + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Number, start_lineno, start_col) + if tok == None: return + token_set_str(lx.pool, tok, lx.src, start, length) + tok.is_float = is_float + tok.is_complex = is_complex + tok.end_lineno = lx.lineno + tok.end_col_offset = start_col + t.CInt(length) + # Parse number + if is_float: + tok.float_val = string.atof(tok.str_val) + else: + tok.int_val = string.atoll(tok.str_val) + _emit(lx, tok) + + +# ============================================================ +# String Handling +# ============================================================ + +def _read_string(lx: Lexer | t.CPtr): + """Read string literal. + Supports prefixes: r, b, u, f, rb, br, rf, fr (case insensitive) + Supports quotes: ', ", ''', + Later we need to support string prefixes like i16/i24""" + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + prefix_start: t.CSizeT = lx.pos + + # Read prefix (r/b/u/f) + is_raw: t.CInt = 0 + is_bytes: t.CInt = 0 + is_fstring: t.CInt = 0 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == 'r' or ch == 'R': + is_raw = 1 + lx.pos += 1 + lx.col += 1 + elif ch == 'b' or ch == 'B': + is_bytes = 1 + lx.pos += 1 + lx.col += 1 + elif ch == 'u' or ch == 'U': + lx.pos += 1 + lx.col += 1 + elif ch == 'f' or ch == 'F': + is_fstring = 1 + lx.pos += 1 + lx.col += 1 + else: + break + + if lx.pos >= lx.len: + lx.error_count += 1 + return + + # Determine quote type + quote: t.CChar = lx.src[lx.pos] + if quote != '\'' and quote != '"': + lx.error_count += 1 + return + + # Check triple quote + is_triple: t.CInt = 0 + if lx.pos + 2 < lx.len: + if lx.src[lx.pos] == quote and lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote: + is_triple = 1 + + content_start: t.CSizeT = lx.pos + if is_triple: + lx.pos += 3 + lx.col += 3 + else: + lx.pos += 1 + lx.col += 1 + + # Read string content + content_buf_start: t.CSizeT = lx.pos + while lx.pos < lx.len: + ch = lx.src[lx.pos] + if is_triple: + if ch == quote: + if lx.pos + 2 < lx.len: + if lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote: + break + elif lx.pos + 2 == lx.len: + break + if ch == '\\': + lx.pos += 1 + lx.col += 1 + if lx.pos < lx.len: + if lx.src[lx.pos] == '\n': + lx.lineno += 1 + lx.col = 0 + lx.pos += 1 + lx.col += 1 + continue + if ch == '\n': + lx.lineno += 1 + lx.col = 0 + lx.pos += 1 + lx.col += 1 + else: + if ch == quote: + break + if ch == '\n': + # Single quote string cannot span multiple lines (unless continued) + lx.error_count += 1 + return + if ch == '\\' and not is_raw: + lx.pos += 1 + lx.col += 1 + if lx.pos < lx.len: + lx.pos += 1 + lx.col += 1 + continue + lx.pos += 1 + lx.col += 1 + + content_end: t.CSizeT = lx.pos + # Skip the closing quote + if is_triple: + if lx.pos + 2 < lx.len: + lx.pos += 3 + lx.col += 3 + else: + lx.pos = lx.len + else: + if lx.pos < lx.len: + lx.pos += 1 + lx.col += 1 + + # Create token + tok: Token | t.CPtr = new_token(lx.pool, TokenType.String, start_lineno, start_col) + if tok == None: return + content_len: t.CSizeT = content_end - content_buf_start + # esc_len: Actual bytes after escaping (used to check single character) + esc_len: t.CSizeT = content_len + + # Handle escape sequences (non-raw strings) + if is_raw == 0 and content_len > 0: + # Allocate conversion buffer (max case: each char is plain, no extension) + conv_buf: str = lx.pool.alloc(content_len + 1) + if conv_buf == None: + token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len) + else: + wpos: t.CSizeT = 0 + rpos: t.CSizeT = 0 + while rpos < content_len: + ch: t.CChar = lx.src[content_buf_start + rpos] + if ch == '\\' and rpos + 1 < content_len: + rpos += 1 + next_ch: t.CChar = lx.src[content_buf_start + rpos] + if next_ch == 'n': + conv_buf[wpos] = '\n' + elif next_ch == 't': + conv_buf[wpos] = '\t' + elif next_ch == 'r': + conv_buf[wpos] = '\r' + elif next_ch == 'f': + conv_buf[wpos] = '\f' + elif next_ch == 'v': + conv_buf[wpos] = '\v' + elif next_ch == 'a': + conv_buf[wpos] = '\a' + elif next_ch == 'b': + conv_buf[wpos] = '\b' + elif next_ch == '\\': + conv_buf[wpos] = '\\' + elif next_ch == '\'': + conv_buf[wpos] = '\'' + elif next_ch == '"': + conv_buf[wpos] = '"' + elif next_ch == '0': + conv_buf[wpos] = '\0' + else: + # Unknown escape sequence, keep original (includes \xNN) + conv_buf[wpos] = '\\' + wpos += 1 + conv_buf[wpos] = next_ch + wpos += 1 + rpos += 1 + else: + conv_buf[wpos] = ch + wpos += 1 + rpos += 1 + conv_buf[wpos] = '\0' + token_set_str_literal(lx.pool, tok, conv_buf) + esc_len = wpos + else: + token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len) + tok.end_lineno = lx.lineno + tok.end_col_offset = lx.col + # flags field: bit0=raw, bit1=bytes, bit2=fstring, bit3=triple, bit4=dquote, bit5=single char candidate + if is_raw: tok.kw_subtype = tok.kw_subtype | 1 + if is_bytes: tok.kw_subtype = tok.kw_subtype | 2 + if is_fstring: tok.kw_subtype = tok.kw_subtype | 4 + if is_triple: tok.kw_subtype = tok.kw_subtype | 8 + # bit4 (16) = double quote=single quote + if quote == '"': tok.kw_subtype = tok.kw_subtype | 16 + # bit5 (32) = single-character candidate (not triple quotes, not f-string, exactly 1 byte after escaping) + # Used for CONST_CHAR checks to prevent '0' and other NUL bytes from being mistaken as empty strings by strlen + if is_triple == 0 and is_fstring == 0 and esc_len == 1: + tok.kw_subtype = tok.kw_subtype | 32 + _emit(lx, tok) + + +# ============================================================ +# Operator Matching +# ============================================================ + +def _read_operator(lx: Lexer | t.CPtr): + """Greedy match operator""" + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + remaining: t.CSizeT = lx.len - lx.pos + + # Traverse operator table, find longest match + best_entry: OpEntry | t.CPtr = None + best_len: t.CInt = 0 + cur: OpEntry | t.CPtr = _op_head + while cur != None: + if cur.length <= t.CInt(remaining): + # Compare cur.name with src[pos:pos+cur.length] + match: t.CInt = 1 + i: t.CSizeT = 0 + while i < t.CSizeT(cur.length): + if lx.src[lx.pos + i] != cur.name[i]: + match = 0 + break + i += 1 + if match: + if cur.length > best_len: + best_len = cur.length + best_entry = cur + cur = cur.next + + if best_entry == None: + # Unknown character, report error and skip + lx.error_count += 1 + lx.pos += 1 + lx.col += 1 + return + + # Update parenthesis depth + if best_entry.op_id == TokOp.LPar or best_entry.op_id == TokOp.Lsqb or best_entry.op_id == TokOp.LBrace: + lx.paren_depth += 1 + elif best_entry.op_id == TokOp.RPar or best_entry.op_id == TokOp.Rsqb or best_entry.op_id == TokOp.RBrace: + if lx.paren_depth > 0: + lx.paren_depth -= 1 + + tok: Token | t.CPtr = _make_op_token(lx, best_entry.op_id, best_entry.length, + start_lineno, start_col) + if tok == None: return + token_set_str(lx.pool, tok, lx.src, lx.pos, t.CSizeT(best_len)) + lx.pos += t.CSizeT(best_len) + lx.col += best_len + _emit(lx, tok) + + +# ============================================================ +# Main Lexical Analysis Entry Point +# ============================================================ + +def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr: + """Execute tokenization, return token list head""" + if lx == None: return None + while lx.pos < lx.len: + # Handle line start indent + if lx.at_line_start and lx.paren_depth == 0: + _handle_indent(lx) + if lx.pos >= lx.len: + break + + ch: t.CChar = _peek_cur(lx) + if ch == '\0': + break + + # New line + if ch == '\n': + if lx.paren_depth > 0: + # # In bi brackets, generates TokenType.Nl + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Nl, lx.lineno, lx.col) + _emit(lx, tok) + else: + # Logical new line + tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col) + _emit(lx, tok) + lx.at_line_start = 1 + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + + # Backslash continuation line + # 支持 LF 与 CRLF(Windows 文件行尾):CRLF 下 `\` 后是 '\r'(非 '\n'), + # 只查 '\n' 会失效 → `\` 被当未知字符跳过、'\n' 产生 NEWLINE → 表达式 + # 中断(VpiReader.vp L324 `or \` 行尾续行根因,CRLF 文件)。 + if ch == '\\' and lx.pos + 1 < lx.len: + if lx.src[lx.pos + 1] == '\n': + lx.pos += 2 + lx.lineno += 1 + lx.col = 0 + continue + if lx.src[lx.pos + 1] == '\r': + # \ + \r\n:跳 \、\r、\n + lx.pos += 2 + if lx.pos < lx.len and lx.src[lx.pos] == '\n': + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + + # Whitespace + if _is_space(ch): + lx.pos += 1 + lx.col += 1 + continue + + # Comment + if ch == '#': + while lx.pos < lx.len and lx.src[lx.pos] != '\n': + lx.pos += 1 + continue + + # String prefixes (like r"...") or strings + if ch == '\'' or ch == '"': + _read_string(lx) + continue + # A string prefix letter followed by a quote (must be checked before _is_alpha, otherwise f/r/b/u will be treated as TokenType.Name) + if (ch == 'r' or ch == 'R' or ch == 'b' or ch == 'B' or + ch == 'u' or ch == 'U' or ch == 'f' or ch == 'F'): + if lx.pos + 1 < lx.len: + ch1: t.CChar = lx.src[lx.pos + 1] + if ch1 == '\'' or ch1 == '"': + _read_string(lx) + continue + # Double prefixes like rb, br, rf, fr + if lx.pos + 2 < lx.len: + ch2: t.CChar = lx.src[lx.pos + 2] + if ((ch1 == 'r' or ch1 == 'R' or ch1 == 'b' or ch1 == 'B' or + ch1 == 'f' or ch1 == 'F' or ch1 == 'u' or ch1 == 'U') and + (ch2 == '\'' or ch2 == '"')): + _read_string(lx) + continue + + # Identifier/keyword + if _is_alpha(ch): + _read_name(lx) + continue + + # Number + if _is_digit(ch): + _read_number(lx) + continue + + # Operator + _read_operator(lx) + + # End of file: generate TokenType.NewLine (if there's content) + if lx.tokens_tail != None: + if lx.tokens_tail.type != TokenType.NewLine and lx.tokens_tail.type != TokenType.Nl: + tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col) + _emit(lx, tok) + + # Generate remaining remaining TokenType.Dedent + while lx.indent_top > 0: + lx.indent_top -= 1 + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0) + _emit(lx, tok) + + # TokenType.EndMarker + tok: Token | t.CPtr = new_token(lx.pool, TokenType.EndMarker, lx.lineno, 0) + _emit(lx, tok) + + return lx.tokens_head diff --git a/ast/match.vp b/ast/match.vp new file mode 100644 index 0000000..7e78378 --- /dev/null +++ b/ast/match.vp @@ -0,0 +1,363 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, ASTKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, +) + + +# ============================================================ +# MatchCase 节点Node +# ============================================================ + +class MatchCase(AST): + """MatchCase(pattern: AST, guard: AST)""" + pattern: AST | t.CPtr + guard: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, guard: AST | t.CPtr): + ptr: MatchCase | t.CPtr = pool.alloc(MatchCase.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchCase.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, guard: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.pattern = pattern + self.guard = guard + + def kind(self) -> t.CInt: + return ASTKind.MatchCase + + def type_name(self) -> str: + return "MatchCase" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchCase(pattern=") + if self.pattern is not None: + pos = self.pattern.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", guard=") + if self.guard is not None: + pos = self.guard.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchValue Node +# ============================================================ + +class MatchValue(AST): + """MatchValue(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: MatchValue | t.CPtr = pool.alloc(MatchValue.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchValue.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.MatchValue + + def type_name(self) -> str: + return "MatchValue" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchValue(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchSingleton Node +# ============================================================ + +class MatchSingleton(AST): + """MatchSingleton(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: MatchSingleton | t.CPtr = pool.alloc(MatchSingleton.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchSingleton.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.MatchSingleton + + def type_name(self) -> str: + return "MatchSingleton" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchSingleton(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchSequence Node +# ============================================================ + +class MatchSequence(AST): + """MatchSequence(patterns: list[AST | t.CPtr])""" + patterns: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + ptr: MatchSequence | t.CPtr = pool.alloc(MatchSequence.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchSequence.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.patterns = patterns + _set_parent_list(patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchSequence + + def type_name(self) -> str: + return "MatchSequence" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchSequence(patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchMapping Node +# ============================================================ + +class MatchMapping(AST): + """MatchMapping(keys: list[AST | t.CPtr], patterns: list[AST | t.CPtr], rest: str)""" + keys: list[AST | t.CPtr] | t.CPtr + patterns: list[AST | t.CPtr] | t.CPtr + rest: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + rest: str): + ptr: MatchMapping | t.CPtr = pool.alloc(MatchMapping.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchMapping.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + rest: str): + _init_ast(self, pool, 0, 0) + self.keys = keys + self.patterns = patterns + self.rest = _copy_str(pool, rest) + _set_parent_list(keys, self) + _set_parent_list(patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchMapping + + def type_name(self) -> str: + return "MatchMapping" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchMapping(keys=") + pos = _dump_list(self.keys, buf, size, pos) + pos = _emit(buf, size, pos, ", patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ", rest='") + pos = _emit_str(buf, size, pos, self.rest) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# MatchClass Node +# ============================================================ + +class MatchClass(AST): + """MatchClass(cls: AST, patterns: list[AST | t.CPtr], + kwd_attrs: list[AST | t.CPtr], kwd_patterns: list[AST | t.CPtr])""" + cls: AST | t.CPtr + patterns: list[AST | t.CPtr] | t.CPtr + kwd_attrs: list[AST | t.CPtr] | t.CPtr + kwd_patterns: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + cls: AST | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + kwd_attrs: list[AST | t.CPtr] | t.CPtr, + kwd_patterns: list[AST | t.CPtr] | t.CPtr): + ptr: MatchClass | t.CPtr = pool.alloc(MatchClass.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchClass.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + cls: AST | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + kwd_attrs: list[AST | t.CPtr] | t.CPtr, + kwd_patterns: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.cls = cls + self.patterns = patterns + self.kwd_attrs = kwd_attrs + self.kwd_patterns = kwd_patterns + _set_parent_list(patterns, self) + _set_parent_list(kwd_attrs, self) + _set_parent_list(kwd_patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchClass + + def type_name(self) -> str: + return "MatchClass" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchClass(cls=") + if self.cls is not None: + pos = self.cls.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ", kwd_attrs=") + pos = _dump_list(self.kwd_attrs, buf, size, pos) + pos = _emit(buf, size, pos, ", kwd_patterns=") + pos = _dump_list(self.kwd_patterns, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchStar Node +# ============================================================ + +class MatchStar(AST): + """MatchStar(name: str)""" + name: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, name: str): + ptr: MatchStar | t.CPtr = pool.alloc(MatchStar.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchStar.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, name: str): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + + def kind(self) -> t.CInt: + return ASTKind.MatchStar + + def type_name(self) -> str: + return "MatchStar" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchStar(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# MatchAs Node +# ============================================================ + +class MatchAs(AST): + """MatchAs(pattern: AST, name: str)""" + pattern: AST | t.CPtr + name: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, name: str): + ptr: MatchAs | t.CPtr = pool.alloc(MatchAs.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchAs.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, name: str): + _init_ast(self, pool, 0, 0) + self.pattern = pattern + self.name = _copy_str(pool, name) + + def kind(self) -> t.CInt: + return ASTKind.MatchAs + + def type_name(self) -> str: + return "MatchAs" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchAs(pattern=") + if self.pattern is not None: + pos = self.pattern.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# MatchOr Node +# ============================================================ + +class MatchOr(AST): + """MatchOr(patterns: list[AST | t.CPtr])""" + patterns: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + ptr: MatchOr | t.CPtr = pool.alloc(MatchOr.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchOr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.patterns = patterns + _set_parent_list(patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchOr + + def type_name(self) -> str: + return "MatchOr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchOr(patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/parser.vp b/ast/parser.vp new file mode 100644 index 0000000..3f49e0e --- /dev/null +++ b/ast/parser.vp @@ -0,0 +1,2749 @@ +import t, c +from stdint import * +import memhub +import string +import stdio +import stdlib +from .tokens import (Token, TokenType, Keyword, TokOp) +from .base import ( + AST, ASTCtx, ASTKind, OpKind, ASTFlag, + _set_pos, _binop_from_op, _augop_from_op, _cmpop_from_op, _copy_str, _inherit_pos, + _init_ast, + CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR, + FLAG_IS_ASYNC, FLAG_IS_EXTERN, +) +from .exprs import ( + BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set, + ListComp, SetComp, DictComp, GeneratorExp, + Await, Yield, YieldFrom, FormattedValue, JoinedStr, + Constant, NamedExpr, Attribute, Subscript, Starred, Name, + List, Tuple, Slice, Call, Compare, OpNode, +) +from .stmts import ( + Module, Expression, Interactive, FunctionType, + FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign, + For, While, If, With, Raise, Try, Assert, Global, Nonlocal, + Pass, Break, Continue, Expr, Import, ImportFrom, Match, +) +from .astaux import ( + ExceptHandler, Arguments, Arg, Keyword as KwNode, Alias, WithItem, Comprehension, +) +from .match import ( + MatchCase, MatchValue, MatchSingleton, MatchSequence, + MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr, +) +from .lexer import Lexer, _lexer_init, tokenize, new_lexer + + +# ============================================================ +# Parser State +# ============================================================ +class Parser: + tokens: Token | t.CPtr # token linked list head + cur: Token | t.CPtr # current token + pool: memhub.MemManager | t.CPtr # memory pool + error_count: t.CInt # error count + pending_decorators: list[AST | t.CPtr] | t.CPtr # pending decorators list + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Parser | t.CPtr = pool.alloc(Parser.__sizeof__()) + if ptr: + string.memset(ptr, 0, Parser.__sizeof__()) + return ptr + + +def new_parser(pool: memhub.MemManager | t.CPtr) -> Parser | t.CPtr: + """Allocate from the pool and return the Parser (cross-module safe wrapper)""" + return Parser(pool) + + +def _parser_init(ps: Parser | t.CPtr, tokens: Token | t.CPtr, + pool: memhub.MemManager | t.CPtr): + if ps is None: return + ps.tokens = tokens + ps.cur = tokens + ps.pool = pool + ps.error_count = 0 + ps.pending_decorators = None + + +# ============================================================ +# Token Navigation Helpers +# ============================================================ + +def _advance(ps: Parser | t.CPtr): + """Advance to the next token""" + if ps.cur is None: return + if ps.cur.next is not None: + ps.cur = ps.cur.next + + +def _cur_type(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return TokenType.EndMarker + return ps.cur.type + + +def _cur_op(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.op_subtype + + +def _cur_kw(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.kw_subtype + + +def _is_funcdef_kw(ps: Parser | t.CPtr, kw: t.CInt) -> int: + """判断当前 token 是否为函数定义关键字(def 及其别名 fn/fun/func/function, + 以及 extern 声明关键字) + + def 是硬关键字直接判定;fn/fun/func/function/extern 是软关键字, + 仅当下一个 token 是 Name 且再下一个是 '('(或泛型 '[T]' 前的 '[')时 + 判定为函数定义。extern 还允许 'extern def A(...)' 形式(下一个是 def)。 + 否则按普通标识符处理,兼容既有代码把 func 用作 + 字段/参数名(如 AST 节点 func 字段、Call.func 注解 `func: AST | t.CPtr`)。 + """ + if kw == Keyword.Def: + return 1 + if kw == Keyword.Extern: + # extern def A(...) 或 extern A(...)(extern 后是 def 或 Name+'(/'[') + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.kw_subtype == Keyword.Def: + return 1 + if nxt.type != TokenType.Name: + return 0 + nxt2: Token | t.CPtr = nxt.next + if nxt2 is None: + return 0 + if nxt2.type == TokenType.Op \ + and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): + return 1 + return 0 + if kw == Keyword.Fn or kw == Keyword.Fun \ + or kw == Keyword.Func or kw == Keyword.Function: + # 软关键字 lookahead: 下个是 Name,再下个是 '(' 或 '[T...]' 泛型参数(PEP 695) + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.type != TokenType.Name: + return 0 + nxt2: Token | t.CPtr = nxt.next + if nxt2 is None: + return 0 + if nxt2.type == TokenType.Op \ + and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): + return 1 + return 0 + return 0 + + +def _is_match_stmt(ps: Parser | t.CPtr) -> int: + """match 是软关键字(CPython 3.10+):lookahead 判断是否为 match 语句 + + match 后直接跟 ':'(变量注解,如 lexer.vp 的 `match: t.CInt = 1`)、 + '='(赋值,如 `match = 0`)、换行/文件尾 → 按普通标识符; + 否则扫描至行尾,在括号深度 0 处出现 ':' → match 语句(subject 后必须冒号)。 + case/type 同理为软关键字(case 仅在 match 套件内消费,type 无语句分发)。 + """ + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.type == TokenType.NewLine or nxt.type == TokenType.EndMarker: + return 0 + if nxt.type == TokenType.Op: + if nxt.op_subtype == TokOp.Colon: + return 0 + if nxt.op_subtype == TokOp.Equal: + return 0 + walk: Token | t.CPtr = nxt + depth: t.CInt = 0 + while walk is not None: + if walk.type == TokenType.NewLine or walk.type == TokenType.EndMarker: + return 0 + if walk.type == TokenType.Op: + wop: t.CInt = walk.op_subtype + if wop == TokOp.LPar or wop == TokOp.Lsqb or wop == TokOp.LBrace: + depth += 1 + elif wop == TokOp.RPar or wop == TokOp.Rsqb or wop == TokOp.RBrace: + if depth > 0: + depth -= 1 + elif wop == TokOp.Colon and depth == 0: + return 1 + walk = walk.next + return 0 + + +# 解析错误位置与消息(fail-fast 仿 Python SyntaxError 报告,首次错误记录) +_g_parse_err_line: t.CInt = 0 +_g_parse_err_col: t.CInt = 0 +_g_parse_err_msg: str = None + + +def _record_parse_err(ps: Parser | t.CPtr): + """记录首个解析错误的位置与消息(只记录第一次,后续错误不覆盖)""" + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + if _g_parse_err_line != 0: + return + _g_parse_err_line = _cur_lineno(ps) + _g_parse_err_col = _cur_col(ps) + err_s: str = _cur_str(ps) + if err_s is None: + err_s = "(none)" + # 消息文本用 stdlib 拷贝(token 的 str_val 在 pool 中,生命周期覆盖本次编译但保险起见独立存储) + buf_m: str = stdlib.malloc(128) + if buf_m is not None: + stdio.snprintf(buf_m, 128, "意外的 token '%s'", err_s) + _g_parse_err_msg = buf_m + else: + _g_parse_err_msg = err_s + + +def get_parse_err_line() -> t.CInt: + """获取最近一次解析错误的行号(0=无错误)""" + return _g_parse_err_line + + +def get_parse_err_col() -> t.CInt: + """获取最近一次解析错误的列号(0=无错误)""" + return _g_parse_err_col + + +def get_parse_err_msg() -> str: + """获取最近一次解析错误的错误消息(仿 Python SyntaxError 消息文本)""" + return _g_parse_err_msg + + +def _cur_str(ps: Parser | t.CPtr) -> str: + if ps.cur is None: return None + return ps.cur.str_val + + +def _cur_lineno(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.lineno + + +def _cur_col(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.col_offset + + +def _skip_nl(ps: Parser | t.CPtr): + """Skip TokenType.Nl token""" + while ps.cur is not None and ps.cur.type == TokenType.Nl: + ps.cur = ps.cur.next + + +def _skip_nls_and_newlines(ps: Parser | t.CPtr): + """Skip TokenType.Nl and TokenType.NewLine (used for line continuation)""" + while ps.cur is not None: + if ps.cur.type == TokenType.Nl or ps.cur.type == TokenType.NewLine: + ps.cur = ps.cur.next + else: + break + + +def _expect_type(ps: Parser | t.CPtr, ttype: t.CInt) -> t.CInt: + """Expect the current token to be of the specified type, advance and return 1, otherwise return 0""" + if _cur_type(ps) == ttype: + _advance(ps) + return 1 + _record_parse_err(ps) + ps.error_count += 1 + return 0 + + +def _expect_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: + """Expecting the current one to be some operator""" + if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id: + _advance(ps) + return 1 + _record_parse_err(ps) + ps.error_count += 1 + return 0 + + +def _match_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: + """Check but not consume the current token""" + if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id: + return 1 + return 0 + + +def _accept_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: + """If match, consume and return 1""" + if _match_op(ps, op_id): + _advance(ps) + return 1 + return 0 + + +# ============================================================ +# Constant Construction Helper (New API: Constant directly accepts lineno/col) +# ============================================================ + +def _new_const_int(pool: memhub.MemManager | t.CPtr, val: t.CInt64T, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + return Constant(pool, CONST_INT, val, 0.0, None, lineno, col) + + +def _new_const_float(pool: memhub.MemManager | t.CPtr, val: t.CDouble, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + global _g_dbg_pts, _g_dbg_vals, _g_dbg_cnt + new_c: Constant | t.CPtr = Constant(pool, CONST_FLOAT, 0, val, None, lineno, col) + # 把数字文本存到 str_val(stdlib 分配,绕开 pool 对 float_val 字段的覆写) + # REG-SRC 用 string.atof(str_val) 恢复原始值 + lit_txt: str = stdlib.malloc(64) + if lit_txt is not None: + stdio.snprintf(lit_txt, 64, "%.17g", val) + new_c.str_val = lit_txt + # 记录浮点节点 ptr→val 到 stdlib 表(构造时值正确,供 REG-SRC 查表绕开 pool 覆写) + # 表满时重置:旧记录对应已翻译完的文件,从当前节点重新记录 + if _g_dbg_pts is None: + _g_dbg_pts = stdlib.malloc(4096 * 8) + _g_dbg_vals = stdlib.malloc(4096 * 8) + _g_dbg_cnt = 0 + elif _g_dbg_cnt >= 4096: + _g_dbg_cnt = 0 + if _g_dbg_pts is not None and _g_dbg_vals is not None: + _g_dbg_pts[_g_dbg_cnt] = t.CUInt64T(new_c) + _g_dbg_vals[_g_dbg_cnt] = val + _g_dbg_cnt += 1 + return new_c + + +# 浮点节点构造值表(stdlib 分配,避免污染 pool) +_g_dbg_pts: t.CUInt64T | t.CPtr = None +_g_dbg_vals: t.CDouble | t.CPtr = None +_g_dbg_cnt: int = 0 +# 最近一次 _dbg_lookup_lit_val 是否命中 +_g_dbg_lit_found: int = 0 + + +def _dbg_lookup_lit_val(ptr: t.CUInt64T) -> double: + """查浮点节点构造值表:返回 ptr 节点的原始构造值(未命中返回 0 并置 found=0) + + 用于绕开 pool 分配对 AST float_val 字段的覆写(构造时值正确,读取时可能被覆写)。 + """ + global _g_dbg_lit_found + _g_dbg_lit_found = 0 + if _g_dbg_pts is None or _g_dbg_vals is None: + return 0.0 + i: t.CSizeT = 0 + while i < _g_dbg_cnt: + if _g_dbg_pts[i] == ptr: + _g_dbg_lit_found = 1 + return _g_dbg_vals[i] + i += 1 + return 0.0 + + +def _dbg_lit_found() -> int: + """检查最近一次 _dbg_lookup_lit_val 是否命中""" + return _g_dbg_lit_found + + +def _new_const_str(pool: memhub.MemManager | t.CPtr, val: str, + lineno: t.CInt, col: t.CInt, + is_dquote: t.CInt = 1, + is_triple: t.CInt = 0, + is_char: t.CInt = 0) -> AST | t.CPtr: + """Create a string/character constant node + + is_dquote: 0 = single quote, non-0 = double quote (default double quote) + is_triple: non-0 = triple-quoted string + is_char: non-0 = single-character candidate (lexer has confirmed that after escaping it's exactly 1 byte, including '0') + Semantic distinctions: + - 'x' (single quote, single character, not triple-quoted) → CONST_CHAR (i8 value) + - "x" (double quote, includes 0 terminator) → CONST_STR (i8* pointer, i8 x 2) + - 'ab' (single quotes, multiple characters) → CONST_STR (i8* pointer) + - '''x''' / \"\"\"x\"\"\" (triple quotes) → CONST_STR (i8* pointer) + - '' / "" (empty string) → CONST_STR (i8* pointer) + """ + # Single quotes, non-triple quotes, single-character candidates marked by lexer → CONST_CHAR + # Mark with is_char instead of strlen(val), because '0' becomes a NUL byte after escaping, strlen would return 0 + if is_dquote == 0 and is_triple == 0 and is_char != 0: + # Single quote # Single character → CONST_CHAR, int_val stores the character's ASCII value + # val[0] is a legal value of 0 even if it's NUL + ch_val: t.CInt64T = val[0] + return Constant(pool, CONST_CHAR, ch_val, 0.0, val, lineno, col) + # Other situations → CONST_STR + return Constant(pool, CONST_STR, 0, 0.0, val, lineno, col) + + +def _new_const_bool(pool: memhub.MemManager | t.CPtr, val: t.CInt, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + return Constant(pool, CONST_BOOL, val, 0.0, None, lineno, col) + + +def _new_const_none(pool: memhub.MemManager | t.CPtr, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + return Constant(pool, CONST_NONE, 0, 0.0, None, lineno, col) + + +# ============================================================ +# ctx Helper (Recursive Fixing Store Context) +# ============================================================ + +def _set_ctx(node: AST | t.CPtr, ctx: t.CInt): + """Set ctx field of node (based on kind conversion)""" + if node is None: return + k: t.CInt = node.kind() + if k == ASTKind.Name: + nm: Name | t.CPtr = (Name | t.CPtr)(node) + nm.ctx = ctx + elif k == ASTKind.Attribute: + at: Attribute | t.CPtr = (Attribute | t.CPtr)(node) + at.ctx = ctx + elif k == ASTKind.Subscript: + sb: Subscript | t.CPtr = (Subscript | t.CPtr)(node) + sb.ctx = ctx + elif k == ASTKind.Tuple: + tp: Tuple | t.CPtr = (Tuple | t.CPtr)(node) + tp.ctx = ctx + elif k == ASTKind.List: + ls: List | t.CPtr = (List | t.CPtr)(node) + ls.ctx = ctx + elif k == ASTKind.Starred: + st: Starred | t.CPtr = (Starred | t.CPtr)(node) + st.ctx = ctx + + +def _fix_store_ctx(node: AST | t.CPtr): + """Fix ctx of store targets to be Store""" + if node is None: return + _set_ctx(node, ASTCtx.Store) + k: t.CInt = node.kind() + if k == ASTKind.Tuple or k == ASTKind.List: + tp_elts: list[AST | t.CPtr] | t.CPtr = None + if k == ASTKind.Tuple: + tp: Tuple | t.CPtr = (Tuple | t.CPtr)(node) + tp_elts = tp.elts + else: + ls: List | t.CPtr = (List | t.CPtr)(node) + tp_elts = ls.elts + if tp_elts is not None: + n: t.CSizeT = tp_elts.__len__() + i: t.CSizeT = 0 + while i < n: + cur: AST | t.CPtr = tp_elts.get(i) + _fix_store_ctx(cur) + i += 1 + elif k == ASTKind.Starred: + st2: Starred | t.CPtr = (Starred | t.CPtr)(node) + _fix_store_ctx(st2.value) + + +# ============================================================ +# Expression Parser +# ============================================================ + +def _parse_expr(ps: Parser | t.CPtr) -> AST | t.CPtr: + """expr: yield_expr | namedexpr_test""" + if _cur_kw(ps) == Keyword.Yield: + return _parse_yield(ps) + return _parse_namedexpr(ps) + + +def _parse_namedexpr(ps: Parser | t.CPtr) -> AST | t.CPtr: + """namedexpr_test: test [':=' test]""" + left: AST | t.CPtr = _parse_test(ps) + if left is None: return None + if _match_op(ps, TokOp.ColonEq): + _advance(ps) + right: AST | t.CPtr = _parse_test(ps) + node: AST | t.CPtr = NamedExpr(ps.pool, left, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + return left + + +def _parse_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """test: or_test ['if' or_test 'else' test] | lambdef""" + if _cur_kw(ps) == Keyword.Lambda: + return _parse_lambda(ps) + left: AST | t.CPtr = _parse_or_test(ps) + if left is None: return None + if _cur_kw(ps) == Keyword.If: + _advance(ps) + test: AST | t.CPtr = _parse_or_test(ps) + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + orelse: AST | t.CPtr = _parse_test(ps) + node: AST | t.CPtr = IfExp(ps.pool, test, left, orelse) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + ps.error_count += 1 + return left + return left + + +def _parse_lambda(ps: Parser | t.CPtr) -> AST | t.CPtr: + """lambdef: 'lambda' [varargslist] ':' test""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # lambda + args: AST | t.CPtr = None + if not _match_op(ps, TokOp.Colon): + args = _parse_varargslist(ps, 1) + if not _expect_op(ps, TokOp.Colon): + return None + body: AST | t.CPtr = _parse_test(ps) + node: AST | t.CPtr = Lambda(ps.pool, args, body) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_or_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """or_test: and_test ('or' and_test)*""" + left: AST | t.CPtr = _parse_and_test(ps) + if left is None: return None + # 括号内行首 or((A\n or B)):or 前的 NL 在此跳过,否则 or_test 返回后 + # 上层 _expect_op(RPar) 遇到 or 报"意外的 token 'or'" + # (CallGenMixin.vp L7918 跨模块调用检查根因;ClassGenMixin L1988 等 + # 括号内换行行首 or 同理,按解析顺序未暴露)。 + _skip_nl(ps) + if _cur_kw(ps) == Keyword.Or: + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values.append(left) + while _cur_kw(ps) == Keyword.Or: + _advance(ps) + _skip_nl(ps) # 括号内跨行: a or\n b + right: AST | t.CPtr = _parse_and_test(ps) + if right is None: break + values.append(right) + node: AST | t.CPtr = BoolOp(ps.pool, OpKind.Or, values) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + return left + + +def _parse_and_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """and_test: not_test ('and' not_test)*""" + left: AST | t.CPtr = _parse_not_test(ps) + if left is None: return None + # 括号内行首 and((A\n and B)):同 or_test 修复(or 前跳 NL) + _skip_nl(ps) + if _cur_kw(ps) == Keyword.And: + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values.append(left) + while _cur_kw(ps) == Keyword.And: + _advance(ps) + _skip_nl(ps) # 括号内跨行: a and\n b + right: AST | t.CPtr = _parse_not_test(ps) + if right is None: break + values.append(right) + node: AST | t.CPtr = BoolOp(ps.pool, OpKind.And, values) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + return left + + +def _parse_not_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """not_test: 'not' not_test | comparison""" + if _cur_kw(ps) == Keyword.Not: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + operand: AST | t.CPtr = _parse_not_test(ps) + node: AST | t.CPtr = UnaryOp(ps.pool, OpKind.Not, operand) + _set_pos(node, lineno, col, 0, 0) + return node + return _parse_comparison(ps) + + +def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: + """comparison: bitor_expr (comp_op bitor_expr)* + + Single comparison design: a < b → Compare(left=a, op=Lt, right=b) + Chained comparison a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c)]) + """ + left: AST | t.CPtr = _parse_bitor(ps) + if left is None: return None + + op_id: t.CInt = _match_comp_op(ps) + if op_id == OpKind.NoneOp: + return left + _advance_comp_op(ps) + _skip_nl(ps) # 括号内跨行: a ==\n b + right: AST | t.CPtr = _parse_bitor(ps) + # Single comparison: construct ops and comparators list + ops: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8) + ops.append(op_id) + comparators: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + comparators.append(right) + first_cmp: AST | t.CPtr = Compare(ps.pool, left, ops, comparators) + _set_pos(first_cmp, left.lineno, left.col_offset, 0, 0) + + # Check chained comparison + next_op: t.CInt = _match_comp_op(ps) + if next_op == OpKind.NoneOp: + return first_cmp + + # Single comparison with chained conditions: a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c), ...]) + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values.append(first_cmp) + cur_left: AST | t.CPtr = right + while next_op != OpKind.NoneOp: + _advance_comp_op(ps) + _skip_nl(ps) # 括号内跨行链式比较 + cur_right: AST | t.CPtr = _parse_bitor(ps) + ops2: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8) + ops2.append(next_op) + comparators2: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + comparators2.append(cur_right) + cmp: AST | t.CPtr = Compare(ps.pool, cur_left, ops2, comparators2) + _set_pos(cmp, cur_left.lineno, cur_left.col_offset, 0, 0) + values.append(cmp) + cur_left = cur_right + next_op = _match_comp_op(ps) + node: AST | t.CPtr = BoolOp(ps.pool, OpKind.And, values) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + + +def _match_comp_op(ps: Parser | t.CPtr) -> t.CInt: + """Check if the current one is a comparison operator, return OP_* or OpKind.NoneOp""" + if _cur_type(ps) == TokenType.Op: + op_id: t.CInt = _cur_op(ps) + if op_id == TokOp.EqEq: return OpKind.Eq + if op_id == TokOp.ExclaimEq: return OpKind.Ne + if op_id == TokOp.Less: return OpKind.Lt + if op_id == TokOp.LessEq: return OpKind.Le + if op_id == TokOp.Greater: return OpKind.Gt + if op_id == TokOp.GreaterEq: return OpKind.Ge + if _cur_kw(ps) == Keyword.Is: + if ps.cur.next is not None and ps.cur.next.type == TokenType.Name and ps.cur.next.kw_subtype == Keyword.Not: + return OpKind.IsNot + return OpKind.Is + if _cur_kw(ps) == Keyword.Not: + if ps.cur.next is not None and ps.cur.next.kw_subtype == Keyword.In: + return OpKind.NotIn + if _cur_kw(ps) == Keyword.In: + return OpKind.In + return OpKind.NoneOp + + +def _advance_comp_op(ps: Parser | t.CPtr): + """Consume comparison operator token""" + if _cur_type(ps) == TokenType.Op: + _advance(ps) + return + if _cur_kw(ps) == Keyword.Is: + _advance(ps) + if _cur_kw(ps) == Keyword.Not: + _advance(ps) + return + if _cur_kw(ps) == Keyword.Not: + _advance(ps) + if _cur_kw(ps) == Keyword.In: + _advance(ps) + return + if _cur_kw(ps) == Keyword.In: + _advance(ps) + + +def _parse_bitor(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_bitxor(ps) + if left is None: return None + while _match_op(ps, TokOp.VBar): + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_bitxor(ps) + node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitOr, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_bitxor(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_bitand(ps) + if left is None: return None + while _match_op(ps, TokOp.Caret): + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_bitand(ps) + node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitXor, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_bitand(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_shift(ps) + if left is None: return None + while _match_op(ps, TokOp.Amp): + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_shift(ps) + node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitAnd, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_shift(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_arith(ps) + if left is None: return None + while _match_op(ps, TokOp.LtLt) or _match_op(ps, TokOp.GtGt): + op_token: t.CInt = _cur_op(ps) + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_arith(ps) + ast_op: t.CInt = OpKind.LShift + if op_token == TokOp.GtGt: + ast_op = OpKind.RShift + node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_arith(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_term(ps) + if left is None: return None + while _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus): + op_token: t.CInt = _cur_op(ps) + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_term(ps) + ast_op: t.CInt = OpKind.Add + if op_token == TokOp.Minus: + ast_op = OpKind.Sub + node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_term(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_factor(ps) + if left is None: return None + while True: + op_token: t.CInt = 0 + if _match_op(ps, TokOp.Star): op_token = TokOp.Star + elif _match_op(ps, TokOp.Slash): op_token = TokOp.Slash + elif _match_op(ps, TokOp.DSlash): op_token = TokOp.DSlash + elif _match_op(ps, TokOp.Percent): op_token = TokOp.Percent + elif _match_op(ps, TokOp.At): op_token = TokOp.At + if op_token == 0: break + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_factor(ps) + ast_op: t.CInt = _binop_from_op(op_token) + node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_factor(ps: Parser | t.CPtr) -> AST | t.CPtr: + """factor: '+' factor | '-' factor | '~' factor | power""" + if _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus) or _match_op(ps, TokOp.Tilde): + op_token: t.CInt = _cur_op(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + operand: AST | t.CPtr = _parse_factor(ps) + ast_op: t.CInt = OpKind.UAdd + if op_token == TokOp.Minus: + ast_op = OpKind.USub + elif op_token == TokOp.Tilde: + ast_op = OpKind.Invert + node: AST | t.CPtr = UnaryOp(ps.pool, ast_op, operand) + _set_pos(node, lineno, col, 0, 0) + return node + return _parse_power(ps) + + +def _parse_power(ps: Parser | t.CPtr) -> AST | t.CPtr: + """power: await_expr ['**' factor] | atom_expr ['**' factor]""" + base: AST | t.CPtr = _parse_atom_expr(ps) + if base is None: return None + if _match_op(ps, TokOp.StarStar): + _advance(ps) + exp: AST | t.CPtr = _parse_factor(ps) + node: AST | t.CPtr = BinOp(ps.pool, base, OpKind.Pow, exp) + _set_pos(node, base.lineno, base.col_offset, 0, 0) + return node + return base + + +def _parse_atom_expr(ps: Parser | t.CPtr) -> AST | t.CPtr: + """atom_expr: ['await'] atom trailer*""" + if _cur_kw(ps) == Keyword.Await: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + inner: AST | t.CPtr = _parse_atom_expr(ps) + node: AST | t.CPtr = Await(ps.pool, inner) + _set_pos(node, lineno, col, 0, 0) + return node + base: AST | t.CPtr = _parse_atom(ps) + if base is None: return None + # trailer loop + while True: + if _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + break + attr_name: str = _cur_str(ps) + attr_lineno: t.CInt = _cur_lineno(ps) + attr_col: t.CInt = _cur_col(ps) + _advance(ps) + ctx: t.CInt = ASTCtx.Load + if _match_op(ps, TokOp.Equal): + ctx = ASTCtx.Store + elif _match_op(ps, TokOp.PlusEq) or _match_op(ps, TokOp.MinusEq): + ctx = ASTCtx.Store + base = Attribute(ps.pool, base, attr_name, ctx) + _set_pos(base, attr_lineno, attr_col, 0, 0) + elif _match_op(ps, TokOp.LPar): + base = _parse_call(ps, base) + elif _match_op(ps, TokOp.Lsqb): + base = _parse_subscript(ps, base) + else: + break + return base + + +def _parse_call(ps: Parser | t.CPtr, func: AST | t.CPtr) -> AST | t.CPtr: + """Parse function call trailer. Both args and keywords are lists.""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # ( + _skip_nls_and_newlines(ps) # Skip the line break after '(' + args: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + keywords: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + + if not _match_op(ps, TokOp.RPar): + while True: + # **expr + if _match_op(ps, TokOp.StarStar): + _advance(ps) + _skip_nls_and_newlines(ps) + val: AST | t.CPtr = _parse_expr(ps) + kw: AST | t.CPtr = KwNode(ps.pool, None, val) + _set_pos(kw, _cur_lineno(ps), _cur_col(ps), 0, 0) + keywords.append(kw) + # *expr + elif _match_op(ps, TokOp.Star): + _advance(ps) + _skip_nls_and_newlines(ps) + val = _parse_expr(ps) + star: AST | t.CPtr = Starred(ps.pool, val, ASTCtx.Load) + _set_pos(star, val.lineno, val.col_offset, 0, 0) + args.append(star) + # keyword = expr + elif _cur_type(ps) == TokenType.Name: + if ps.cur.next is not None and ps.cur.next.type == TokenType.Op and ps.cur.next.op_subtype == TokOp.Equal: + kw_name: str = _cur_str(ps) + kw_lineno: t.CInt = _cur_lineno(ps) + kw_col: t.CInt = _cur_col(ps) + _advance(ps) # name + _advance(ps) # = + _skip_nls_and_newlines(ps) + val = _parse_expr(ps) + kw = KwNode(ps.pool, kw_name, val) + _set_pos(kw, kw_lineno, kw_col, 0, 0) + keywords.append(kw) + else: + val = _parse_expr(ps) + args.append(val) + else: + val = _parse_expr(ps) + args.append(val) + _skip_nls_and_newlines(ps) # Skip the line break after the parameter + if not _accept_op(ps, TokOp.Comma): + break + _skip_nls_and_newlines(ps) # Skip the line break after the comma + _skip_nls_and_newlines(ps) # Skip the line break before ')' + _expect_op(ps, TokOp.RPar) + node: AST | t.CPtr = Call(ps.pool, func, args, keywords) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_subscript(ps: Parser | t.CPtr, value: AST | t.CPtr) -> AST | t.CPtr: + """Parse subscript trailer.""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # [ + _skip_nl(ps) + slice_node: AST | t.CPtr = _parse_slice(ps) + _expect_op(ps, TokOp.Rsqb) + ctx: t.CInt = ASTCtx.Load + if _match_op(ps, TokOp.Equal): + ctx = ASTCtx.Store + node: AST | t.CPtr = Subscript(ps.pool, value, slice_node, ctx) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_slice(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse slice: [expr] ':' [expr] [':' [expr]] | expr | expr, expr, ...""" + lower: AST | t.CPtr = None + if not _match_op(ps, TokOp.Colon): + lower = _parse_expr(ps) + + # Check if there’s a comma (tuple syntax: a[x, y, ...]) + if _match_op(ps, TokOp.Comma): + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if lower is not None: + elts.append(lower) + while _accept_op(ps, TokOp.Comma): + if _match_op(ps, TokOp.Rsqb): + break # Trailing comma + elem: AST | t.CPtr = _parse_expr(ps) + if elem is not None: + elts.append(elem) + lineno: t.CInt = 0 + if lower is not None: + lineno = lower.lineno + node: AST | t.CPtr = Tuple(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, 0, 0, 0) + return node + + if _match_op(ps, TokOp.Colon): + _advance(ps) + upper: AST | t.CPtr = None + if not _match_op(ps, TokOp.Colon) and not _match_op(ps, TokOp.Rsqb): + upper = _parse_expr(ps) + step: AST | t.CPtr = None + if _accept_op(ps, TokOp.Colon): + if not _match_op(ps, TokOp.Rsqb): + step = _parse_expr(ps) + lineno: t.CInt = 0 + if lower is not None: + lineno = lower.lineno + elif upper is not None: + lineno = upper.lineno + else: + lineno = _cur_lineno(ps) + node: AST | t.CPtr = Slice(ps.pool, lower, upper, step) + _set_pos(node, lineno, 0, 0, 0) + return node + return lower + + +def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr: + """atom: the smallest unit of expression""" + ttype: t.CInt = _cur_type(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + + if ttype == TokenType.Name: + kw: t.CInt = _cur_kw(ps) + if kw == Keyword.True_: + _advance(ps) + return _new_const_bool(ps.pool, 1, lineno, col) + if kw == Keyword.False_: + _advance(ps) + return _new_const_bool(ps.pool, 0, lineno, col) + if kw == Keyword.None_: + _advance(ps) + return _new_const_none(ps.pool, lineno, col) + name_str: str = _cur_str(ps) + _advance(ps) + node: AST | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + + if ttype == TokenType.Number: + tok: Token | t.CPtr = ps.cur + _advance(ps) + if tok.is_float: + return _new_const_float(ps.pool, tok.float_val, lineno, col) + return _new_const_int(ps.pool, tok.int_val, lineno, col) + + if ttype == TokenType.String: + sval: str = _cur_str(ps) + is_fstr: t.CInt = ps.cur.kw_subtype & 4 + is_triple: t.CInt = ps.cur.kw_subtype & 8 + is_dquote: t.CInt = ps.cur.kw_subtype & 16 + is_char: t.CInt = ps.cur.kw_subtype & 32 + _advance(ps) + node: AST | t.CPtr + if is_fstr: + node = _parse_fstring(ps, sval, lineno, col) + else: + node = _new_const_str(ps.pool, sval, lineno, col, is_dquote, is_triple, is_char) + # Python 相邻字符串字面量隐式拼接:"a" "b" → "ab" + # Nl 是括号内换行 token(允许括号内跨行拼接);语句级换行是 NewLine,不跳过 + while True: + _skip_nl(ps) + if _cur_type(ps) != TokenType.String: + break + n_sval: str = _cur_str(ps) + n_fstr: t.CInt = ps.cur.kw_subtype & 4 + n_triple: t.CInt = ps.cur.kw_subtype & 8 + n_dquote: t.CInt = ps.cur.kw_subtype & 16 + n_char: t.CInt = ps.cur.kw_subtype & 32 + _advance(ps) + n_node: AST | t.CPtr + if n_fstr: + n_node = _parse_fstring(ps, n_sval, lineno, col) + else: + n_node = _new_const_str(ps.pool, n_sval, lineno, col, n_dquote, n_triple, n_char) + node = _concat_str_nodes(ps.pool, node, n_node) + return node + + if _match_op(ps, TokOp.Ellipsis): + _advance(ps) + return _new_const_none(ps.pool, lineno, col) + + if _match_op(ps, TokOp.LPar): + return _parse_paren(ps) + if _match_op(ps, TokOp.Lsqb): + return _parse_list(ps) + if _match_op(ps, TokOp.LBrace): + return _parse_brace(ps) + + ps.error_count += 1 + return None + + +def _parse_paren(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parenthesis expressions: () | (expr) | (expr,) | (expr, ...) | (yield)""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # ( + _skip_nl(ps) # Skip the line break after '(' (multi-line tuple) + if _match_op(ps, TokOp.RPar): + _advance(ps) + # Empty tuple + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = Tuple(ps.pool, empty, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + # yield + if _cur_kw(ps) == Keyword.Yield: + y: AST | t.CPtr = _parse_yield(ps) + _expect_op(ps, TokOp.RPar) + return y + first: AST | t.CPtr = _parse_expr(ps) + if _match_op(ps, TokOp.Comma): + # Tuple + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.RPar): + break + e: AST | t.CPtr = _parse_expr(ps) + elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾(多行元组) + _expect_op(ps, TokOp.RPar) + node = Tuple(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + _skip_nl(ps) # (expr\n) 单表达式括号跨行收尾 + _expect_op(ps, TokOp.RPar) + # Check for generator expression + if _cur_kw(ps) == Keyword.For: + return _parse_comprehension(ps, first, ASTKind.GeneratorExp, lineno, col) + return first + + +def _parse_list(ps: Parser | t.CPtr) -> AST | t.CPtr: + """List expressions: [] | [expr_list] | [expr_list comp_for]""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # [ + _skip_nl(ps) # Skip the line break after '[' (multi-line list) + if _match_op(ps, TokOp.Rsqb): + _advance(ps) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = List(ps.pool, empty, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + first: AST | t.CPtr = _parse_expr(ps) + if _cur_kw(ps) == Keyword.For: + node = _parse_comprehension(ps, first, ASTKind.ListComp, lineno, col) + _expect_op(ps, TokOp.Rsqb) + return node + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.Rsqb): + break + e: AST | t.CPtr = _parse_expr(ps) + elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾(base64.vp 多行列表) + _expect_op(ps, TokOp.Rsqb) + node = List(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_brace(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Brace expressions: {} | {set_items} | {dict_items} | {comp_for}""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # { + _skip_nl(ps) # Skip the line break after '{' (multi-line dict) + if _match_op(ps, TokOp.RBrace): + _advance(ps) + empty_k: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + empty_v: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = Dict(ps.pool, empty_k, empty_v) + _set_pos(node, lineno, col, 0, 0) + return node + first: AST | t.CPtr = _parse_expr(ps) + # dict: key: value + if _match_op(ps, TokOp.Colon): + _advance(ps) + val: AST | t.CPtr = _parse_expr(ps) + if _cur_kw(ps) == Keyword.For: + # dict comprehension + gens: list[AST | t.CPtr] | t.CPtr = _parse_comp_for(ps) + node = DictComp(ps.pool, first, val, gens) + _set_pos(node, lineno, col, 0, 0) + _expect_op(ps, TokOp.RBrace) + return node + keys: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + keys.append(first) + values.append(val) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.RBrace): + break + k: AST | t.CPtr = _parse_expr(ps) + _expect_op(ps, TokOp.Colon) + v: AST | t.CPtr = _parse_expr(ps) + keys.append(k) + values.append(v) + _skip_nl(ps) # 末元素无尾逗号时收尾 + _expect_op(ps, TokOp.RBrace) + node = Dict(ps.pool, keys, values) + _set_pos(node, lineno, col, 0, 0) + return node + # set + if _cur_kw(ps) == Keyword.For: + node = _parse_comprehension(ps, first, ASTKind.SetComp, lineno, col) + _expect_op(ps, TokOp.RBrace) + return node + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) # 括号内跨行集合字面量 + if _match_op(ps, TokOp.RBrace): + break + e: AST | t.CPtr = _parse_expr(ps) + elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾 + _expect_op(ps, TokOp.RBrace) + node = Set(ps.pool, elts) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# f-string parsing +# ============================================================ + +def _parse_sub_expr(ps: Parser | t.CPtr, src: str) -> AST | t.CPtr: + """Create a sub-lexer and parser to parse expressions (used for {expr} inside f-strings)""" + pool: memhub.MemManager | t.CPtr = ps.pool + lx: Lexer | t.CPtr = new_lexer(pool) + if lx is None: return None + _lexer_init(lx, src, pool) + tokens: Token | t.CPtr = tokenize(lx) + if tokens is None: return None + sub_ps: Parser | t.CPtr = new_parser(pool) + if sub_ps is None: return None + _parser_init(sub_ps, tokens, pool) + return _parse_test(sub_ps) + + +def _append_str_value(pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr, + node: AST | t.CPtr): + """将字符串节点展开加入 values(JoinedStr 展开其 values,其余直接追加)""" + if node is None: + return + if node.kind() == ASTKind.JoinedStr: + js_val: JoinedStr | t.CPtr = (JoinedStr | t.CPtr)(node) + if js_val.values is not None: + n_v: t.CSizeT = js_val.values.__len__() + i_v: t.CSizeT + for i_v in range(n_v): + values.append(js_val.values.get(i_v)) + else: + values.append(node) + + +def _concat_str_nodes(pool: memhub.MemManager | t.CPtr, + a: AST | t.CPtr, b: AST | t.CPtr) -> AST | t.CPtr: + """合并相邻字符串字面量节点(Python 隐式拼接 "a" "b" → "ab") + + 纯常量字符串直接拼接文本;涉及 f-string(JoinedStr/FormattedValue)时 + 合并到 JoinedStr 的 values 列表。 + """ + if a is None: + return b + if b is None: + return a + # 两个都是常量字符串 → 直接拼接文本 + if a.kind() == ASTKind.Constant and b.kind() == ASTKind.Constant: + ca_c: Constant | t.CPtr = (Constant | t.CPtr)(a) + cb_c: Constant | t.CPtr = (Constant | t.CPtr)(b) + if ca_c.const_kind == CONST_STR and cb_c.const_kind == CONST_STR \ + and ca_c.str_val is not None and cb_c.str_val is not None: + la_c: t.CSizeT = string.strlen(ca_c.str_val) + lb_c: t.CSizeT = string.strlen(cb_c.str_val) + buf_c: str = pool.alloc(la_c + lb_c + 1) + if buf_c is not None: + string.memcpy(buf_c, ca_c.str_val, la_c) + string.memcpy(buf_c + la_c, cb_c.str_val, lb_c + 1) + return _new_const_str(pool, buf_c, a.lineno, a.col_offset, 0, 0, 0) + # 涉及 f-string → 合并到 JoinedStr + values_c: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](pool, 8) + _append_str_value(pool, values_c, a) + _append_str_value(pool, values_c, b) + if values_c.__len__() == 1: + return values_c.get(0) + node_c: AST | t.CPtr = JoinedStr(pool, values_c) + _set_pos(node_c, a.lineno, a.col_offset, 0, 0) + return node_c + + +def _parse_fstring(ps: Parser | t.CPtr, content: str, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """Parse f-string content, building JoinedStr or FormattedValue nodes""" + pool: memhub.MemManager | t.CPtr = ps.pool + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](pool, 8) + i: t.CSizeT = 0 + content_len: t.CSizeT = string.strlen(content) + # Literal text buffer for f-string content + lit_buf: str = pool.alloc(content_len + 1) + if lit_buf is None: return None + lit_pos: t.CSizeT = 0 + + while i < content_len: + ch: t.CChar = content[i] + if ch == '{': + # {{ → Literal { + if i + 1 < content_len and content[i + 1] == '{': + lit_buf[lit_pos] = '{' + lit_pos += 1 + i += 2 + continue + # Refresh literal buffer + if lit_pos > 0: + lit_buf[lit_pos] = '\0' + lit_node: AST | t.CPtr = _new_const_str(pool, lit_buf, lineno, col) + values.append(lit_node) + lit_buf = pool.alloc(content_len + 1) + if lit_buf is None: break + lit_pos = 0 + # Find matching closing '}' while tracking nested '{}' and string literals inside the f-string + j: t.CSizeT = i + 1 + depth: t.CInt = 1 + conv_pos: t.CSizeT = 0 + fmt_pos: t.CSizeT = 0 + while j < content_len and depth > 0: + c: t.CChar = content[j] + if c == '{': + depth += 1 + elif c == '}': + depth -= 1 + if depth == 0: + break + elif depth == 1: + if c == '!' and conv_pos == 0 and fmt_pos == 0: + if j + 1 < content_len: + nc: t.CChar = content[j + 1] + if nc == 's' or nc == 'r' or nc == 'a': + if j + 2 < content_len: + after: t.CChar = content[j + 2] + if after == ':' or after == '}': + conv_pos = j + elif j + 2 == content_len: + conv_pos = j + elif c == ':' and fmt_pos == 0: + fmt_pos = j + j += 1 + if depth != 0: + ps.error_count += 1 + break + # Extract expression text + expr_end: t.CSizeT = j + if conv_pos > 0: + expr_end = conv_pos + elif fmt_pos > 0: + expr_end = fmt_pos + expr_len: t.CSizeT = expr_end - i - 1 + if expr_len == 0: + ps.error_count += 1 + i = j + 1 + continue + expr_buf: str = pool.alloc(expr_len + 1) + if expr_buf is None: break + string.memcpy(expr_buf, content + i + 1, expr_len) + expr_buf[expr_len] = '\0' + # Parse expression text + expr_node: AST | t.CPtr = _parse_sub_expr(ps, expr_buf) + # Conversion specifier + conversion: t.CInt = -1 + if conv_pos > 0: + conv_char: t.CChar = content[conv_pos + 1] + if conv_char == 's': + conversion = 115 + elif conv_char == 'r': + conversion = 114 + elif conv_char == 'a': + conversion = 97 + # Format specifier + format_spec: AST | t.CPtr = None + if fmt_pos > 0: + spec_len: t.CSizeT = j - fmt_pos - 1 + if spec_len > 0: + spec_buf: str = pool.alloc(spec_len + 1) + if spec_buf is not None: + string.memcpy(spec_buf, content + fmt_pos + 1, spec_len) + spec_buf[spec_len] = '\0' + format_spec = _new_const_str(pool, spec_buf, lineno, col) + fv: AST | t.CPtr = FormattedValue(pool, expr_node, conversion, format_spec) + _set_pos(fv, lineno, col, 0, 0) + values.append(fv) + i = j + 1 + elif ch == '}': + if i + 1 < content_len and content[i + 1] == '}': + lit_buf[lit_pos] = '}' + lit_pos += 1 + i += 2 + else: + ps.error_count += 1 + i += 1 + else: + lit_buf[lit_pos] = ch + lit_pos += 1 + i += 1 + + # Refresh remaining literal buffer + if lit_pos > 0: + lit_buf[lit_pos] = '\0' + lit_node2: AST | t.CPtr = _new_const_str(pool, lit_buf, lineno, col) + values.append(lit_node2) + + # If no content, return empty string + if values.__len__() == 0: + return _new_const_str(pool, "", lineno, col) + # If only one FormattedValue and no literal, return FormattedValue + if values.__len__() == 1: + first: AST | t.CPtr = values.get(0) + if first.kind() == ASTKind.FormattedValue: + return first + node: AST | t.CPtr = JoinedStr(pool, values) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_comprehension(ps: Parser | t.CPtr, elt: AST | t.CPtr, + vtype: t.CInt, lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """General comprehension: elt comp_for""" + gens: list[AST | t.CPtr] | t.CPtr = _parse_comp_for(ps) + node: AST | t.CPtr = None + if vtype == ASTKind.ListComp: + node = ListComp(ps.pool, elt, gens) + elif vtype == ASTKind.SetComp: + node = SetComp(ps.pool, elt, gens) + else: + node = GeneratorExp(ps.pool, elt, gens) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_comp_for(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """comp_for: ['async'] 'for' exprlist 'in' or_test [comp_if] (comp_for)* + Returns generators list。""" + gens: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while True: + is_async: t.CInt = 0 + if _cur_kw(ps) == Keyword.Async: + is_async = 1 + _advance(ps) + if _cur_kw(ps) != Keyword.For: + break + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + target: AST | t.CPtr = _parse_target_list(ps) + if _cur_kw(ps) != Keyword.In: + ps.error_count += 1 + break + _advance(ps) + iter_: AST | t.CPtr = _parse_or_test(ps) + # Collect ifs to list + ifs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while _cur_kw(ps) == Keyword.If: + _advance(ps) + cond: AST | t.CPtr = _parse_or_test(ps) + ifs.append(cond) + comp: AST | t.CPtr = Comprehension(ps.pool, target, iter_, ifs, is_async) + _set_pos(comp, lineno, col, 0, 0) + gens.append(comp) + return gens + + +def _parse_target_list(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse assignment target list (comma-separated)""" + first: AST | t.CPtr = _parse_target(ps) + if _match_op(ps, TokOp.Comma): + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + if _cur_kw(ps) == Keyword.In: + break + e: AST | t.CPtr = _parse_target(ps) + elts.append(e) + node: AST | t.CPtr = Tuple(ps.pool, elts, ASTCtx.Store) + _set_pos(node, first.lineno, first.col_offset, 0, 0) + return node + return first + + +def _parse_target(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse assignment target""" + if _match_op(ps, TokOp.Star): + _advance(ps) + inner: AST | t.CPtr = _parse_atom_expr(ps) + node: AST | t.CPtr = Starred(ps.pool, inner, ASTCtx.Store) + _set_pos(node, inner.lineno, inner.col_offset, 0, 0) + return node + if _match_op(ps, TokOp.LPar): + _advance(ps) + _skip_nl(ps) + t_: AST | t.CPtr = _parse_target_list(ps) + _skip_nl(ps) + _expect_op(ps, TokOp.RPar) + return t_ + if _match_op(ps, TokOp.Lsqb): + _advance(ps) + _skip_nl(ps) + first: AST | t.CPtr = _parse_target(ps) + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.Rsqb): + break + e: AST | t.CPtr = _parse_target(ps) + elts.append(e) + _expect_op(ps, TokOp.Rsqb) + node = List(ps.pool, elts, ASTCtx.Store) + _set_pos(node, first.lineno, first.col_offset, 0, 0) + return node + # Normal atom_expr, ctx=Store + node = _parse_atom_expr(ps) + if node is not None: + _set_ctx(node, ASTCtx.Store) + return node + + +def _parse_yield(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # yield + if _cur_kw(ps) == Keyword.From: + _advance(ps) + val: AST | t.CPtr = _parse_expr(ps) + node: AST | t.CPtr = YieldFrom(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + val2: AST | t.CPtr = None + if not _match_op(ps, TokOp.RPar) and _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + if _cur_type(ps) == TokenType.Op and (_cur_op(ps) == TokOp.Comma or _cur_op(ps) == TokOp.Rsqb): + pass + else: + val2 = _parse_test(ps) + node = Yield(ps.pool, val2) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_varargslist(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr: + """Parse function parameter list + New API: args/defaults/kw_defaults are lists, vararg/kwarg are fields.""" + args: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + vararg: AST | t.CPtr = None + kwarg: AST | t.CPtr = None + defaults: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + kw_defaults: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + + while True: + _skip_nl(ps) + if _match_op(ps, TokOp.RPar): + break + # *args 或 * (kwonly separated) + if _match_op(ps, TokOp.Star): + _advance(ps) + _skip_nl(ps) + if _cur_type(ps) == TokenType.Name: + vararg = _parse_arg_def(ps, is_lambda) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + continue + # **kwargs + if _match_op(ps, TokOp.StarStar): + _advance(ps) + _skip_nl(ps) + kwarg = _parse_arg_def(ps, is_lambda) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + continue + # / Delimiter (posonly end)— New API: posonly/regular are not distinguished + if _match_op(ps, TokOp.Slash): + _advance(ps) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + continue + # Normal parameter + a: AST | t.CPtr = _parse_arg_def(ps, is_lambda) + if a is None: break + args.append(a) + if _match_op(ps, TokOp.Equal): + _advance(ps) + d: AST | t.CPtr = _parse_test(ps) + defaults.append(d) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + return Arguments(ps.pool, args, vararg, kwarg, defaults, kw_defaults) + + +def _parse_arg_def(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr: + """arg: TokenType.Name [':' annotation]""" + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name_str: str = _cur_str(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + annotation: AST | t.CPtr = None + if is_lambda == 0: + if _accept_op(ps, TokOp.Colon): + annotation = _parse_test(ps) + result: AST | t.CPtr = Arg(ps.pool, name_str, annotation) + _set_pos(result, lineno, col, 0, 0) + return result + + +# ============================================================ +# Statement parsing (Design: directly append to parent, do not return a list) +# ============================================================ + +def _parse_suite_into_children(ps: Parser | t.CPtr, parent: AST | t.CPtr): + """Parse statement suite, directly append to parent's children. + suite: TokenType.NewLine TokenType.Indent stmt+ TokenType.Dedent | simple_stmt""" + _skip_nl(ps) + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + _skip_nl(ps) + if _cur_type(ps) != TokenType.Indent: + ps.error_count += 1 + return + _advance(ps) + sidx: t.CInt = 0 + while _cur_type(ps) != TokenType.Dedent and _cur_type(ps) != TokenType.EndMarker: + sidx += 1 + # Decorator (class body methods can have decorators) + if _match_op(ps, TokOp.At): + ps.pending_decorators = _parse_decorators(ps) + before_cur: Token | t.CPtr = ps.cur + _parse_statement_into(ps, parent) + # Defensive: if parse did not advance token, force advance to avoid infinite loop + if ps.cur is before_cur: + ps.error_count += 1 + _advance(ps) + _skip_nl(ps) + _expect_type(ps, TokenType.Dedent) + return + # Single-line suite + _parse_simple_stmt_into(ps, parent) + + +def _parse_statement_into(ps: Parser | t.CPtr, parent: AST | t.CPtr): + """Parse statement (compound or simple), append to the parent.""" + ttype: t.CInt = _cur_type(ps) + kw: t.CInt = _cur_kw(ps) + if ttype == TokenType.Name: + if kw == Keyword.If or kw == Keyword.While or kw == Keyword.For or kw == Keyword.Try: + stmt: AST | t.CPtr = _parse_compound(ps) + if stmt is not None: + parent.append(stmt) + return + if kw == Keyword.With or _is_funcdef_kw(ps, kw) != 0 or kw == Keyword.Class: + stmt = _parse_compound(ps) + if stmt is not None: + parent.append(stmt) + return + if (kw == Keyword.Match and _is_match_stmt(ps) != 0) or kw == Keyword.Async: + stmt = _parse_compound(ps) + if stmt is not None: + parent.append(stmt) + return + _parse_simple_stmt_into(ps, parent) + + +def _parse_simple_stmt_into(ps: Parser | t.CPtr, parent: AST | t.CPtr): + """simple_stmt: small_stmt (';' small_stmt)* [';'] TokenType.NewLine""" + first: AST | t.CPtr = _parse_small_stmt(ps) + if first is not None: + parent.append(first) + while _accept_op(ps, TokOp.Semi): + if _cur_type(ps) == TokenType.NewLine or _cur_type(ps) == TokenType.EndMarker: + break + s: AST | t.CPtr = _parse_small_stmt(ps) + if s is None: break + parent.append(s) + # 先跳过 Nl(括号内换行,如多行函数调用参数间的换行,属合法 token) + _skip_nl(ps) + # 语句结束检查:simple_stmt 必须以换行/文件尾结束。 + # 残留 token(如相邻表达式 `func12344444 avg3(...)` 被静默拆成多条语句、 + # `def` 缺失的关键字函数定义残留)是语法错误(fail-fast),禁止静默, + # 并仿 Python 报告错误位置(SyntaxError at line/col)。 + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + _record_parse_err(ps) + err_str: str = _cur_str(ps) + if err_str is None: + err_str = "(none)" + # 定位:从链表头找 cur,记录前一个 token 与下一个 token 的上下文 + prev_tok: Token | t.CPtr = None + walk_tok: Token | t.CPtr = ps.tokens + while walk_tok is not None and walk_tok is not ps.cur: + prev_tok = walk_tok + walk_tok = walk_tok.next + pv_str: str = "(head)" + pv_line: t.CInt = 0 + pv_col: t.CInt = 0 + if prev_tok is not None: + pv_str = prev_tok.str_val + pv_line = prev_tok.lineno + pv_col = prev_tok.col_offset + nxt_tok: Token | t.CPtr = ps.cur.next + nxt_str: str = "(none)" + nxt_line: t.CInt = 0 + nxt_col: t.CInt = 0 + if nxt_tok is not None: + nxt_str = nxt_tok.str_val + nxt_line = nxt_tok.lineno + nxt_col = nxt_tok.col_offset + stdio.printf("[AST] SyntaxError: line %d col %d (end %d %d), 意外的 token '%s' (type=%d) | prev='%s' (line %d col %d) | next='%s' (line %d col %d)\n", + _g_parse_err_line, _g_parse_err_col, ps.cur.end_lineno, ps.cur.end_col_offset, + err_str, _cur_type(ps), + pv_str, pv_line, pv_col, + nxt_str, nxt_line, nxt_col) + ps.error_count += 1 + return + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + + +def _parse_small_stmt(ps: Parser | t.CPtr) -> AST | t.CPtr: + """small_stmt: various simple statements""" + kw: t.CInt = _cur_kw(ps) + if kw == Keyword.Pass: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + node: AST | t.CPtr = Pass(ps.pool) + _set_pos(node, lineno, col, 0, 0) + return node + if kw == Keyword.Break: + lineno = _cur_lineno(ps) + col = _cur_col(ps) + _advance(ps) + node = Break(ps.pool) + _set_pos(node, lineno, col, 0, 0) + return node + if kw == Keyword.Continue: + lineno = _cur_lineno(ps) + col = _cur_col(ps) + _advance(ps) + node = Continue(ps.pool) + _set_pos(node, lineno, col, 0, 0) + return node + if kw == Keyword.Return: + return _parse_return(ps) + if kw == Keyword.Raise: + return _parse_raise(ps) + if kw == Keyword.Global: + return _parse_global(ps) + if kw == Keyword.Nonlocal: + return _parse_nonlocal(ps) + if kw == Keyword.Import: + return _parse_import(ps) + if kw == Keyword.From: + return _parse_from_import(ps) + if kw == Keyword.Del: + return _parse_del(ps) + if kw == Keyword.Assert: + return _parse_assert(ps) + if kw == Keyword.Yield: + return _parse_expr_stmt(ps, _parse_yield(ps)) + # Expression statement / assignment / augassign / annassign + return _parse_expr_stmt(ps, None) + + +def _maybe_tuple(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr: + """If there is a comma after first, collect the comma-separated expressions into a Tuple.""" + if first is None: return None + if not _match_op(ps, TokOp.Comma): + return first + lineno: t.CInt = first.lineno + col: t.CInt = first.col_offset + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + _accept_op(ps, TokOp.Comma) + while True: + tt: t.CInt = _cur_type(ps) + if tt == TokenType.NewLine or tt == TokenType.EndMarker: + break + if tt == TokenType.Op: + op: t.CInt = _cur_op(ps) + if op == TokOp.Equal or op == TokOp.Semi: + break + e: AST | t.CPtr = _parse_expr(ps) + if e is None: break + elts.append(e) + if not _accept_op(ps, TokOp.Comma): + break + node: AST | t.CPtr = Tuple(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_testlist(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse a comma-separated list of expressions, if there’s more than one, form a tuple.""" + first: AST | t.CPtr = _parse_expr(ps) + return _maybe_tuple(ps, first) + + +def _parse_expr_stmt(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr: + """Expression statement, handle assignment/augassign/annassign""" + if first is None: + first = _parse_testlist(ps) + else: + first = _maybe_tuple(ps, first) + if first is None: + return None + lineno: t.CInt = first.lineno + col: t.CInt = first.col_offset + # Assignment + if _match_op(ps, TokOp.Equal): + targets: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + targets.append(first) + _fix_store_ctx(first) + value: AST | t.CPtr = None + accept_result: t.CInt = _accept_op(ps, TokOp.Equal) + while accept_result: + v: AST | t.CPtr = _parse_testlist(ps) + if v is None: break + if value is not None: + targets.append(value) + _fix_store_ctx(value) + value = v + accept_result = _accept_op(ps, TokOp.Equal) + node: AST | t.CPtr = Assign(ps.pool, targets, value) + _set_pos(node, lineno, col, 0, 0) + return node + # augassign + if _cur_type(ps) == TokenType.Op: + op_id: t.CInt = _cur_op(ps) + aug_op: t.CInt = _augop_from_op(op_id) + if aug_op != OpKind.NoneOp: + _advance(ps) + value2: AST | t.CPtr = _parse_testlist(ps) + _fix_store_ctx(first) + node2: AST | t.CPtr = AugAssign(ps.pool, first, aug_op, value2) + _set_pos(node2, lineno, col, 0, 0) + return node2 + # annassign: target ':' annotation [= value] + if _match_op(ps, TokOp.Colon): + _advance(ps) + annotation: AST | t.CPtr = _parse_test(ps) + value3: AST | t.CPtr = None + if _accept_op(ps, TokOp.Equal): + value3 = _parse_testlist(ps) + if ps.pool is None: + return None + _fix_store_ctx(first) + if ps.pool is None: + return None + node3: AST | t.CPtr = AnnAssign(ps.pool, first, annotation, value3, 1) + _set_pos(node3, lineno, col, 0, 0) + return node3 + # Expression statement + node4: AST | t.CPtr = Expr(ps.pool, first) + _set_pos(node4, lineno, col, 0, 0) + return node4 + + +def _parse_return(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + val: AST | t.CPtr = None + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker and _cur_type(ps) != TokenType.Op: + val = _parse_testlist(ps) + elif _cur_type(ps) == TokenType.Op and _cur_op(ps) != TokOp.Semi: + val = _parse_testlist(ps) + node: AST | t.CPtr = Return(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_raise(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + exc: AST | t.CPtr = None + cause: AST | t.CPtr = None + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + exc = _parse_test(ps) + if _cur_kw(ps) == Keyword.From: + _advance(ps) + cause = _parse_test(ps) + node: AST | t.CPtr = Raise(ps.pool, exc, cause) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_global(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if _cur_type(ps) == TokenType.Name: + n: AST | t.CPtr = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + while _accept_op(ps, TokOp.Comma): + if _cur_type(ps) != TokenType.Name: break + n = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + node: AST | t.CPtr = Global(ps.pool, names) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_nonlocal(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if _cur_type(ps) == TokenType.Name: + n: AST | t.CPtr = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + while _accept_op(ps, TokOp.Comma): + if _cur_type(ps) != TokenType.Name: break + n = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + node: AST | t.CPtr = Nonlocal(ps.pool, names) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_import(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + names: list[AST | t.CPtr] | t.CPtr = _parse_alias_list(ps) + node: AST | t.CPtr = Import(ps.pool, names) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + # Parse module (possibly with dots) + level: t.CInt = 0 + while _match_op(ps, TokOp.Dot): + level += 1 + _advance(ps) + while _match_op(ps, TokOp.Ellipsis): + level += 3 + _advance(ps) + module_name: str = None + # The token type for keywords (like import) is also Name, so they must be excluded using kw_subtype, + # otherwise the `import` in `from . import` would be mistakenly treated as a module_name. + # Note: only `import` itself should be excluded. Module names can be keywords (like in `from .match import ...`, + # where match is a Viper match statement keyword), requiring NotKeyword would cause + # `from .match import` to fail parsing and the dependency scan would miss that module. + if _cur_type(ps) == TokenType.Name and _cur_kw(ps) != Keyword.Import: + module_name = _cur_str(ps) + _advance(ps) + while _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword: + next_name: str = _cur_str(ps) + mlen: t.CInt = string.strlen(module_name) + nlen: t.CInt = string.strlen(next_name) + new_mod: str = ps.pool.alloc(mlen + 1 + nlen + 1) + if new_mod is not None: + string.strcpy(new_mod, module_name) + new_mod[mlen] = '.' + string.strcpy(new_mod + mlen + 1, next_name) + module_name = new_mod + _advance(ps) + if _cur_kw(ps) != Keyword.Import: + ps.error_count += 1 + return None + _advance(ps) + _skip_nl(ps) + # import * + if _match_op(ps, TokOp.Star): + _advance(ps) + star_alias: AST | t.CPtr = Alias(ps.pool, "*", None) + _set_pos(star_alias, lineno, col, 0, 0) + star_names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + star_names.append(star_alias) + node: AST | t.CPtr = ImportFrom(ps.pool, module_name, star_names, level) + _set_pos(node, lineno, col, 0, 0) + return node + # ( names ) or names + if _match_op(ps, TokOp.LPar): + _advance(ps) + _skip_nl(ps) + names: list[AST | t.CPtr] | t.CPtr = _parse_alias_list(ps) + _skip_nl(ps) + _expect_op(ps, TokOp.RPar) + else: + names = _parse_alias_list(ps) + node: AST | t.CPtr = ImportFrom(ps.pool, module_name, names, level) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_alias_list(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """Parse alias list.""" + names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while True: + if _cur_type(ps) != TokenType.Name: + break + name_str: str = _cur_str(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + # dotted name + while _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) == TokenType.Name: + next_n: str = _cur_str(ps) + nmlen: t.CInt = string.strlen(name_str) + nxtlen: t.CInt = string.strlen(next_n) + new_name: str = ps.pool.alloc(nmlen + 1 + nxtlen + 1) + if new_name is not None: + string.strcpy(new_name, name_str) + new_name[nmlen] = '.' + string.strcpy(new_name + nmlen + 1, next_n) + name_str = new_name + _advance(ps) + asname: str = None + if _cur_kw(ps) == Keyword.As: + _advance(ps) + if _cur_type(ps) == TokenType.Name: + asname = _cur_str(ps) + _advance(ps) + a: AST | t.CPtr = Alias(ps.pool, name_str, asname) + _set_pos(a, lineno, col, 0, 0) + names.append(a) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + return names + + +def _parse_del(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + targets: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while True: + t_: AST | t.CPtr = _parse_atom_expr(ps) + if t_ is None: break + _set_ctx(t_, ASTCtx.Del) + targets.append(t_) + if not _accept_op(ps, TokOp.Comma): + break + node: AST | t.CPtr = Delete(ps.pool, targets) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_assert(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + test: AST | t.CPtr = _parse_test(ps) + msg: AST | t.CPtr = None + if _accept_op(ps, TokOp.Comma): + msg = _parse_test(ps) + node: AST | t.CPtr = Assert(ps.pool, test, msg) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# Compound statements +# ============================================================ + +def _parse_compound(ps: Parser | t.CPtr) -> AST | t.CPtr: + kw: t.CInt = _cur_kw(ps) + if kw == Keyword.If: + return _parse_if(ps) + if kw == Keyword.While: + return _parse_while(ps) + if kw == Keyword.For: + return _parse_for(ps, 0) + if kw == Keyword.Try: + return _parse_try(ps) + if kw == Keyword.With: + return _parse_with(ps, 0) + if _is_funcdef_kw(ps, kw) != 0: + return _parse_funcdef(ps, 0) + if kw == Keyword.Class: + return _parse_classdef(ps) + if kw == Keyword.Async: + _advance(ps) + if _is_funcdef_kw(ps, _cur_kw(ps)) != 0: + return _parse_funcdef(ps, 1) + if _cur_kw(ps) == Keyword.For: + return _parse_for(ps, 1) + if _cur_kw(ps) == Keyword.With: + return _parse_with(ps, 1) + ps.error_count += 1 + return None + if kw == Keyword.Match and _is_match_stmt(ps) != 0: + return _parse_match(ps) + ps.error_count += 1 + return None + + +def _parse_if(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # if + test: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + # First construct with empty orelse, then fill it in later + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: If | t.CPtr = If(ps.pool, test, empty) + _parse_suite_into_children(ps, node) + orelse: list[AST | t.CPtr] | t.CPtr = _parse_if_tail(ps) + node.orelse = orelse + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_if_tail(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """Parse elif/else chain and return orelse list. + + elif: orelse = list containing single If node (nested) + else: orelse = statement list + """ + if _cur_kw(ps) == Keyword.Elif: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + elif_test: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elif_node: If | t.CPtr = If(ps.pool, elif_test, empty) + _parse_suite_into_children(ps, elif_node) + elif_orelse: list[AST | t.CPtr] | t.CPtr = _parse_if_tail(ps) + elif_node.orelse = elif_orelse + _set_pos(elif_node, lineno, col, 0, 0) + orelse: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + orelse.append(elif_node) + return orelse + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + return scratch.children + return list[AST | t.CPtr](ps.pool, 8) # 空 list + + +# ============================================================ +# Parsing Compound Statements (Continued) +# ============================================================ + +def _parse_while(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # while + test: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: While | t.CPtr = While(ps.pool, test, empty) + _parse_suite_into_children(ps, node) + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + node.orelse = scratch.children + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_for(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # for + target: AST | t.CPtr = _parse_target_list(ps) + if _cur_kw(ps) != Keyword.In: + ps.error_count += 1 + return None + _advance(ps) + iter_: AST | t.CPtr = _parse_or_test(ps) + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: For | t.CPtr = For(ps.pool, target, iter_, empty, is_async) + _fix_store_ctx(target) + _parse_suite_into_children(ps, node) + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + node.orelse = scratch.children + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_try(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # try + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: Try | t.CPtr = Try(ps.pool, empty, empty, empty) + _parse_suite_into_children(ps, node) + # handlers (except) + handlers: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while _cur_kw(ps) == Keyword.Except: + h: AST | t.CPtr = _parse_except_handler(ps) + if h is not None: + handlers.append(h) + node.handlers = handlers + # else + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + node.orelse = scratch.children + # finally + if _cur_kw(ps) == Keyword.Finally: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch2: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch2) + node.finalbody = scratch2.children + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_except_handler(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # except + type_: AST | t.CPtr = None + name: str = None + if _cur_op(ps) != TokOp.Colon: + type_ = _parse_test(ps) + if _cur_kw(ps) == Keyword.As: + _advance(ps) + if _cur_type(ps) == TokenType.Name: + name = _cur_str(ps) + _advance(ps) + _expect_op(ps, TokOp.Colon) + node: AST | t.CPtr = ExceptHandler(ps.pool, type_, name) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_with(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # with + items: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + # items + while True: + item: AST | t.CPtr = _parse_with_item(ps) + if item is None: break + items.append(item) + if not _accept_op(ps, TokOp.Comma): + break + # Check if we can continue with a newline (with (...): form) + if _cur_type(ps) == TokenType.NewLine or _cur_type(ps) == TokenType.Nl: + break + _expect_op(ps, TokOp.Colon) + node: With | t.CPtr = With(ps.pool, items, is_async) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_with_item(ps: Parser | t.CPtr) -> AST | t.CPtr: + """with_item: test ['as' expr]""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + context_expr: AST | t.CPtr = _parse_or_test(ps) + if context_expr is None: return None + optional_vars: AST | t.CPtr = None + if _cur_kw(ps) == Keyword.As: + _advance(ps) + optional_vars = _parse_target(ps) + _fix_store_ctx(optional_vars) + node: AST | t.CPtr = WithItem(ps.pool, context_expr, optional_vars) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_funcdef(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + is_extern_fd: t.CInt = 0 + if _cur_kw(ps) == Keyword.Extern: + # extern 声明:extern [def] A(...) [-> T] [": pass" 可选] + is_extern_fd = 1 + _advance(ps) # extern + if _cur_kw(ps) == Keyword.Def: + _advance(ps) + else: + _advance(ps) # def / fn / ... + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + # PEP 695 泛型函数类型参数: def add[T](a: T, b: T) — 解析并存入 type_params。 + # (与 class 解析器一致;之前缺失此处理导致 _expect_op(Colon) 失败、函数体被 + # 误提升到模块级——b = Box(42) 被当作模块级全局注册,函数内赋值误报 + # "需用 global 声明"。翻译时 type_params 映射到 int 兜底。) + type_params_fd: list[str] | t.CPtr = None + if _accept_op(ps, TokOp.Lsqb): + type_params_fd = list[str](ps.pool, 8) + while not _match_op(ps, TokOp.Rsqb): + if _cur_type(ps) == TokenType.EndMarker: + break + if _cur_type(ps) == TokenType.Name: + tp_name_fd: str = _cur_str(ps) + _advance(ps) + # 跳过可选 bound/约束: [T: bound] 或 [T: (A, B)] + if _match_op(ps, TokOp.Colon): + _advance(ps) + _parse_test(ps) + type_params_fd.append(tp_name_fd) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.Rsqb) + args: AST | t.CPtr = None + if _accept_op(ps, TokOp.LPar): + args = _parse_varargslist(ps, 0) + _expect_op(ps, TokOp.RPar) + returns: AST | t.CPtr = None + if _accept_op(ps, TokOp.RArrow): + returns = _parse_test(ps) + if is_extern_fd: + # extern 声明:返回注解改写为 <原类型> | t.State,复用既有 + # State/外部 C 函数识别路径(vpi 注解含 "State" → 定义端裸名 + 不生成函数体) + state_attr_fd: AST | t.CPtr = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "State", ASTCtx.Load) + if returns != None: + returns = BinOp(ps.pool, returns, OpKind.BitOr, state_attr_fd) + else: + returns = state_attr_fd + dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators + ps.pending_decorators = None + node: FunctionDef | t.CPtr = FunctionDef(ps.pool, name, args, dec_list, returns, is_async, type_params_fd) + if is_extern_fd: + node.flags = node.flags | FLAG_IS_EXTERN + if is_extern_fd == 0 or _match_op(ps, TokOp.Colon): + _expect_op(ps, TokOp.Colon) + _parse_suite_into_children(ps, node) + # extern 无 ': pass' 形式(extern A(...) -> int):body 为空,仅声明 + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # class + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + # Parse type parameters [T] or [T, U] (PEP 695 generic class syntax) + type_params: list[str] | t.CPtr = None + if _accept_op(ps, TokOp.Lsqb): + type_params = list[str](ps.pool, 8) + while not _match_op(ps, TokOp.Rsqb): + if _cur_type(ps) == TokenType.EndMarker: break + if _cur_type(ps) == TokenType.Name: + tp_name: str = _cur_str(ps) + _advance(ps) + # Skip optional bound/constraint: [T: bound] or [T: (A, B)] + if _match_op(ps, TokOp.Colon): + _advance(ps) + _parse_test(ps) + type_params.append(tp_name) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.Rsqb) + bases: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + keywords: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + # bases / keywords + if _accept_op(ps, TokOp.LPar): + while not _match_op(ps, TokOp.RPar): + # 基类括号内跨行(class X(A,\n B):):逗号后换行在此跳过, + # 否则 cur=NL 非 Name/Comma → break → _expect_op(RPar) 报 + # "意外的 token"(Generator.vp L34 多继承跨行根因) + _skip_nl(ps) + if _cur_type(ps) == TokenType.EndMarker: break + # base 或 keyword=value + if _cur_type(ps) == TokenType.Name: + # Parse as expression, if followed by '=', then as keyword=value + e: AST | t.CPtr = _parse_or_test(ps) + if _match_op(ps, TokOp.Equal): + _advance(ps) + v: AST | t.CPtr = _parse_test(ps) + kw_node: AST | t.CPtr = KwNode(ps.pool, e, v) + keywords.append(kw_node) + else: + bases.append(e) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) # 末基类后换行收尾(class X(A,\n B):) + _expect_op(ps, TokOp.RPar) + _expect_op(ps, TokOp.Colon) + dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators + ps.pending_decorators = None + node: ClassDef | t.CPtr = ClassDef(ps.pool, name, bases, keywords, dec_list, type_params) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_match(ps: Parser | t.CPtr) -> AST | t.CPtr: + """match statement: match subject ':' NewLine Indent case+ Dedent""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # match + subject: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + cases: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = Match(ps.pool, subject, cases) + # Parsing body: Same NewLine/Indent/Dedent pattern as _parse_suite_into_children, + # but parses case clauses into a cases list instead of normal statements into children + _skip_nl(ps) + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + _skip_nl(ps) + if _cur_type(ps) == TokenType.Indent: + _advance(ps) + while _cur_type(ps) != TokenType.Dedent and _cur_type(ps) != TokenType.EndMarker: + if _cur_kw(ps) == Keyword.Case: + case_node: AST | t.CPtr = _parse_match_case(ps) + if case_node is not None: + cases.append(case_node) + else: + _advance(ps) # Skip non-case token to avoid infinite loop + _expect_type(ps, TokenType.Dedent) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# Match pattern parsing +# ============================================================ + +def _make_name_ast(pool: memhub.MemManager | t.CPtr, node: Name | t.CPtr) -> AST | t.CPtr: + # Analysis: "Convert Name* to AST* (Solving the TransPyC Type Inference Problem)" + return node + + +def _parse_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr: + """pattern: or_pattern ['as' NAME] + or_pattern: closed_pattern ('|' closed_pattern)*""" + pat: AST | t.CPtr = _parse_closed_pattern(ps) + if pat is None: return None + # OR pattern + if _match_op(ps, TokOp.VBar): + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + patterns.append(pat) + while _accept_op(ps, TokOp.VBar): + p: AST | t.CPtr = _parse_closed_pattern(ps) + if p is not None: + patterns.append(p) + or_node: AST | t.CPtr = MatchOr(ps.pool, patterns) + _set_pos(or_node, pat.lineno, pat.col_offset, 0, 0) + pat = or_node + # AS pattern + if _cur_kw(ps) == Keyword.As: + _advance(ps) + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return pat + name_str: str = _cur_str(ps) + _advance(ps) + as_node: AST | t.CPtr = MatchAs(ps.pool, pat, name_str) + _set_pos(as_node, pat.lineno, pat.col_offset, 0, 0) + return as_node + return pat + + +def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr: + """closed_pattern: literal | capture | wildcard | value | group | sequence | mapping | class""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + ttype: t.CInt = _cur_type(ps) + val: AST | t.CPtr + node: AST | t.CPtr + tok: Token | t.CPtr + sval: str + + # Number literal pattern + if ttype == TokenType.Number: + tok = ps.cur + _advance(ps) + if tok.is_float: + val = _new_const_float(ps.pool, tok.float_val, lineno, col) + else: + val = _new_const_int(ps.pool, tok.int_val, lineno, col) + node = MatchValue(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + + # String literal pattern + if ttype == TokenType.String: + sval = _cur_str(ps) + is_dquote_m: t.CInt = ps.cur.kw_subtype & 16 + _advance(ps) + val = _new_const_str(ps.pool, sval, lineno, col, is_dquote_m) + node = MatchValue(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + + # Negative number literal pattern: -1, -1.5 + if _match_op(ps, TokOp.Minus): + _advance(ps) + if _cur_type(ps) == TokenType.Number: + tok = ps.cur + _advance(ps) + if tok.is_float: + val = _new_const_float(ps.pool, -tok.float_val, lineno, col) + else: + val = _new_const_int(ps.pool, -tok.int_val, lineno, col) + node = MatchValue(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + ps.error_count += 1 + return None + + # Name: None/True/False/_ /capture/value/class + if ttype == TokenType.Name: + kw: t.CInt = _cur_kw(ps) + # None/True/False → MatchSingleton + if kw == Keyword.None_ or kw == Keyword.True_ or kw == Keyword.False_: + _advance(ps) + if kw == Keyword.None_: + val = _new_const_none(ps.pool, lineno, col) + elif kw == Keyword.True_: + val = _new_const_bool(ps.pool, 1, lineno, col) + else: + val = _new_const_bool(ps.pool, 0, lineno, col) + node = MatchSingleton(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + name_str: str = _cur_str(ps) + # Wildcard pattern: _ + if string.strcmp(name_str, "_") == 0: + _advance(ps) + node = MatchAs(ps.pool, None, None) + _set_pos(node, lineno, col, 0, 0) + return node + _advance(ps) + # Check dotted name(value pattern 或 class pattern) + if _match_op(ps, TokOp.Dot): + name_node: Name | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load) + _set_pos(name_node, lineno, col, 0, 0) + base: AST | t.CPtr = _make_name_ast(ps.pool, name_node) + while _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + break + attr_name: str = _cur_str(ps) + attr_lineno: t.CInt = _cur_lineno(ps) + attr_col: t.CInt = _cur_col(ps) + _advance(ps) + base = Attribute(ps.pool, base, attr_name, ASTCtx.Load) + _set_pos(base, attr_lineno, attr_col, 0, 0) + # class pattern: dotted.name(...) + if _match_op(ps, TokOp.LPar): + return _parse_class_pattern(ps, base, lineno, col) + # value pattern: dotted.name + node = MatchValue(ps.pool, base) + _set_pos(node, lineno, col, 0, 0) + return node + # class pattern: Name(...) + if _match_op(ps, TokOp.LPar): + cls_node: Name | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load) + _set_pos(cls_node, lineno, col, 0, 0) + cls: AST | t.CPtr = _make_name_ast(ps.pool, cls_node) + return _parse_class_pattern(ps, cls, lineno, col) + # capture pattern: NAME + node = MatchAs(ps.pool, None, name_str) + _set_pos(node, lineno, col, 0, 0) + return node + + # group pattern / sequence pattern (tuple): (...) + if _match_op(ps, TokOp.LPar): + _advance(ps) + inner: AST | t.CPtr = _parse_pattern(ps) + if _accept_op(ps, TokOp.Comma): + # sequence pattern (tuple) + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if inner is not None: + patterns.append(inner) + while not _match_op(ps, TokOp.RPar) and _cur_type(ps) != TokenType.EndMarker: + p: AST | t.CPtr = _parse_pattern(ps) + if p is not None: + patterns.append(p) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.RPar) + node = MatchSequence(ps.pool, patterns) + _set_pos(node, lineno, col, 0, 0) + return node + _expect_op(ps, TokOp.RPar) + return inner # group pattern + + # sequence pattern (list): [...] + if _match_op(ps, TokOp.Lsqb): + return _parse_sequence_pattern(ps, TokOp.Rsqb, lineno, col) + + # mapping pattern: {...} + if _match_op(ps, TokOp.LBrace): + return _parse_mapping_pattern(ps, lineno, col) + + ps.error_count += 1 + return None + + +def _parse_sequence_pattern(ps: Parser | t.CPtr, close_op: t.CInt, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """sequence_pattern: '[' [pattern_list] ']'""" + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + _advance(ps) # [ + while not _match_op(ps, close_op) and _cur_type(ps) != TokenType.EndMarker: + # *name (star pattern) + if _match_op(ps, TokOp.Star): + _advance(ps) + if _cur_type(ps) == TokenType.Name: + star_name: str = _cur_str(ps) + _advance(ps) + star_node: AST | t.CPtr + if string.strcmp(star_name, "_") == 0: + star_node = MatchStar(ps.pool, None) + else: + star_node = MatchStar(ps.pool, star_name) + _set_pos(star_node, lineno, col, 0, 0) + patterns.append(star_node) + else: + p: AST | t.CPtr = _parse_pattern(ps) + if p is not None: + patterns.append(p) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, close_op) + node: AST | t.CPtr = MatchSequence(ps.pool, patterns) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_mapping_pattern(ps: Parser | t.CPtr, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """mapping_pattern: '{' [items] '}' + items: key ':' pattern (',' key ':' pattern)* [',' '**' NAME] | '**' NAME""" + keys: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + rest: str = None + node: AST | t.CPtr + key: AST | t.CPtr + val_pat: AST | t.CPtr + _advance(ps) # { + if _match_op(ps, TokOp.RBrace): + _advance(ps) + node = MatchMapping(ps.pool, keys, patterns, rest) + _set_pos(node, lineno, col, 0, 0) + return node + while _cur_type(ps) != TokenType.EndMarker: + if _match_op(ps, TokOp.StarStar): + _advance(ps) + if _cur_type(ps) == TokenType.Name: + rest = _cur_str(ps) + _advance(ps) + break + key = _parse_expr(ps) + _expect_op(ps, TokOp.Colon) + val_pat = _parse_pattern(ps) + if key is not None: + keys.append(key) + if val_pat is not None: + patterns.append(val_pat) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.RBrace) + node = MatchMapping(ps.pool, keys, patterns, rest) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_class_pattern(ps: Parser | t.CPtr, cls: AST | t.CPtr, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """class_pattern: cls '(' [pattern_list] ')' + pattern_list: positional_pattern (',' positional_pattern)* + [',' keyword_pattern]* | keyword_pattern (',' keyword_pattern)* + keyword_pattern: NAME '=' pattern""" + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + kwd_attrs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + kwd_patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + p: AST | t.CPtr + _advance(ps) # ( + if not _match_op(ps, TokOp.RPar): + while _cur_type(ps) != TokenType.EndMarker: + # keyword pattern: NAME '=' pattern + if _cur_type(ps) == TokenType.Name and ps.cur is not None: + nxt: Token | t.CPtr = ps.cur.next + if nxt is not None and nxt.type == TokenType.Op and nxt.op_subtype == TokOp.Equal: + attr_name: str = _cur_str(ps) + _advance(ps) # NAME + _advance(ps) # = + kwd_pat: AST | t.CPtr = _parse_pattern(ps) + attr_n: Name | t.CPtr = Name(ps.pool, attr_name, ASTCtx.Load) + _set_pos(attr_n, lineno, col, 0, 0) + attr_node: AST | t.CPtr = _make_name_ast(ps.pool, attr_n) + kwd_attrs.append(attr_node) + if kwd_pat is not None: + kwd_patterns.append(kwd_pat) + else: + p = _parse_pattern(ps) + if p is not None: + patterns.append(p) + else: + p = _parse_pattern(ps) + if p is not None: + patterns.append(p) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.RPar) + node: AST | t.CPtr = MatchClass(ps.pool, cls, patterns, kwd_attrs, kwd_patterns) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_match_case(ps: Parser | t.CPtr) -> AST | t.CPtr: + """case pattern [if guard] ':' suite""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # case + guard: AST | t.CPtr = None + pattern: AST | t.CPtr = _parse_pattern(ps) + if _cur_kw(ps) == Keyword.If: + _advance(ps) + guard = _parse_or_test(ps) + _expect_op(ps, TokOp.Colon) + node: AST | t.CPtr = MatchCase(ps.pool, pattern, guard) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_decorators(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """解析装饰器链,返回 list。""" + decs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while _match_op(ps, TokOp.At): + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # @ + expr: AST | t.CPtr = _parse_namedexpr(ps) + _skip_nl(ps) + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + decs.append(expr) + return decs + + +# ============================================================ +# Module entry +# ============================================================ + +def _parse_module_body(ps: Parser | t.CPtr, module_node: AST | t.CPtr): + """解析模块体,append 到 module_node。""" + _skip_nl(ps) + stmt_idx: t.CInt = 0 + while _cur_type(ps) != TokenType.EndMarker: + stmt_idx += 1 + # Decorator + if _match_op(ps, TokOp.At): + ps.pending_decorators = _parse_decorators(ps) + # Record current token pointer to check for infinite loop + before_cur: Token | t.CPtr = ps.cur + _parse_statement_into(ps, module_node) + # Defense: If parsing doesn't advance the token (like when _parse_atom encounters an unrecognized token and returns None), + # force it to move forward to avoid an infinite loop in the main loop; accumulate error_count for the caller to diagnose + if ps.cur is before_cur: + ps.error_count += 1 + _advance(ps) + _skip_nl(ps) + + +def parse_tokens(pool: memhub.MemManager | t.CPtr, + tokens: Token | t.CPtr) -> AST | t.CPtr: + """Parse an AST Module from a token list.""" + if pool is None or tokens is None: + return None + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + _g_parse_err_line = 0 + _g_parse_err_col = 0 + _g_parse_err_msg = None + ps: Parser | t.CPtr = new_parser(pool) + if ps is None: return None + _parser_init(ps, tokens, pool) + module_node: Module | t.CPtr = Module(pool) + _parse_module_body(ps, module_node) + # fail-fast: 解析出错(error_count > 0)时返回 None,由调用方(TPV 等)报错终止, + # 避免错误代码静默编译(如 `func12344444 avg3(...)` 缺 def 关键字的函数定义残留)。 + if ps.error_count > 0: + return None + return module_node diff --git a/ast/stmts.vp b/ast/stmts.vp new file mode 100644 index 0000000..569646a --- /dev/null +++ b/ast/stmts.vp @@ -0,0 +1,1157 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, Stmt, ASTKind, ASTCtx, OpKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, + FLAG_IS_ASYNC, +) + + +# ============================================================ +# Module Node +# ============================================================ + +@t.CVTable +class Module(AST): + """Module(children: list[AST | t.CPtr])""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Module | t.CPtr = pool.alloc(Module.__sizeof__()) + if ptr: + string.memset(ptr, 0, Module.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Module + + def type_name(self) -> str: + return "Module" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Module(body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Assign Node +# ============================================================ + +class Assign(Stmt): + """Assign(targets: list[AST | t.CPtr], value: AST)""" + targets: list[AST | t.CPtr] | t.CPtr + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr, value: AST | t.CPtr): + ptr: Assign | t.CPtr = pool.alloc(Assign.__sizeof__()) + if ptr: + string.memset(ptr, 0, Assign.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.targets = targets + self.value = value + _set_parent_list(targets, self) + + def kind(self) -> t.CInt: + return ASTKind.Assign + + def type_name(self) -> str: + return "Assign" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Assign(targets=") + pos = _dump_list(self.targets, buf, size, pos) + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# If Node +# ============================================================ + +class If(Stmt): + """If(test: AST, orelse: list[AST | t.CPtr])""" + test: AST | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + ptr: If | t.CPtr = pool.alloc(If.__sizeof__()) + if ptr: + string.memset(ptr, 0, If.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.orelse = orelse + _set_parent_list(orelse, self) + + def kind(self) -> t.CInt: + return ASTKind.If + + def type_name(self) -> str: + return "If" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "If(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", orelse=") + pos = _dump_list(self.orelse, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# For Node +# ============================================================ + +class For(Stmt): + """For(target: AST, iter: AST, orelse: list[AST | t.CPtr], is_async: CInt)""" + target: AST | t.CPtr + iter: AST | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + flags: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + ptr: For | t.CPtr = pool.alloc(For.__sizeof__()) + if ptr: + string.memset(ptr, 0, For.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + _init_ast(self, pool, 0, 0) + self.target = target + self.iter = iter + self.orelse = orelse + if is_async: + self.flags = FLAG_IS_ASYNC + else: + self.flags = 0 + _set_parent_list(orelse, self) + + def kind(self) -> t.CInt: + return ASTKind.For + + def type_name(self) -> str: + return "For" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "For(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", iter=") + if self.iter is not None: + pos = self.iter.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# While Node +# ============================================================ + +class While(Stmt): + """While(test: AST, orelse: list[AST | t.CPtr])""" + test: AST | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + ptr: While | t.CPtr = pool.alloc(While.__sizeof__()) + if ptr: + string.memset(ptr, 0, While.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.orelse = orelse + _set_parent_list(orelse, self) + + def kind(self) -> t.CInt: + return ASTKind.While + + def type_name(self) -> str: + return "While" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "While(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Return Node +# ============================================================ + +class Return(Stmt): + """Return(value: AST | None)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Return | t.CPtr = pool.alloc(Return.__sizeof__()) + if ptr: + string.memset(ptr, 0, Return.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Return + + def type_name(self) -> str: + return "Return" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Return(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Expr Node (expression statement) +# ============================================================ + +class Expr(Stmt): + """Expr(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Expr | t.CPtr = pool.alloc(Expr.__sizeof__()) + if ptr: + string.memset(ptr, 0, Expr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Expr + + def type_name(self) -> str: + return "Expr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Expr(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# FunctionDef Node +# ============================================================ + +class FunctionDef(Stmt): + """FunctionDef(name: str, args: AST, + decorator_list: list[AST | t.CPtr], returns: AST, flags: CInt, + type_params: list[str] | t.CPtr = None) + + type_params: 泛型函数类型参数名列表(PEP 695 def f[T](...): 中的 [T]), + None 表示非泛型函数。""" + name: str + args: AST | t.CPtr + decorator_list: list[AST | t.CPtr] | t.CPtr + returns: AST | t.CPtr + flags: t.CInt + type_params: list[str] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + name: str, args: AST | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr, is_async: t.CInt): + ptr: FunctionDef | t.CPtr = pool.alloc(FunctionDef.__sizeof__()) + if ptr: + string.memset(ptr, 0, FunctionDef.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + name: str, args: AST | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr, is_async: t.CInt, + type_params: list[str] | t.CPtr = None): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + self.args = args + self.decorator_list = decorator_list + self.returns = returns + self.type_params = type_params + if is_async: + self.flags = FLAG_IS_ASYNC + else: + self.flags = 0 + _set_parent_list(decorator_list, self) + + def kind(self) -> t.CInt: + return ASTKind.FunctionDef + + def type_name(self) -> str: + return "FunctionDef" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "FunctionDef(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', args=") + if self.args is not None: + pos = self.args.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", decorator_list=") + pos = _dump_list(self.decorator_list, buf, size, pos) + pos = _emit(buf, size, pos, ", returns=") + if self.returns is not None: + pos = self.returns.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Expression Node +# ============================================================ + +class Expression(AST): + """Expression(body: AST)""" + body: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + ptr: Expression | t.CPtr = pool.alloc(Expression.__sizeof__()) + if ptr: + string.memset(ptr, 0, Expression.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.body = body + + def kind(self) -> t.CInt: + return ASTKind.Expression + + def type_name(self) -> str: + return "Expression" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Expression(body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Interactive Node +# ============================================================ + +class Interactive(AST): + """Interactive(body: AST)""" + body: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + ptr: Interactive | t.CPtr = pool.alloc(Interactive.__sizeof__()) + if ptr: + string.memset(ptr, 0, Interactive.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.body = body + + def kind(self) -> t.CInt: + return ASTKind.Interactive + + def type_name(self) -> str: + return "Interactive" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Interactive(body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# FunctionType Node +# ============================================================ + +class FunctionType(AST): + """FunctionType(argtypes: list[AST | t.CPtr], returns: AST)""" + argtypes: list[AST | t.CPtr] | t.CPtr + returns: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + argtypes: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr): + ptr: FunctionType | t.CPtr = pool.alloc(FunctionType.__sizeof__()) + if ptr: + string.memset(ptr, 0, FunctionType.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + argtypes: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.argtypes = argtypes + self.returns = returns + + def kind(self) -> t.CInt: + return ASTKind.FunctionType + + def type_name(self) -> str: + return "FunctionType" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "FunctionType(argtypes=") + pos = _dump_list(self.argtypes, buf, size, pos) + pos = _emit(buf, size, pos, ", returns=") + if self.returns is not None: + pos = self.returns.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# ClassDef Node +# ============================================================ + +class ClassDef(Stmt): + """ClassDef(name: str, bases: list[AST | t.CPtr], keywords: list[AST | t.CPtr], + decorator_list: list[AST | t.CPtr], type_params: list[str] | t.CPtr) + + type_params: 泛型类型参数名列表(PEP 695 class list[T]: 中的 [T]), + None 表示非泛型类。""" + name: str + bases: list[AST | t.CPtr] | t.CPtr + keywords: list[AST | t.CPtr] | t.CPtr + decorator_list: list[AST | t.CPtr] | t.CPtr + type_params: list[str] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + name: str, + bases: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + type_params: list[str] | t.CPtr = None): + ptr: ClassDef | t.CPtr = pool.alloc(ClassDef.__sizeof__()) + if ptr: + string.memset(ptr, 0, ClassDef.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + name: str, + bases: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + type_params: list[str] | t.CPtr = None): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + self.bases = bases + self.keywords = keywords + self.decorator_list = decorator_list + self.type_params = type_params + _set_parent_list(decorator_list, self) + + def kind(self) -> t.CInt: + return ASTKind.ClassDef + + def type_name(self) -> str: + return "ClassDef" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ClassDef(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', bases=") + pos = _dump_list(self.bases, buf, size, pos) + pos = _emit(buf, size, pos, ", keywords=") + pos = _dump_list(self.keywords, buf, size, pos) + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", decorator_list=") + pos = _dump_list(self.decorator_list, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Delete Node +# ============================================================ + +class Delete(Stmt): + """Delete(targets: list[AST | t.CPtr])""" + targets: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr): + ptr: Delete | t.CPtr = pool.alloc(Delete.__sizeof__()) + if ptr: + string.memset(ptr, 0, Delete.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.targets = targets + _set_parent_list(targets, self) + + def kind(self) -> t.CInt: + return ASTKind.Delete + + def type_name(self) -> str: + return "Delete" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Delete(targets=") + pos = _dump_list(self.targets, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# AugAssign Node +# ============================================================ + +class AugAssign(Stmt): + """AugAssign(target: AST, op: CInt, value: AST)""" + target: AST | t.CPtr + op: t.CInt + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, op: t.CInt, value: AST | t.CPtr): + ptr: AugAssign | t.CPtr = pool.alloc(AugAssign.__sizeof__()) + if ptr: + string.memset(ptr, 0, AugAssign.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, op: t.CInt, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.target = target + self.op = op + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.AugAssign + + def type_name(self) -> str: + return "AugAssign" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "AugAssign(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# AnnAssign Node +# ============================================================ + +class AnnAssign(Stmt): + """AnnAssign(target: AST, annotation: AST, value: AST, simple: CInt)""" + target: AST | t.CPtr + annotation: AST | t.CPtr + value: AST | t.CPtr + simple: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, annotation: AST | t.CPtr, + value: AST | t.CPtr, simple: t.CInt): + ptr: AnnAssign | t.CPtr = pool.alloc(AnnAssign.__sizeof__()) + if ptr: + string.memset(ptr, 0, AnnAssign.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, annotation: AST | t.CPtr, + value: AST | t.CPtr, simple: t.CInt): + _init_ast(self, pool, 0, 0) + self.target = target + self.annotation = annotation + self.value = value + self.simple = simple + + def kind(self) -> t.CInt: + return ASTKind.AnnAssign + + def type_name(self) -> str: + return "AnnAssign" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "AnnAssign(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", annotation=") + if self.annotation is not None: + pos = self.annotation.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", simple=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.simple)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# With Node +# ============================================================ + +class With(Stmt): + """With(items: list[AST | t.CPtr], is_async: CInt)""" + items: list[AST | t.CPtr] | t.CPtr + flags: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + items: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + ptr: With | t.CPtr = pool.alloc(With.__sizeof__()) + if ptr: + string.memset(ptr, 0, With.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + items: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + _init_ast(self, pool, 0, 0) + self.items = items + if is_async: + self.flags = FLAG_IS_ASYNC + else: + self.flags = 0 + _set_parent_list(items, self) + + def kind(self) -> t.CInt: + return ASTKind.With + + def type_name(self) -> str: + return "With" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "With(items=") + pos = _dump_list(self.items, buf, size, pos) + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Raise Node +# ============================================================ + +class Raise(Stmt): + """Raise(exc: AST, cause: AST)""" + exc: AST | t.CPtr + cause: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + exc: AST | t.CPtr, cause: AST | t.CPtr): + ptr: Raise | t.CPtr = pool.alloc(Raise.__sizeof__()) + if ptr: + string.memset(ptr, 0, Raise.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + exc: AST | t.CPtr, cause: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.exc = exc + self.cause = cause + + def kind(self) -> t.CInt: + return ASTKind.Raise + + def type_name(self) -> str: + return "Raise" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Raise(exc=") + if self.exc is not None: + pos = self.exc.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", cause=") + if self.cause is not None: + pos = self.cause.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Try Node +# ============================================================ + +class Try(Stmt): + """Try(handlers: list[AST | t.CPtr], + orelse: list[AST | t.CPtr], finalbody: list[AST | t.CPtr])""" + handlers: list[AST | t.CPtr] | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + finalbody: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + handlers: list[AST | t.CPtr] | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + finalbody: list[AST | t.CPtr] | t.CPtr): + ptr: Try | t.CPtr = pool.alloc(Try.__sizeof__()) + if ptr: + string.memset(ptr, 0, Try.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + handlers: list[AST | t.CPtr] | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + finalbody: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.handlers = handlers + self.orelse = orelse + self.finalbody = finalbody + _set_parent_list(handlers, self) + _set_parent_list(orelse, self) + _set_parent_list(finalbody, self) + + def kind(self) -> t.CInt: + return ASTKind.Try + + def type_name(self) -> str: + return "Try" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Try(body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", handlers=") + pos = _dump_list(self.handlers, buf, size, pos) + pos = _emit(buf, size, pos, ", orelse=") + pos = _dump_list(self.orelse, buf, size, pos) + pos = _emit(buf, size, pos, ", finalbody=") + pos = _dump_list(self.finalbody, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Assert Node +# ============================================================ + +class Assert(Stmt): + """Assert(test: AST, msg: AST)""" + test: AST | t.CPtr + msg: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, msg: AST | t.CPtr): + ptr: Assert | t.CPtr = pool.alloc(Assert.__sizeof__()) + if ptr: + string.memset(ptr, 0, Assert.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, msg: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.msg = msg + + def kind(self) -> t.CInt: + return ASTKind.Assert + + def type_name(self) -> str: + return "Assert" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Assert(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", msg=") + if self.msg is not None: + pos = self.msg.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Global Node +# ============================================================ + +class Global(Stmt): + """Global(names: list[AST | t.CPtr])""" + names: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + ptr: Global | t.CPtr = pool.alloc(Global.__sizeof__()) + if ptr: + string.memset(ptr, 0, Global.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.names = names + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.Global + + def type_name(self) -> str: + return "Global" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Global(names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Nonlocal Node +# ============================================================ + +class Nonlocal(Stmt): + """Nonlocal(names: list[AST | t.CPtr])""" + names: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + ptr: Nonlocal | t.CPtr = pool.alloc(Nonlocal.__sizeof__()) + if ptr: + string.memset(ptr, 0, Nonlocal.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.names = names + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.Nonlocal + + def type_name(self) -> str: + return "Nonlocal" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Nonlocal(names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Pass Node +# ============================================================ + +class Pass(Stmt): + """Pass()""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Pass | t.CPtr = pool.alloc(Pass.__sizeof__()) + if ptr: + string.memset(ptr, 0, Pass.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Pass + + def type_name(self) -> str: + return "Pass" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Pass()") + return pos + + +# ============================================================ +# Break Node +# ============================================================ + +class Break(Stmt): + """Break()""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Break | t.CPtr = pool.alloc(Break.__sizeof__()) + if ptr: + string.memset(ptr, 0, Break.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Break + + def type_name(self) -> str: + return "Break" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Break()") + return pos + + +# ============================================================ +# Continue Node +# ============================================================ + +class Continue(Stmt): + """Continue()""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Continue | t.CPtr = pool.alloc(Continue.__sizeof__()) + if ptr: + string.memset(ptr, 0, Continue.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Continue + + def type_name(self) -> str: + return "Continue" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Continue()") + return pos + + +# ============================================================ +# Import Node +# ============================================================ + +class Import(Stmt): + """Import(names: list[AST | t.CPtr])""" + names: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + ptr: Import | t.CPtr = pool.alloc(Import.__sizeof__()) + if ptr: + string.memset(ptr, 0, Import.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.names = names + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.Import + + def type_name(self) -> str: + return "Import" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Import(names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# ImportFrom Node +# ============================================================ + +class ImportFrom(Stmt): + """ImportFrom(module: str, names: list[AST | t.CPtr], level: CInt)""" + module: str + names: list[AST | t.CPtr] | t.CPtr + level: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + module: str, + names: list[AST | t.CPtr] | t.CPtr, + level: t.CInt): + ptr: ImportFrom | t.CPtr = pool.alloc(ImportFrom.__sizeof__()) + if ptr: + string.memset(ptr, 0, ImportFrom.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + module: str, + names: list[AST | t.CPtr] | t.CPtr, + level: t.CInt): + _init_ast(self, pool, 0, 0) + self.module = _copy_str(pool, module) + self.names = names + self.level = level + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.ImportFrom + + def type_name(self) -> str: + return "ImportFrom" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ImportFrom(module='") + pos = _emit_str(buf, size, pos, self.module) + pos = _emit(buf, size, pos, "', names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ", level=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.level)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Match Node +# ============================================================ + +class Match(Stmt): + """Match(subject: AST, cases: list[AST | t.CPtr])""" + subject: AST | t.CPtr + cases: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + subject: AST | t.CPtr, + cases: list[AST | t.CPtr] | t.CPtr): + ptr: Match | t.CPtr = pool.alloc(Match.__sizeof__()) + if ptr: + string.memset(ptr, 0, Match.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + subject: AST | t.CPtr, + cases: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.subject = subject + self.cases = cases + _set_parent_list(cases, self) + + def kind(self) -> t.CInt: + return ASTKind.Match + + def type_name(self) -> str: + return "Match" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Match(subject=") + if self.subject is not None: + pos = self.subject.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", cases=") + pos = _dump_list(self.cases, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/tokens.vp b/ast/tokens.vp new file mode 100644 index 0000000..d9c07c5 --- /dev/null +++ b/ast/tokens.vp @@ -0,0 +1,404 @@ +import t, c +from stdint import * +import memhub +import string + + +# ============================================================ +# Token type enumeration (refer to CPython Lib/token.py) +# Organized as a type-safe enum using t.CEnum; old names XXX retained as compatible aliases +# ============================================================ + +class TokenType(t.CEnum): + EndMarker: t.State + NewLine: t.State + Indent: t.State + Dedent: t.State + Name: t.State + Number: t.State + String: t.State + FStringStart: t.State + FStringMiddle: t.State + FStringEnd: t.State + Op: t.State + Nl: t.State + Comment: t.State + Encoding: t.State + + +# ============================================================ +# Keyword enumeration (refer to CPython Lib/keyword.py) +# Organized as a type-safe enum using t.CEnum; old names KW_XXX are kept as compatible aliases +# NotKeyword(0) represents a non-keyword (sentinel to avoid conflict between False_=0 and kw_subtype=0) +# ============================================================ + +class Keyword(t.CEnum): + NotKeyword: t.State + False_: t.State + None_: t.State + True_: t.State + And: t.State + As: t.State + Assert: t.State + Async: t.State + Await: t.State + Break: t.State + Class: t.State + Continue: t.State + Def: t.State + Del: t.State + Elif: t.State + Else: t.State + Except: t.State + Finally: t.State + For: t.State + From: t.State + Global: t.State + If: t.State + Import: t.State + In: t.State + Is: t.State + Lambda: t.State + Nonlocal: t.State + Not: t.State + Or: t.State + Pass: t.State + Raise: t.State + Return: t.State + Try: t.State + While: t.State + With: t.State + Yield: t.State + Match: t.State + Case: t.State + Type: t.State + # def 的别名关键字(fn/fun/func/function,语义与 def 完全相同) + Fn: t.State + Fun: t.State + Func: t.State + Function: t.State + # extern 函数声明关键字(FFI,等价 t.State 标记;软判定见 _is_funcdef_kw) + Extern: t.State + + +# ============================================================ +# Operator/Separator Enumeration +# Organized as a type-safe enum using t.CEnum; old names OP_XXX retained as compatible aliases +# Stored in the token.op_subtype field +# ============================================================ + +class TokOp(t.CEnum): + LPar: t.State # ( + RPar: t.State # ) + Lsqb: t.State # [ + Rsqb: t.State # ] + LBrace: t.State # { + RBrace: t.State # } + Comma: t.State # , + Colon: t.State # : + Dot: t.State # . + Semi: t.State # ; + At: t.State # @ + Equal: t.State # = + RArrow: t.State # -> + PlusEq: t.State # += + MinusEq: t.State # -= + StarEq: t.State # *= + SlashEq: t.State # /= + DSlashEq: t.State # //= + PercentEq: t.State # %= + AtEq: t.State # @= + AmpEq: t.State # &= + VBarEq: t.State # |= + CaretEq: t.State # ^= + GtGtEq: t.State # >>= + LtLtEq: t.State # <<= + StarEqEq: t.State # **= + DSlash: t.State # // + StarStar: t.State # ** + LtLt: t.State # << + GtGt: t.State # >> + LessEq: t.State # <= + GreaterEq: t.State # >= + EqEq: t.State # == + ExclaimEq: t.State # != + Less: t.State # < + Greater: t.State # > + Plus: t.State # + + Minus: t.State # - + Star: t.State # * + Slash: t.State # / + Percent: t.State # % + Amp: t.State # & + VBar: t.State # | + Caret: t.State # ^ + Tilde: t.State # ~ + ColonEq: t.State # := + Ellipsis: t.State # ... + Bang: t.State # !(Non-standard, used for parsing tolerance) + + +# ============================================================ +# Token stucture +# ============================================================ +class Token: + type: t.CInt # Token type (TokenType.EndMarker / TokenType.NewLine / TokenType.Name / ...) + op_subtype: t.CInt # Operator subtype (OP_*). Only valid when type == TokenType.Op + kw_subtype: t.CInt # Keyword subtype (KW_*). Only valid when type == TokenType.Name and it is a keyword + str_val: str # Token text (NUL‑terminated, allocated from pool) + int_val: t.CInt64T # Integer value (used by TokenType.Number) + float_val: t.CDouble # Floating‑point value (used by TokenType.Number) + is_float: t.CInt # 1 = floating‑point number, 0 = integer + is_complex: t.CInt # 1 = complex number, 0 = real number + lineno: t.CInt # Starting line number + col_offset: t.CInt # Starting column offset + end_lineno: t.CInt # Ending line number + end_col_offset: t.CInt # Ending column offset + next: Token | t.CPtr # Next token in linked list + + def __new__(self, pool: memhub.MemManager | t.CPtr): + """Allocate zero‑initialized Token struct memory from mpool""" + ptr: Token | t.CPtr = pool.alloc(Token.__sizeof__()) + if ptr: + string.memset(ptr, 0, Token.__sizeof__()) + return ptr + + +# ============================================================ +# Keyword lookup table +# Since TransPyC has no dict literals, implemented with linked lists +# ============================================================ +class KwEntry: + name: str + kw_id: t.CInt + next: KwEntry | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: KwEntry | t.CPtr = pool.alloc(KwEntry.__sizeof__()) + if ptr: + string.memset(ptr, 0, KwEntry.__sizeof__()) + return ptr + + +# Global keyword linked list head (lazy initialization) +_kw_head: KwEntry | t.CPtr = None +_kw_pool: memhub.MemManager | t.CPtr = None + + +def _kw_intern(pool: memhub.MemManager | t.CPtr, name: str, kw_id: t.CInt): + """Register keyword name in the linked list""" + global _kw_head + entry: KwEntry | t.CPtr = KwEntry(pool) + if entry == None: return + slen: t.CSizeT = string.strlen(name) + buf: str = pool.alloc(slen + 1) + if buf == None: return + string.memcpy(buf, name, slen + 1) + entry.name = buf + entry.kw_id = kw_id + entry.next = _kw_head + _kw_head = entry + + +def _kw_lookup(name: str) -> t.CInt: + """Look up keyword name in the linked list, return the kw_id (0 if not keyword)""" + cur: KwEntry | t.CPtr = _kw_head + while cur != None: + if string.strcmp(cur.name, name) == 0: + return cur.kw_id + cur = cur.next + return 0 + + +def _init_keywords(pool: memhub.MemManager | t.CPtr): + """Initialize keyword linked list (only once)""" + global _kw_head, _kw_pool + if _kw_head != None: return + _kw_pool = pool + _kw_intern(pool, "False", Keyword.False_) + _kw_intern(pool, "None", Keyword.None_) + _kw_intern(pool, "True", Keyword.True_) + _kw_intern(pool, "and", Keyword.And) + _kw_intern(pool, "as", Keyword.As) + _kw_intern(pool, "assert", Keyword.Assert) + _kw_intern(pool, "async", Keyword.Async) + _kw_intern(pool, "await", Keyword.Await) + _kw_intern(pool, "break", Keyword.Break) + _kw_intern(pool, "class", Keyword.Class) + _kw_intern(pool, "continue", Keyword.Continue) + _kw_intern(pool, "def", Keyword.Def) + _kw_intern(pool, "del", Keyword.Del) + _kw_intern(pool, "elif", Keyword.Elif) + _kw_intern(pool, "else", Keyword.Else) + _kw_intern(pool, "except", Keyword.Except) + _kw_intern(pool, "finally", Keyword.Finally) + _kw_intern(pool, "for", Keyword.For) + _kw_intern(pool, "from", Keyword.From) + _kw_intern(pool, "global", Keyword.Global) + _kw_intern(pool, "if", Keyword.If) + _kw_intern(pool, "import", Keyword.Import) + _kw_intern(pool, "in", Keyword.In) + _kw_intern(pool, "is", Keyword.Is) + _kw_intern(pool, "lambda", Keyword.Lambda) + _kw_intern(pool, "nonlocal", Keyword.Nonlocal) + _kw_intern(pool, "not", Keyword.Not) + _kw_intern(pool, "or", Keyword.Or) + _kw_intern(pool, "pass", Keyword.Pass) + _kw_intern(pool, "raise", Keyword.Raise) + _kw_intern(pool, "return", Keyword.Return) + _kw_intern(pool, "try", Keyword.Try) + _kw_intern(pool, "while", Keyword.While) + _kw_intern(pool, "with", Keyword.With) + _kw_intern(pool, "yield", Keyword.Yield) + _kw_intern(pool, "match", Keyword.Match) + _kw_intern(pool, "case", Keyword.Case) + _kw_intern(pool, "type", Keyword.Type) + # def 的别名关键字(fn/fun/func/function,语义与 def 完全相同) + _kw_intern(pool, "fn", Keyword.Fn) + _kw_intern(pool, "fun", Keyword.Fun) + _kw_intern(pool, "func", Keyword.Func) + _kw_intern(pool, "function", Keyword.Function) + _kw_intern(pool, "extern", Keyword.Extern) + + +# ============================================================ +# Operator lookup table +# Since TransPyC doesn't have dict, use an array with linear search +# Operators are sorted by descending length for greedy matching +# ============================================================ +class OpEntry: + name: str # Operator text (e.g. "==", "+=") + op_id: t.CInt + length: t.CInt + next: OpEntry | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: OpEntry | t.CPtr = pool.alloc(OpEntry.__sizeof__()) + if ptr: + string.memset(ptr, 0, OpEntry.__sizeof__()) + return ptr + + +_op_head: OpEntry | t.CPtr = None + + +def _op_intern(pool: memhub.MemManager | t.CPtr, name: str, op_id: t.CInt): + global _op_head + slen: t.CSizeT = string.strlen(name) + entry: OpEntry | t.CPtr = OpEntry(pool) + if entry == None: return + buf: str = pool.alloc(slen + 1) + if buf == None: return + string.memcpy(buf, name, slen + 1) + entry.name = buf + entry.op_id = op_id + entry.length = t.CInt(slen) + entry.next = _op_head + _op_head = entry + + +def _init_operators(pool: memhub.MemManager | t.CPtr): + """Initialize the operator table (register in descending length order for easy greedy matching)""" + global _op_head + if _op_head != None: return + # 3-character operators + _op_intern(pool, "**=", TokOp.StarEqEq) + _op_intern(pool, "//=", TokOp.DSlashEq) + _op_intern(pool, ">>=", TokOp.GtGtEq) + _op_intern(pool, "<<=", TokOp.LtLtEq) + _op_intern(pool, "...", TokOp.Ellipsis) + # 2-character operators + _op_intern(pool, "->", TokOp.RArrow) + _op_intern(pool, "+=", TokOp.PlusEq) + _op_intern(pool, "-=", TokOp.MinusEq) + _op_intern(pool, "*=", TokOp.StarEq) + _op_intern(pool, "/=", TokOp.SlashEq) + _op_intern(pool, "%=", TokOp.PercentEq) + _op_intern(pool, "@=", TokOp.AtEq) + _op_intern(pool, "&=", TokOp.AmpEq) + _op_intern(pool, "|=", TokOp.VBarEq) + _op_intern(pool, "^=", TokOp.CaretEq) + _op_intern(pool, "//", TokOp.DSlash) + _op_intern(pool, "**", TokOp.StarStar) + _op_intern(pool, "<<", TokOp.LtLt) + _op_intern(pool, ">>", TokOp.GtGt) + _op_intern(pool, "<=", TokOp.LessEq) + _op_intern(pool, ">=", TokOp.GreaterEq) + _op_intern(pool, "==", TokOp.EqEq) + _op_intern(pool, "!=", TokOp.ExclaimEq) + _op_intern(pool, ":=", TokOp.ColonEq) + # 1-character operators + _op_intern(pool, "(", TokOp.LPar) + _op_intern(pool, ")", TokOp.RPar) + _op_intern(pool, "[", TokOp.Lsqb) + _op_intern(pool, "]", TokOp.Rsqb) + _op_intern(pool, "{", TokOp.LBrace) + _op_intern(pool, "}", TokOp.RBrace) + _op_intern(pool, ",", TokOp.Comma) + _op_intern(pool, ":", TokOp.Colon) + _op_intern(pool, ".", TokOp.Dot) + _op_intern(pool, ";", TokOp.Semi) + _op_intern(pool, "@", TokOp.At) + _op_intern(pool, "=", TokOp.Equal) + _op_intern(pool, "<", TokOp.Less) + _op_intern(pool, ">", TokOp.Greater) + _op_intern(pool, "+", TokOp.Plus) + _op_intern(pool, "-", TokOp.Minus) + _op_intern(pool, "*", TokOp.Star) + _op_intern(pool, "/", TokOp.Slash) + _op_intern(pool, "%", TokOp.Percent) + _op_intern(pool, "&", TokOp.Amp) + _op_intern(pool, "|", TokOp.VBar) + _op_intern(pool, "^", TokOp.Caret) + _op_intern(pool, "~", TokOp.Tilde) + + +def _init_tables(pool: memhub.MemManager | t.CPtr): + """Initialize all lookup tables (idempotent)""" + _init_keywords(pool) + _init_operators(pool) + + +# ============================================================ +# Token creation helper functions +# ============================================================ + +def new_token(pool: memhub.MemManager | t.CPtr, ttype: t.CInt, lineno: t.CInt, + col_offset: t.CInt) -> Token | t.CPtr: + """Create a new empty Token and fill in fields later""" + tok: Token | t.CPtr = Token(pool) + if tok == None: return None + tok.type = ttype + tok.lineno = lineno + tok.col_offset = col_offset + tok.end_lineno = lineno + tok.end_col_offset = col_offset + return tok + + +def token_set_str(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr, + src: str, start: t.CSizeT, length: t.CSizeT): + """Copy text from src[start:start + length] to token.str_val + + Note: When length == 0, still allocate 1 byte for NUL, so that an empty string is distinguished from a NULL pointer. + """ + if tok == None: return + buf: str = pool.alloc(length + 1) + if buf == None: return + i: t.CSizeT = 0 + while i < length: + buf[i] = src[start + i] + i += 1 + buf[length] = '\0' + tok.str_val = buf + + +def token_set_str_literal(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr, + text: str): + """Copy a C string to token.str_val""" + if tok == None or text == None: return + slen: t.CSizeT = string.strlen(text) + buf: str = pool.alloc(slen + 1) + if buf == None: return + string.memcpy(buf, text, slen + 1) + tok.str_val = buf diff --git a/atom.vp b/atom.vp new file mode 100644 index 0000000..6c58de9 --- /dev/null +++ b/atom.vp @@ -0,0 +1,41 @@ +import t, c + + +ATOMIC_RELAXED: t.CDefine = 0 +ATOMIC_CONSUME: t.CDefine = 1 +ATOMIC_ACQUIRE: t.CDefine = 2 +ATOMIC_RELEASE: t.CDefine = 3 +ATOMIC_ACQ_REL: t.CDefine = 4 +ATOMIC_SEQ_CST: t.CDefine = 5 + + +def __atomic_test_and_set(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CBool: + result: t.CUInt8T = 1 + c.Asm(f"""mov al, 1 + xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al + mov $0, al""", + out = [c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)], + op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX]) + return t.CBool(result) + + +def __atomic_clear(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CVoid: + c.Asm(f"""mov byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], 0""", + inp = [c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)], + op = [t.ASM_DESCR.CLOBBER_MEMORY]) + + +def __atomic_thread_fence(order: t.CInt) -> t.CVoid: + c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) + + +def __atomic_signal_fence(order: t.CInt) -> t.CVoid: + pass + + +def __atomic_always_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool: + return t.CBool(1) + + +def __atomic_is_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool: + return t.CBool(1) diff --git a/base64.vp b/base64.vp new file mode 100644 index 0000000..0dfc962 --- /dev/null +++ b/base64.vp @@ -0,0 +1,80 @@ +import t, c + + +# ============================================== +# Base64 Encoder & Decoder, pure bare-metal implementation +# ============================================== +# Base64 encoding lookup table +b64_tab: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +# Base64 反向解码表,映射字符到索引值 +b64_dec_tab: t.CArray[t.CInt8T, 80] = [ + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 +] + +# * @brief Base64 encoding +# * @param s: Input binary data +# * @param out: Output buffer for Base64 string +# * @retval Length of encoded string +def b64encode(s: str, out: str) -> t.CSizeT: + _s = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + i: t.CSizeT = 0 + j: t.CSizeT = 0 + val: t.CUInt32T = 0 + # Process input in groups of 3 bytes, produce 4 Base64 characters + for i in range(0, length, 3): + # Assemble 24-bit chunk + val = ((t.CUInt32T(_s[i + 0]) << 16 ) | + (t.CUInt32T(_s[i + 1]) << 8 if (i + 1 < length) else 0) | + (t.CUInt32T(_s[i + 2]) << 0 if (i + 2 < length) else 0)) + # Split into four 6-bit values for table lookup + out[j + 0] = b64_tab[(val >> 18) & 0x3F] + out[j + 1] = b64_tab[(val >> 12) & 0x3F] + out[j + 2] = b64_tab[(val >> 6) & 0x3F] if (i + 1 < length) else '=' + out[j + 3] = b64_tab[(val >> 0) & 0x3F] if (i + 2 < length) else '=' + j += 4 + out[j] = '\0' # Null terminator for C-style string + return j + + +# * @brief Base64 decoding +# * @param s: Base64 encoded string +# * @param out: Output binary buffer +# * @retval Length of decoded binary data +def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT: + length: t.CSizeT = len(s) + i: t.CSizeT = 0 + j: t.CSizeT = 0 + val: t.CUInt32T = 0 + c: t.CInt + # Restore 3 bytes from every 4 Base64 characters + for i in range(0, length, 4): + if s[i] == '=': + break + val = 0 + # Parse 6-bit values sequentially + c = s[i] - 43 + val |= (b64_dec_tab[c] & 0x3F) << 18 + c = s[i+1] - 43 + val |= (b64_dec_tab[c] & 0x3F) << 12 + c = s[i+2] - 43 + if s[i+2] != '=': + val |= (b64_dec_tab[c] & 0x3F) << 6 + c = s[i+3] - 43 + if s[i+3] != '=': + val |= (b64_dec_tab[c] & 0x3F) + # Write recovered bytes + out[j] = (val >> 16) & 0xFF + j += 1 + if s[i+2] != '=': + out[j] = (val >> 8) & 0xFF + j += 1 + if s[i+3] != '=': + out[j] = val & 0xFF + j += 1 + return j diff --git a/binascii.vp b/binascii.vp new file mode 100644 index 0000000..31e81ee --- /dev/null +++ b/binascii.vp @@ -0,0 +1,349 @@ +import t, c +import stdlib + + +HEX_CHARS: t.CArray[t.CChar, None] = "0123456789abcdef" +HEX_VALS: t.CArray[t.CInt, 256] + +B64_CHARS: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +B64_VALS: t.CArray[t.CInt, 256] + +HQX_CHARS: t.CArray[t.CChar, 64] = [ + ' ', '!', chr(34), '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '@', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', + '[', chr(92), '`', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm' +] +HQX_VALS: t.CArray[t.CInt, 256] + +UU_CHARS: t.CArray[t.CChar, None] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + +CRC32_TABLE: t.CArray[t.CUnsignedInt, 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] + +CRC_HQX_TABLE: t.CArray[t.CUnsignedShort, 256] = [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +] + +def init_binascii(): + i: t.CInt + for i in range(256): + HEX_VALS[i] = -1 + B64_VALS[i] = -1 + HQX_VALS[i] = -1 + for i in range(16): + HEX_VALS[t.CInt(HEX_CHARS[i])] = i + HEX_VALS[t.CInt(HEX_CHARS[i] - 32)] = i + for i in range(64): + B64_VALS[t.CInt(B64_CHARS[i])] = i + for i in range(64): + HQX_CHARS[i] = t.CChar(32 + i) + for i in range(64): + HQX_VALS[t.CUnsignedChar(HQX_CHARS[i])] = i + +def crc32(data: str, length: t.CInt, crc: t.CUnsignedInt) -> t.CUnsignedInt: + i: t.CInt + s: t.CUnsignedInt = crc ^ 0xFFFFFFFF + for i in range(length): + s = CRC32_TABLE[(s ^ t.CUnsignedChar(data[i])) & 0xFF] ^ (s >> 8) + return s ^ 0xFFFFFFFF + +def crc_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort) -> t.CUnsignedShort: + i: t.CInt + s: t.CUnsignedShort = crc + for i in range(length): + s = CRC_HQX_TABLE[t.CUnsignedChar(s >> 8)] ^ (s << 1 | (data[i] & 0xFF)) + return s + +def hexlify(data: str, length: t.CInt) -> str: + if not data or length < 0: return None + out: str = str(stdlib.malloc(length * 2 + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(length): + s: t.CUnsignedChar = t.CUnsignedChar(data[i]) + out[oi] = HEX_CHARS[(s >> 4) & 0x0F] + oi += 1 + out[oi] = HEX_CHARS[(s >> 0) & 0x0F] + oi += 1 + out[oi] = '\0' + return out + +def b2a_hex(data: str, length: t.CInt) -> str: + return hexlify(data, length) + +def a2b_hex(hexstr: str, length: t.CInt) -> str: + if not hexstr or length < 0 or length % 2 != 0: return None + out_len: t.CInt = length // 2 + out: str = str(stdlib.malloc(out_len + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(0, length, 2): + hi: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i])] + lo: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i + 1])] + if hi < 0 or lo < 0: + stdlib.free(out) + return None + out[oi] = t.CChar((hi << 4) | lo) + oi += 1 + out[oi] = '\0' + return out + +def unhexlify(data: str, length: t.CInt) -> bytes: + return a2b_hex(data, length) + +def b2a_base64(data: str, length: t.CInt) -> str: + if not data or length < 0: return None + olen: t.CInt = (length // 3) * 4 + if length % 3 != 0: + olen += 4 + olen += 1 + out: str = str(stdlib.malloc(olen + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(0, length, 3): + b0: t.CUnsignedChar = t.CUnsignedChar(data[i]) + b1: t.CUnsignedChar = 0 + b2: t.CUnsignedChar = 0 + if i + 1 < length: + b1 = t.CUnsignedChar(data[i + 1]) + if i + 2 < length: + b2 = t.CUnsignedChar(data[i + 2]) + out[oi] = B64_CHARS[(b0 >> 2) & 0x3F] + oi += 1 + out[oi] = B64_CHARS[((b0 & 0x03) << 4) | ((b1 >> 4) & 0x0F)] + oi += 1 + if i + 1 < length: + out[oi] = B64_CHARS[((b1 & 0x0F) << 2) | ((b2 >> 6) & 0x03)] + else: + out[oi] = '=' + oi += 1 + if i + 2 < length: + out[oi] = B64_CHARS[b2 & 0x3F] + else: + out[oi] = '=' + oi += 1 + out[oi] = '\0' + return out + +def a2b_base64(data: str, length: t.CInt) -> str: + if not data or length < 4: return None + olen: t.CInt = (length // 4) * 3 + if length >= 4 and data[length - 1] == '=': + olen -= 1 + if length >= 4 and data[length - 2] == '=': + olen -= 1 + out: str = str(stdlib.malloc(olen + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(0, length, 4): + v0: t.CInt = 0 + v1: t.CInt = 0 + v2: t.CInt = 0 + v3: t.CInt = 0 + j: t.CInt + for j in range(4): + c: t.CChar = data[i + j] + if c == '=': + pass + else: + k: t.CInt + for k in range(64): + if B64_CHARS[k] == c: + if j == 0: v0 = k + elif j == 1: v1 = k + elif j == 2: v2 = k + elif j == 3: v3 = k + break + out[oi] = t.CChar((v0 << 2) | (v1 >> 4)) + oi += 1 + if data[i + 2] != '=': + out[oi] = t.CChar(((v1 & 0x0F) << 4) | (v2 >> 2)) + oi += 1 + if data[i + 3] != '=': + out[oi] = t.CChar(((v2 & 0x03) << 6) | v3) + oi += 1 + out[oi] = '\0' + return out + +def b2a_uu(data: str, length: t.CInt) -> str: + if not data or length < 1 or length > 45: return None + out: str = str(stdlib.malloc(length * 2 + 2)) + if not out: return None + oi: t.CInt = 0 + out[oi] = UU_CHARS[length] + oi += 1 + for i in range(0, length, 3): + b0: t.CUnsignedChar = t.CUnsignedChar(data[i]) + b1: t.CUnsignedChar = 0 + b2: t.CUnsignedChar = 0 + if i + 1 < length: + b1 = t.CUnsignedChar(data[i + 1]) + if i + 2 < length: + b2 = t.CUnsignedChar(data[i + 2]) + m: t.CUnsignedInt = (t.CUnsignedInt(b0) << 16) | (t.CUnsignedInt(b1) << 8) | t.CUnsignedInt(b2) + out[oi] = UU_CHARS[(m >> 18) & 0x3F] + oi += 1 + out[oi] = UU_CHARS[(m >> 12) & 0x3F] + oi += 1 + out[oi] = UU_CHARS[(m >> 6) & 0x3F] + oi += 1 + out[oi] = UU_CHARS[m & 0x3F] + oi += 1 + out[oi] = '\n' + oi += 1 + out[oi] = '\0' + return out + +def a2b_uu(data: str) -> str: + if not data or data[0] == ' ' or data[0] == '`': return None + length: t.CInt = t.CInt(data[0]) - 32 + if length < 0 or length > 45: return None + out: str = str(stdlib.malloc(length + 1)) + if not out: return None + oi: t.CInt = 0 + i: t.CInt = 1 + while oi < length: + v0: t.CInt = data[i] - 32 + v1: t.CInt = data[i + 1] - 32 + v2: t.CInt = data[i + 2] - 32 + v3: t.CInt = data[i + 3] - 32 + if v0 < 0 or v0 > 63: v0 = 0 + if v1 < 0 or v1 > 63: v1 = 0 + if v2 < 0 or v2 > 63: v2 = 0 + if v3 < 0 or v3 > 63: v3 = 0 + m: t.CUnsignedInt = (t.CUnsignedInt(v0) << 18) | (t.CUnsignedInt(v1) << 12) | (t.CUnsignedInt(v2) << 6) | t.CUnsignedInt(v3) + if oi < length: + out[oi] = t.CChar((m >> 16) & 0xFF) + oi += 1 + if oi < length: + out[oi] = t.CChar((m >> 8) & 0xFF) + oi += 1 + if oi < length: + out[oi] = t.CChar(m & 0xFF) + oi += 1 + i += 4 + out[oi] = '\0' + return out + +def b2a_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]: + if not data or length != 3: + return None, crc + out: str = str(stdlib.malloc(5)) + if not out: + return None, crc + # 3字节 → 4字节 HQX + m: t.CUnsignedInt = (t.CUnsignedChar(data[0]) << 16) | (t.CUnsignedChar(data[1]) << 8) | t.CUnsignedChar(data[2]) + out[0] = HQX_CHARS[(m >> 18) & 0x3F] + out[1] = HQX_CHARS[(m >> 12) & 0x3F] + out[2] = HQX_CHARS[(m >> 6) & 0x3F] + out[3] = HQX_CHARS[m & 0x3F] + out[4] = '\0' + # CRC 初始化 + 正确计算 + s: t.CUnsignedShort = crc + for i in range(3): + byte: t.CUnsignedChar = t.CUnsignedChar(data[i]) + s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF] + return out, s + + +def a2b_hqx(data: str, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]: + if not data: + return None, crc + # 检查字符是否有效 + for i in range(4): + cchar: t.CUnsignedChar = t.CUnsignedChar(data[i]) + if HQX_VALS[cchar] < 0: + return None, crc + # 解码 + m: t.CUnsignedInt = 0 + for i in range(4): + m = (m << 6) | t.CUnsignedInt(HQX_VALS[t.CUnsignedChar(data[i])]) + out: str = str(stdlib.malloc(4)) + if not out: + return None, crc + out[0] = t.CChar((m >> 16) & 0xFF) + out[1] = t.CChar((m >> 8) & 0xFF) + out[2] = t.CChar(m & 0xFF) + out[3] = '\0' + # CRC 初始化 + 正确计算 + s: t.CUnsignedShort = crc + for i in range(3): + byte: t.CUnsignedChar = t.CUnsignedChar(out[i]) + s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF] + return out, s + +def adler32(data: str, length: t.CInt, adler: t.CUnsignedInt) -> t.CUnsignedInt: + a: t.CUnsignedInt = adler & 0xFFFF + b: t.CUnsignedInt = (adler >> 16) & 0xFFFF + i: t.CInt + for i in range(length): + a = (a + t.CUnsignedChar(data[i])) % 65521 + b = (b + a) % 65521 + return (b << 16) | a diff --git a/builtins.vp b/builtins.vp new file mode 100644 index 0000000..5296c61 --- /dev/null +++ b/builtins.vp @@ -0,0 +1,13 @@ +import t + +# ============================================================ +# 内置函数(Python 语义,自动与 builtins 关联,无需显式 import) +# ord: 字符 → ASCII 码(int) +# chr: ASCII 码 → 字符(t.CChar) +# ============================================================ + +def ord(s: t.CChar) -> int: + return s + +def chr(i: int) -> t.CChar: + return i diff --git a/condition.vp b/condition.vp new file mode 100644 index 0000000..96b7d9e --- /dev/null +++ b/condition.vp @@ -0,0 +1,52 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import ( + CRITICAL_SECTION, + InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, + InitializeConditionVariable, SleepConditionVariableCS, + WakeConditionVariable, WakeAllConditionVariable +) + + +class Condition: + """Windows condition variable backed primitive, internally bundled with CRITICAL_SECTION. + + Usage: + cond: Condition = Condition() + with cond: + while not ready: + cond.wait() + cond.notify() + """ + cond_var: VOIDPTR + cs: CRITICAL_SECTION + + def __init__(self): + InitializeCriticalSection(c.Addr(self.cs)) + InitializeConditionVariable(c.Addr(self.cond_var)) + + def wait(self, timeout_ms: ULONG = INFINITE) -> BOOL: + return SleepConditionVariableCS(c.Addr(self.cond_var), c.Addr(self.cs), timeout_ms) + + def notify(self): + WakeConditionVariable(c.Addr(self.cond_var)) + + def notify_all(self): + WakeAllConditionVariable(c.Addr(self.cond_var)) + + def acquire(self): + EnterCriticalSection(c.Addr(self.cs)) + + def release(self): + LeaveCriticalSection(c.Addr(self.cs)) + + def __enter__(self) -> 'Condition' | t.CPtr: + self.acquire() + return self + + def __exit__(self): + self.release() + + def delete(self): + DeleteCriticalSection(c.Addr(self.cs)) diff --git a/ctraits.vpi b/ctraits.vpi new file mode 100644 index 0000000..52da5b9 --- /dev/null +++ b/ctraits.vpi @@ -0,0 +1,19 @@ +"""ctraits — Compile-time type trait library + +Provides compile-time type predicates with no runtime code generated. +All functions are evaluated exclusively at compile time and can be combined with conditional compilation constructs such as c.CIf. +""" +import t + +def isptr(x: t.CType) -> bool: + """Compile-time predicate to determine whether the type of x is a pointer. + + Returns True if x is a pointer type (ptr_count > 0); otherwise returns False. + Can be used alongside c.CIf to implement conditional compilation. + + Example: + if c.CIf(ctraits.isptr(my_var)): + # This branch compiles only when my_var is a pointer type + ... + """ + pass \ No newline at end of file diff --git a/event.vp b/event.vp new file mode 100644 index 0000000..103d51b --- /dev/null +++ b/event.vp @@ -0,0 +1,36 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import CreateEventA, SetEvent, ResetEvent, WaitForSingleObject + + +@t.Object +class Event: + """Windows Event-based event object, supports manual-reset and auto-reset modes. + + Usage: + evt: Event = Event(FALSE, FALSE) + evt.set() + evt.wait() + """ + handle: HANDLE + manual_reset: BOOL + + def __init__(self, manual_reset: BOOL = FALSE, initial_state: BOOL = FALSE): + self.manual_reset = manual_reset + self.handle = CreateEventA(NULL, manual_reset, initial_state, NULL) + + def set(self): + SetEvent(self.handle) + + def clear(self): + ResetEvent(self.handle) + + def is_set(self) -> BOOL: + return WaitForSingleObject(self.handle, 0) == WAIT_OBJECT_0 + + def wait(self, timeout_ms: ULONG = INFINITE) -> BOOL: + return WaitForSingleObject(self.handle, timeout_ms) == WAIT_OBJECT_0 + + def close(self): + CloseHandle(self.handle) diff --git a/hashlib/__init__.vp b/hashlib/__init__.vp new file mode 100644 index 0000000..3ee2214 --- /dev/null +++ b/hashlib/__init__.vp @@ -0,0 +1,4 @@ +from .__md5 import md5, MD5_DIGEST_LEN +from .__sha1 import sha1, SHA1_DIGEST_LEN +from .__sha256 import sha256, SHA256_DIGEST_LEN +from .__sha512 import sha512, SHA512_DIGEST_LEN diff --git a/hashlib/__md5.vp b/hashlib/__md5.vp new file mode 100644 index 0000000..d98680f --- /dev/null +++ b/hashlib/__md5.vp @@ -0,0 +1,132 @@ +import string +import t, c + + +# ============================================== +# MD5 hash algorithm +# ============================================== +MD5_BLOCK_LEN: t.CDefine = 64 # Group block size +MD5_DIGEST_LEN: t.CDefine = 16 # Digest output length + +# MD5 four-round nonlinear functions +def md5_F(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) | (~x & z) +def md5_G(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & z) | (y & ~z) +def md5_H(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return x ^ y ^ z +def md5_I(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return y ^ (x | ~z) +# Circular left shift +def md5_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) + +# MD5 constant table +md5_T: t.CArray[t.CUInt32T, 64] = [ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 +] + +md5_S: t.CArray[t.CInt, 64] = [ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 +] + +# MD5 context structure +# ============================================================ +@t.Object +class md5: + state: t.CArray[t.CUInt32T, 4] # 4 32-bit state registers + count: t.CUInt64T # processed bits + buf: t.CArray[t.CUInt8T, MD5_BLOCK_LEN] # Group buffer + # Initialize MD5 context + def __init__(self): + string.memset(self.buf, 0, MD5_BLOCK_LEN) + self.state[0] = 0x67452301 + self.state[1] = 0xefcdab89 + self.state[2] = 0x98badcfe + self.state[3] = 0x10325476 + self.count = 0 + # MD5 single-group compression transform + def transform(self, block: t.CUInt8T | t.CPtr): + a: t.CUInt32T = self.state[0] + b: t.CUInt32T = self.state[1] + c: t.CUInt32T = self.state[2] + d: t.CUInt32T = self.state[3] + w: t.CArray[t.CUInt32T, 16] + # Byte order 32-bit words + for i in range(16): + w[i] = ((t.CUInt32T(block[i * 4 + 0]) << 0) | + (t.CUInt32T(block[i * 4 + 1]) << 8) | + (t.CUInt32T(block[i * 4 + 2]) << 16) | + (t.CUInt32T(block[i * 4 + 3]) << 24)) + # 4-round 51 iterations + for i in range(16): + tmp: t.CUInt32T = md5_F(b, c, d) + a + md5_T[i] + w[i] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + # 4-round 51 iterations + for i in range(16, 32): + tmp: t.CUInt32T = md5_G(b, c, d) + a + md5_T[i] + w[(5 * i + 1) % 16] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + for i in range(32, 48): + tmp: t.CUInt32T = md5_H(b, c, d) + a + md5_T[i] + w[(3 * i + 5) % 16] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + for i in range(48, 64): + tmp: t.CUInt32T = md5_I(b, c, d) + a + md5_T[i] + w[(7 * i + 0) % 16] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + # Accumulate to state registers + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + # Batch input data + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CSizeT = self.count % MD5_BLOCK_LEN + self.count += length + if idx > 0: + left: t.CSizeT = MD5_BLOCK_LEN - idx + if length >= left: + string.memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= MD5_BLOCK_LEN: + self.transform(data) + data += MD5_BLOCK_LEN + length -= MD5_BLOCK_LEN + if length > 0: + string.memcpy(self.buf + idx, data, length) + # End calculation, output 16-byte digest + def final(self, out: t.CArray[t.CUInt8T, MD5_DIGEST_LEN]): + idx: t.CSizeT = self.count % MD5_BLOCK_LEN + # Pad 0x80 end + self.buf[idx] = 0x80 + idx += 1 + # If space is not enough, compress once + if idx > MD5_BLOCK_LEN - 8: + string.memset(self.buf + idx, 0, MD5_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + # Pad 0 to end 8 bytes + string.memset(self.buf + idx, 0, MD5_BLOCK_LEN - 8 - idx) + # Write total bit count + bits: t.CUInt64T = self.count << 3 + for i in range(8): + self.buf[MD5_BLOCK_LEN - 8 + i] = (bits >> (i * 8)) & 0xFF + self.transform(self.buf) + # State registers to little-endian byte output output + for i in range(4): + out[i * 4 + 0] = (self.state[i] >> 0) & 0xFF + out[i * 4 + 1] = (self.state[i] >> 8) & 0xFF + out[i * 4 + 2] = (self.state[i] >> 16) & 0xFF + out[i * 4 + 3] = (self.state[i] >> 24) & 0xFF diff --git a/hashlib/__sha1.vp b/hashlib/__sha1.vp new file mode 100644 index 0000000..fdd28ae --- /dev/null +++ b/hashlib/__sha1.vp @@ -0,0 +1,120 @@ +import string +import t, c + + + +# ============================================== +# SHA1 Hash Algorithm +# ============================================== +SHA1_BLOCK_LEN: t.CDefine = 64 +SHA1_DIGEST_LEN: t.CDefine = 20 + +def sha1_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) +# 3-round logical functions +def sha1_f1(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (~b & d) +def sha1_f2(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return b ^ c ^ d +def sha1_f3(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (b & d) | (c & d) + +# SHA1 Context +@t.Object +class sha1: + state: t.CArray[t.CUInt32T, 5] + count: t.CUInt64T + buf: t.CArray[t.CUInt8T, SHA1_BLOCK_LEN] + def __init__(self): + memset(self.buf, 0, SHA1_BLOCK_LEN) + self.state[0] = 0x67452301 + self.state[1] = 0xefcdab89 + self.state[2] = 0x98badcfe + self.state[3] = 0x10325476 + self.state[4] = 0xc3d2e1f0 + self.count = 0 + # Single-group compression transform + def transform(self, block: t.CUInt8T | t.CPtr): + w: t.CArray[t.CUInt32T, 80] + data: t.CUInt8T | t.CPtr = block + # First 16 words + for i in range(16): + w[i] = (((t.CUInt32T(data[i * 4 + 0])) << 24) | + ((t.CUInt32T(data[i * 4 + 1])) << 16) | + ((t.CUInt32T(data[i * 4 + 2])) << 8) | + ((t.CUInt32T(data[i * 4 + 3])) << 0)) + # Extend to 80 words + for i in range(16, 80): + w[i] = sha1_rotl(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16],1) + a: t.CUInt32T = self.state[0] + b: t.CUInt32T = self.state[1] + c: t.CUInt32T = self.state[2] + d: t.CUInt32T = self.state[3] + e: t.CUInt32T = self.state[4] + k: t.CUInt32T + tmp: t.CUInt32T + # 4-round iterations + for i in range(0, 20): + k = 0x5a827999 + tmp = sha1_rotl(a,5) + sha1_f1(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + for i in range(20, 40): + k = 0x6ed9eba1 + tmp = sha1_rotl(a,5) + sha1_f2(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + for i in range(40, 60): + k = 0x8f1bbcdc + tmp = sha1_rotl(a,5) + sha1_f3(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + for i in range(60, 80): + k = 0xca62c1d6 + tmp = sha1_rotl(a,5) + sha1_f2(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + self.state[4] += e + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CSizeT = self.count % SHA1_BLOCK_LEN + self.count += length + if idx > 0: + left: t.CSizeT = SHA1_BLOCK_LEN - idx + if length >= left: + string.memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= SHA1_BLOCK_LEN: + self.transform(data) + data += SHA1_BLOCK_LEN + length -= SHA1_BLOCK_LEN + if length > 0: + string.memcpy(self.buf + idx, data, length) + def final(self, out: t.CArray[t.CUInt8T, SHA1_DIGEST_LEN]): + idx: t.CSizeT = self.count % SHA1_BLOCK_LEN + self.buf[idx] = 0x80 + idx += 1 + if idx > SHA1_BLOCK_LEN - 8: + memset(self.buf + idx, 0, SHA1_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + memset(self.buf + idx,0,SHA1_BLOCK_LEN-8-idx) + bits: t.CUInt64T = self.count << 3 + # SHA1 big-endian write length + for i in range(8): + self.buf[SHA1_BLOCK_LEN - 8 + i] = (bits >> (56 - i * 8)) & 0xFF + self.transform(self.buf) + # State registers to big-endian byte output output output + for i in range(5): + out[i * 4 + 0] = (self.state[i] >> 24) & 0xFF + out[i * 4 + 1] = (self.state[i] >> 16) & 0xFF + out[i * 4 + 2] = (self.state[i] >> 8) & 0xFF + out[i * 4 + 3] = (self.state[i] >> 0) & 0xFF diff --git a/hashlib/__sha256.vp b/hashlib/__sha256.vp new file mode 100644 index 0000000..4330bd5 --- /dev/null +++ b/hashlib/__sha256.vp @@ -0,0 +1,124 @@ +import t, c +import string + + +# ============================================== +# SHA256 Hash Algorithm +# ============================================== +SHA256_BLOCK_LEN: t.CDefine = 64 +SHA256_DIGEST_LEN: t.CDefine = 32 + +# SHA256 Constants K +sha256_K: t.CArray[t.CUInt32T, 64] = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +] + +# SHA256 Auxiliary Functions +def s0(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ ((x >> 3)) +def s1(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ ((x >> 10)) +def S0(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) +def S1(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) +def Ch(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) ^ (~x & z) +def Maj(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) ^ (x & z) ^ (y & z) + +# SHA256 Context +@t.Object +class sha256: + state: t.CArray[t.CUInt32T, 8] + count: t.CUInt64T + buf: t.CArray[t.CUInt8T, SHA256_BLOCK_LEN] + def __init__(self): + string.memset(self, 0, sha256.__sizeof__()) + self.state[0] = 0x6a09e667 + self.state[1] = 0xbb67ae85 + self.state[2] = 0x3c6ef372 + self.state[3] = 0xa54ff53a + self.state[4] = 0x510e527f + self.state[5] = 0x9b05688c + self.state[6] = 0x1f83d9ab + self.state[7] = 0x5be0cd19 + self.count = 0 + # string.memset(self.buf, 0, SHA256_BLOCK_LEN) + # SHA256 single-group compression transform + def transform(self, block: t.CUInt8T | t.CPtr): + w: t.CArray[t.CUInt32T, 64] + for i in range(16): + w[i] = ((t.CUInt32T(block[i * 4 + 0]) << 24) | + (t.CUInt32T(block[i * 4 + 1]) << 16) | + (t.CUInt32T(block[i * 4 + 2]) << 8 ) | + (t.CUInt32T(block[i * 4 + 3]) << 0 )) + # Extend to 64 words + for i in range(16, 64): + w[i] = w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2]) + a: t.CUInt32T = self.state[0] + b: t.CUInt32T = self.state[1] + c: t.CUInt32T = self.state[2] + d: t.CUInt32T = self.state[3] + e: t.CUInt32T = self.state[4] + f: t.CUInt32T = self.state[5] + g: t.CUInt32T = self.state[6] + h: t.CUInt32T = self.state[7] + t1: t.CUInt32T + t2: t.CUInt32T + # 64-round iterations + for i in range(64): + t1 = h + S1(e) + Ch(e,f,g) + sha256_K[i] + w[i] + t2 = S0(a) + Maj(a,b,c) + h = g; g = f; f = e + e = d + t1 + d = c; c = b; b = a + a = t1 + t2 + # Accumulate to state registers + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + self.state[4] += e + self.state[5] += f + self.state[6] += g + self.state[7] += h + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CSizeT = self.count % SHA256_BLOCK_LEN + self.count += length + if idx > 0: + left: t.CSizeT = SHA256_BLOCK_LEN - idx + if length >= left: + string.memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= SHA256_BLOCK_LEN: + self.transform(data) + data += SHA256_BLOCK_LEN + length -= SHA256_BLOCK_LEN + if length > 0: + string.memcpy(self.buf + idx, data, length) + def final(self, out: t.CArray[t.CUInt8T, SHA256_DIGEST_LEN]): + idx: t.CSizeT = self.count % SHA256_BLOCK_LEN + self.buf[idx] = 0x80 + idx += 1 + if idx > SHA256_BLOCK_LEN - 8: + string.memset(self.buf + idx, 0, SHA256_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + string.memset(self.buf + idx, 0, SHA256_BLOCK_LEN - 8 - idx) + bits: t.CUInt64T = self.count << 3 + for i in range(8): + self.buf[SHA256_BLOCK_LEN-8+i] = (bits >> (56 - i*8)) & 0xFF + self.transform(self.buf) + # Byte order 32-bit words + for i in range(8): + out[i * 4 + 0] = (self.state[i] >> 24) & 0xFF + out[i * 4 + 1] = (self.state[i] >> 16) & 0xFF + out[i * 4 + 2] = (self.state[i] >> 8) & 0xFF + out[i * 4 + 3] = (self.state[i] >> 0) & 0xFF diff --git a/hashlib/__sha512.vp b/hashlib/__sha512.vp new file mode 100644 index 0000000..cbcec85 --- /dev/null +++ b/hashlib/__sha512.vp @@ -0,0 +1,149 @@ +import t, c +import string + + +# ============================================== +# SHA512 Hash Algorithm +# ============================================== +SHA512_BLOCK_LEN: t.CDefine = 128 +SHA512_DIGEST_LEN: t.CDefine = 64 + +def sha512_ror(x: t.CUInt64T, n: int) -> t.CUInt64T: return (x >> n) | (x << (64 - n)) +def sha512_shr(x: t.CUInt64T, n: int) -> t.CUInt64T: return x >> n +def sha512_Ch (x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (~x & z) +def sha512_Maj(x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (x & z) ^ (y & z) +def sha512_BigSigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 28) ^ sha512_ror(x, 34) ^ sha512_ror(x, 39) +def sha512_BigSigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 14) ^ sha512_ror(x, 18) ^ sha512_ror(x, 41) +def sha512_Sigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 1) ^ sha512_ror(x, 8) ^ sha512_shr(x, 7) +def sha512_Sigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 19) ^ sha512_ror(x, 61) ^ sha512_shr(x, 6) + +sha512_K: t.CArray[t.CUInt64T, 80] = [ + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 +] + +@t.Object +class sha512: + state: t.CArray[t.CUInt64T, 8] + count: t.CArray[t.CUInt64T, 2] + buf: t.CArray[t.CUInt8T, SHA512_BLOCK_LEN] + def __init__(self): + string.memset(self, 0, sha512.__sizeof__()) + self.state[0] = 0x6a09e667f3bcc908 + self.state[1] = 0xbb67ae8584caa73b + self.state[2] = 0x3c6ef372fe94f82b + self.state[3] = 0xa54ff53a5f1d36f1 + self.state[4] = 0x510e527fade682d1 + self.state[5] = 0x9b05688c2b3e6c1f + self.state[6] = 0x1f83d9abfb41bd6b + self.state[7] = 0x5be0cd19137e2179 + def transform(self, block: t.CArray[t.CUInt8T, SHA512_BLOCK_LEN]): + w: t.CArray[t.CUInt64T, 80] + a: t.CUInt64T + b: t.CUInt64T + c: t.CUInt64T + d: t.CUInt64T + e: t.CUInt64T + f: t.CUInt64T + g: t.CUInt64T + h: t.CUInt64T + t1: t.CUInt64T + t2: t.CUInt64T + for i in range(16): + w[i] = t.CUInt64T(block[i * 8 + 0]) << 56 + w[i] |= t.CUInt64T(block[i * 8 + 1]) << 48 + w[i] |= t.CUInt64T(block[i * 8 + 2]) << 40 + w[i] |= t.CUInt64T(block[i * 8 + 3]) << 32 + w[i] |= t.CUInt64T(block[i * 8 + 4]) << 24 + w[i] |= t.CUInt64T(block[i * 8 + 5]) << 16 + w[i] |= t.CUInt64T(block[i * 8 + 6]) << 8 + w[i] |= t.CUInt64T(block[i * 8 + 7]) << 0 + for i in range(16, 80): + w[i] = sha512_Sigma1(w[i-2]) + w[i-7] + sha512_Sigma0(w[i-15]) + w[i-16] + a = self.state[0] + b = self.state[1] + c = self.state[2] + d = self.state[3] + e = self.state[4] + f = self.state[5] + g = self.state[6] + h = self.state[7] + for i in range(80): + t1 = h + sha512_BigSigma1(e) + sha512_Ch(e, f, g) + sha512_K[i] + w[i] + t2 = sha512_BigSigma0(a) + sha512_Maj(a, b, c) + h = g; g = f; f = e + e = d + t1 + d = c; c = b; b = a + a = t1 + t2 + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + self.state[4] += e + self.state[5] += f + self.state[6] += g + self.state[7] += h + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CUInt32T = t.CUInt32T(self.count[0] % SHA512_BLOCK_LEN) + self.count[0] += length + if self.count[0] < length: + self.count[1] += 1 + if idx > 0: + left: t.CSizeT = SHA512_BLOCK_LEN - idx + if length >= left: + string.memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= SHA512_BLOCK_LEN: + self.transform(data) + data += SHA512_BLOCK_LEN + length -= SHA512_BLOCK_LEN + if length > 0: + string.memcpy(self.buf + idx, data, length) + def final(self, out: t.CArray[t.CUInt8T, SHA512_DIGEST_LEN]): + bits_lo: t.CUInt64T = self.count[0] << 3 + bits_hi: t.CUInt64T = (self.count[1] << 3) | (self.count[0] >> 61) + idx: t.CUInt32T = t.CUInt32T(self.count[0] % SHA512_BLOCK_LEN) + self.buf[idx] = 0x80 + idx += 1 + if idx > SHA512_BLOCK_LEN - 16: + string.memset(self.buf + idx, 0, SHA512_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + string.memset(self.buf + idx, 0, SHA512_BLOCK_LEN - 16 - idx) + for i in range(8): + self.buf[SHA512_BLOCK_LEN - 16 + i] = t.CUInt8T(bits_hi >> (56 - i * 8)) + for i in range(8): + self.buf[SHA512_BLOCK_LEN - 8 + i] = t.CUInt8T(bits_lo >> (56 - i * 8)) + self.transform(self.buf) + for i in range(8): + out[i * 8 + 0] = t.CUInt8T(self.state[i] >> 56) + out[i * 8 + 1] = t.CUInt8T(self.state[i] >> 48) + out[i * 8 + 2] = t.CUInt8T(self.state[i] >> 40) + out[i * 8 + 3] = t.CUInt8T(self.state[i] >> 32) + out[i * 8 + 4] = t.CUInt8T(self.state[i] >> 24) + out[i * 8 + 5] = t.CUInt8T(self.state[i] >> 16) + out[i * 8 + 6] = t.CUInt8T(self.state[i] >> 8) + out[i * 8 + 7] = t.CUInt8T(self.state[i] >> 0) diff --git a/hashtable.vp b/hashtable.vp new file mode 100644 index 0000000..99a190f --- /dev/null +++ b/hashtable.vp @@ -0,0 +1,242 @@ +# hashtable - Open-addressing hash table library +# Linear probing for collision resolution, supports auto-resizing and tombstone deletion +# Key type fixed as str (i8*), value type is void* (generic pointer) +import t, c +import string +import memhub +import stdio +from stdint import * + +# Empty slot marker (hash == 0) +_HT_EMPTY: t.CDefine = 0 +# Tombstone slot marker (hash == 1) +_HT_TOMBSTONE: t.CDefine = 1 +# Default initial capacity (must be power of two) +_HT_INIT_CAP: t.CDefine = 16 +# Slot memory layout: hash(8) + key pointer(8) + value pointer(8) = 24 bytes +_HT_SLOT_SIZE: t.CDefine = 24 +# FNV-1a 64-bit constants +_FNV_OFFSET: t.CUInt64T = 0xcbf29ce484222325 +_FNV_PRIME: t.CUInt64T = 0x100000001b3 + + +def _fnv1a_hash(key: str) -> t.CUInt64T: + """FNV-1a 64-bit hash function.""" + h: t.CUInt64T = _FNV_OFFSET + k: str = key + while k[0] != 0: + h = h ^ t.CUInt64T(k[0]) + h = h * _FNV_PRIME + k += 1 + # Ensure h >= 2 (avoids empty slot marker 0 and tombstone marker 1) + if h < 2: + h = 2 + return h + + +class HashTable: + """Open-addressing hash table using linear probing for collision resolution. + + Key type fixed as str (i8*), value type is void* (generic pointer). + Memory is managed via the mbuddy allocator. Automatically resizes when load factor exceeds 0.75. + + Usage: + mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size) + ht: HashTable = HashTable(mb) + ht.set_int("x", 42) + p: t.CPtr = ht["x"] + v: int = c.Deref(p) + """ + __slots__: t.CVoid | t.CPtr # Base address of slot array + __count__: t.CSizeT = 0 # Number of occupied entries + __capacity__: t.CSizeT = 16 # Total slot count (power of two) + __tombstones__: t.CSizeT = 0 # Tombstone entry count + __mbuddy__: memhub.MemBuddy | t.CPtr + __iter_index__: t.CSizeT = 0 + + def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: + # Heap-allocate HashTable object (6 fields × 8 bytes = 48 bytes) + return mb.alloc(48) + + def __init__(self, mb: memhub.MemBuddy | t.CPtr): + self.__mbuddy__ = mb + self.__capacity__ = _HT_INIT_CAP + self.__count__ = 0 + self.__tombstones__ = 0 + self.__slots__ = mb.alloc(self.__capacity__ * _HT_SLOT_SIZE) + # Initialize all slots to empty (hash = 0) + string.memset(self.__slots__, 0, self.__capacity__ * _HT_SLOT_SIZE) + + def _slot_hash(self, idx: t.CSizeT) -> t.CUInt64T: + """Read hash value from target slot.""" + ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) + return ptr[0] + + def _slot_key(self, idx: t.CSizeT) -> str: + """Read key pointer from target slot.""" + ptr: str | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 8) + return ptr[0] + + def _slot_value(self, idx: t.CSizeT) -> t.CPtr: + """Read value pointer from target slot.""" + ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 16) + return ptr[0] + + def _set_slot(self, idx: t.CSizeT, h: t.CUInt64T, key: str, val: t.CPtr): + """Assign three fields of the target slot.""" + h_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) + h_ptr[0] = h + k_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 8) + k_ptr[0] = key + v_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 16) + v_ptr[0] = val + + def _find_slot(self, key: str, h: t.CUInt64T) -> t.CSizeT: + """Locate slot index for key insertion or lookup. + + Returns: Index of matching key if found; otherwise returns index of first usable empty/tombstone slot. + """ + mask: t.CSizeT = self.__capacity__ - 1 + idx: t.CSizeT = t.CSizeT(h) & mask + first_tombstone: t.CSizeT = self.__capacity__ + i: t.CSizeT = 0 + while i < self.__capacity__: + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY: + if first_tombstone < self.__capacity__: + return first_tombstone + return idx + if sh == _HT_TOMBSTONE: + if first_tombstone >= self.__capacity__: + first_tombstone = idx + else: + if sh == h: + sk: str = self._slot_key(idx) + if string.strcmp(sk, key) == 0: + return idx + idx = (idx + 1) & mask + i += 1 + if first_tombstone < self.__capacity__: + return first_tombstone + return self.__capacity__ + + def _resize(self, new_cap: t.CSizeT): + """Resize table and rehash all entries.""" + old_slots: t.CVoid | t.CPtr = self.__slots__ + old_cap: t.CSizeT = self.__capacity__ + new_slots: t.CVoid | t.CPtr = self.__mbuddy__.alloc(new_cap * _HT_SLOT_SIZE) + if new_slots == None: + return + string.memset(new_slots, 0, new_cap * _HT_SLOT_SIZE) + self.__slots__ = new_slots + self.__capacity__ = new_cap + self.__count__ = 0 + self.__tombstones__ = 0 + i: t.CSizeT = 0 + while i < old_cap: + old_h_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE) + h: t.CUInt64T = old_h_ptr[0] + if h != _HT_EMPTY and h != _HT_TOMBSTONE: + old_k_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE + 8) + old_v_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE + 16) + k: str = old_k_ptr[0] + v: t.CPtr = old_v_ptr[0] + idx: t.CSizeT = self._find_slot(k, h) + self._set_slot(idx, h, k, v) + self.__count__ += 1 + i += 1 + + def __setitem__(self, key: str, val: t.CNeedPtr): + """Insert or update key-value pair. val automatically decays to pointer (t.CNeedPtr: no conversion if already pointer).""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + if sh == _HT_TOMBSTONE: + self.__tombstones__ -= 1 + self._set_slot(idx, h, key, val) + self.__count__ += 1 + # Resize when load factor > 0.75 + load: t.CSizeT = self.__count__ + self.__tombstones__ + if load * 4 >= self.__capacity__ * 3: + self._resize(self.__capacity__ * 2) + else: + self._set_slot(idx, h, key, val) + + def __getitem__(self, key: str) -> t.CPtr: + """Lookup key and return value pointer. Returns None if key not found.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return None + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return None + v: t.CPtr = self._slot_value(idx) + return v + + def __contains__(self, key: str) -> t.CInt: + """Check whether key exists in table.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return 0 + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return 0 + return 1 + + def __delitem__(self, key: str) -> t.CInt: + """Delete entry by key. Return 1 on success, 0 if key not present.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return 0 + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return 0 + h_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) + h_ptr[0] = _HT_TOMBSTONE + self.__count__ -= 1 + self.__tombstones__ += 1 + return 1 + + def __len__(self) -> t.CSizeT: + return self.__count__ + + def __iter__(self) -> HashTable | t.CPtr: + self.__iter_index__ = 0 + return self + + def __next__(self) -> str: + while self.__iter_index__ < self.__capacity__: + idx: t.CSizeT = self.__iter_index__ + self.__iter_index__ = idx + 1 + sh: t.CUInt64T = self._slot_hash(idx) + if sh != _HT_EMPTY and sh != _HT_TOMBSTONE: + return self._slot_key(idx) + raise StopIteration + + def get(self, key: str, default: t.CPtr) -> t.CPtr: + """Return value pointer; return default pointer if key not found.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return default + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return default + return self._slot_value(idx) + + def set_int(self, key: str, val: int): + """Store integer value. Value is copied into mbuddy-managed storage.""" + storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8) + int_ptr: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + int_ptr[0] = val + self[key] = storage + + def set_str(self, key: str, val: str): + """Store string value. Directly store the string pointer.""" + self[key] = val diff --git a/hello.vp b/hello.vp new file mode 100644 index 0000000..248bb67 --- /dev/null +++ b/hello.vp @@ -0,0 +1,5 @@ +import stdio + + +def helloworld(): + stdio.printf("Hello, world!\n") diff --git a/json/__init__.vp b/json/__init__.vp new file mode 100644 index 0000000..b937cea --- /dev/null +++ b/json/__init__.vp @@ -0,0 +1,237 @@ +import t, c +from stdint import * +import memhub +import string +import viperio + +# ============================================================ +# JSON 值类型枚举 +# ============================================================ +JSON_NULL: t.CDefine = 0 +JSON_BOOL: t.CDefine = 1 +JSON_INT: t.CDefine = 2 +JSON_FLOAT: t.CDefine = 3 +JSON_STRING: t.CDefine = 4 +JSON_ARRAY: t.CDefine = 5 +JSON_OBJECT: t.CDefine = 6 + + +# ============================================================ +# JsonValue - JSON 值节点 +# 使用 mpool 分配:JsonValue(pool) 从池中分配内存 +# ============================================================ +class JsonValue: + vtype: t.CInt + bool_val: t.CInt + int_val: t.CInt64T + float_val: t.CDouble + str_val: t.CChar | t.CPtr + next: 'JsonValue' | t.CPtr + key: t.CChar | t.CPtr + child: 'JsonValue' | t.CPtr + child_count: t.CSizeT + + def __new__(self, pool: memhub.MemManager | t.CPtr): + """从 mpool 分配 JsonValue 结构体内存并零初始化""" + ptr: JsonValue | t.CPtr = pool.alloc(JsonValue.__sizeof__()) + if ptr: + string.memset(ptr, 0, JsonValue.__sizeof__()) + return ptr + + def type(self) -> t.CInt: + return self.vtype + + def is_null(self) -> bool: + return self.vtype == JSON_NULL + + def is_bool(self) -> bool: + return self.vtype == JSON_BOOL + + def is_int(self) -> bool: + return self.vtype == JSON_INT + + def is_float(self) -> bool: + return self.vtype == JSON_FLOAT + + def is_string(self) -> bool: + return self.vtype == JSON_STRING + + def is_array(self) -> bool: + return self.vtype == JSON_ARRAY + + def is_object(self) -> bool: + return self.vtype == JSON_OBJECT + + def as_bool(self) -> bool: + return self.bool_val != 0 + + def as_int(self) -> t.CInt64T: + return self.int_val + + def as_float(self) -> t.CDouble: + return self.float_val + + def as_string(self) -> t.CChar | t.CPtr: + return self.str_val + + def __len__(self) -> t.CSizeT: + return self.child_count + + def __getitem__(self, key: t.CChar | t.CPtr) -> 'JsonValue' | t.CPtr: + """Python风格取值:v["key"] 取对象字段""" + if self.vtype != JSON_OBJECT: + return None + if key == None: + return None + cur: JsonValue | t.CPtr = self.child + while cur != None: + if cur.key != None: + if string.strcmp(cur.key, key) == 0: + return cur + cur = cur.next + return None + + def __setitem__(self, key: t.CChar | t.CPtr, val: 'JsonValue' | t.CPtr): + """Python风格赋值:v["key"] = val""" + if self.vtype != JSON_OBJECT or key == None or val == None: + return + cur: JsonValue | t.CPtr = self.child + while cur != None: + if cur.key != None: + if string.strcmp(cur.key, key) == 0: + cur.vtype = val.vtype + cur.bool_val = val.bool_val + cur.int_val = val.int_val + cur.float_val = val.float_val + cur.str_val = val.str_val + cur.child = val.child + cur.child_count = val.child_count + return + cur = cur.next + # key 不存在,追加新子节点 + klen: t.CSizeT = string.strlen(key) + kbuf: t.CChar | t.CPtr = self._pool_alloc(klen + 1) + if kbuf != None: + string.memcpy(kbuf, key, klen + 1) + val.key = kbuf + self._append_child(val) + + def get_item(self, index: t.CSizeT) -> 'JsonValue' | t.CPtr: + """按索引取数组元素:v.get_item(0)""" + if self.vtype != JSON_ARRAY and self.vtype != JSON_OBJECT: + return None + cur: JsonValue | t.CPtr = self.child + i: t.CSizeT = 0 + while cur != None: + if i == index: + return cur + cur = cur.next + i += 1 + return None + + def _pool_alloc(self, size: t.CSizeT) -> t.CChar | t.CPtr: + """内部方法:从当前对象的 mpool 分配内存(预留,暂返回 None)""" + return None + + def _append_child(self, child: 'JsonValue' | t.CPtr): + if self.child == None: + self.child = child + else: + cur: JsonValue | t.CPtr = self.child + while cur.next != None: + cur = cur.next + cur.next = child + self.child_count += 1 + + +# ============================================================ +# 构造函数:创建各类 JsonValue(从 mpool 分配) +# ============================================================ + +def null(pool: memhub.MemManager | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_NULL + return v + +def bool_val(pool: memhub.MemManager | t.CPtr, val: bool) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_BOOL + v.bool_val = 1 if val else 0 + return v + +def int_val(pool: memhub.MemManager | t.CPtr, val: t.CInt64T) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_INT + v.int_val = val + return v + +def float_val(pool: memhub.MemManager | t.CPtr, val: t.CDouble) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_FLOAT + v.float_val = val + return v + +def string_val(pool: memhub.MemManager | t.CPtr, val: t.CChar | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_STRING + if val != None: + slen: t.CSizeT = string.strlen(val) + buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + if buf != None: + string.memcpy(buf, val, slen + 1) + v.str_val = buf + return v + +def array(pool: memhub.MemManager | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_ARRAY + return v + +def object(pool: memhub.MemManager | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_OBJECT + return v + +# 向数组追加元素 +def array_append(pool: memhub.MemManager | t.CPtr, arr: JsonValue | t.CPtr, item: JsonValue | t.CPtr): + if arr == None or item == None: return + if arr.vtype != JSON_ARRAY: return + arr._append_child(item) + +# 向对象设置键值对 +def object_set(pool: memhub.MemManager | t.CPtr, obj: JsonValue | t.CPtr, key: t.CChar | t.CPtr, val: JsonValue | t.CPtr): + if obj == None or key == None or val == None: return + if obj.vtype != JSON_OBJECT: return + cur: JsonValue | t.CPtr = obj.child + while cur != None: + if cur.key != None: + if string.strcmp(cur.key, key) == 0: + cur.vtype = val.vtype + cur.bool_val = val.bool_val + cur.int_val = val.int_val + cur.float_val = val.float_val + cur.str_val = val.str_val + cur.child = val.child + cur.child_count = val.child_count + return + cur = cur.next + klen: t.CSizeT = string.strlen(key) + kbuf: t.CChar | t.CPtr = pool.alloc(klen + 1) + if kbuf != None: + string.memcpy(kbuf, key, klen + 1) + val.key = kbuf + obj._append_child(val) + + +# ============================================================ +# 导入子模块 +# ============================================================ +from .__parser import parse +from .__writer import write diff --git a/json/__parser.vp b/json/__parser.vp new file mode 100644 index 0000000..2c9a300 --- /dev/null +++ b/json/__parser.vp @@ -0,0 +1,291 @@ +import t, c +from stdint import * +import memhub +import string +from . import ( + JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT, + JSON_STRING, JSON_ARRAY, JSON_OBJECT, + null, bool_val, int_val, float_val, string_val, array, object, +) + + +class ParseState: + src: t.CChar | t.CPtr + pos: t.CSizeT + len: t.CSizeT + pool: memhub.MemManager | t.CPtr + + def __init__(self, src: t.CChar | t.CPtr, pool: memhub.MemManager | t.CPtr): + self.src = src + self.pos = 0 + self.len = string.strlen(src) if src != None else 0 + self.pool = pool + + +def _peek(s: ParseState | t.CPtr) -> t.CChar: + if s.pos >= s.len: + return '\0' + return s.src[s.pos] + +def _advance(s: ParseState | t.CPtr) -> t.CChar: + if s.pos >= s.len: + return '\0' + ch: t.CChar = s.src[s.pos] + s.pos += 1 + return ch + +def _skip_whitespace(s: ParseState | t.CPtr): + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r': + s.pos += 1 + else: + break + +def _expect(s: ParseState | t.CPtr, ch: t.CChar) -> bool: + _skip_whitespace(s) + if s.pos >= s.len: + return False + if s.src[s.pos] != ch: + return False + s.pos += 1 + return True + + +def _parse_string(s: ParseState | t.CPtr) -> t.CChar | t.CPtr: + if _peek(s) != '"': + return None + _advance(s) + + start: t.CSizeT = s.pos + slen: t.CSizeT = 0 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch == '"': + break + if ch == '\\': + s.pos += 1 + slen += 1 + slen += 1 + s.pos += 1 + + buf: t.CChar | t.CPtr = s.pool.alloc(slen + 1) + if buf == None: + return None + + s.pos = start + di: t.CSizeT = 0 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch == '"': + s.pos += 1 + break + if ch == '\\': + s.pos += 1 + if s.pos < s.len: + esc: t.CChar = s.src[s.pos] + if esc == 'n': + buf[di] = '\n' + elif esc == 't': + buf[di] = '\t' + elif esc == 'r': + buf[di] = '\r' + elif esc == '\\': + buf[di] = '\\' + elif esc == '"': + buf[di] = '"' + elif esc == '/': + buf[di] = '/' + else: + buf[di] = esc + di += 1 + s.pos += 1 + continue + buf[di] = ch + di += 1 + s.pos += 1 + + buf[di] = '\0' + return buf + + +def _parse_number(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + _skip_whitespace(s) + is_float: bool = False + start: t.CSizeT = s.pos + + if s.pos < s.len and s.src[s.pos] == '-': + s.pos += 1 + + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch >= '0' and ch <= '9': + s.pos += 1 + else: + break + + if s.pos < s.len and s.src[s.pos] == '.': + is_float = True + s.pos += 1 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch >= '0' and ch <= '9': + s.pos += 1 + else: + break + + if s.pos < s.len and (s.src[s.pos] == 'e' or s.src[s.pos] == 'E'): + is_float = True + s.pos += 1 + if s.pos < s.len and (s.src[s.pos] == '+' or s.src[s.pos] == '-'): + s.pos += 1 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch >= '0' and ch <= '9': + s.pos += 1 + else: + break + + num_len: t.CSizeT = s.pos - start + buf: t.CChar | t.CPtr = s.pool.alloc(num_len + 1) + if buf == None: + return null(s.pool) + + i: t.CSizeT = 0 + while i < num_len: + buf[i] = s.src[start + i] + i += 1 + buf[num_len] = '\0' + + if is_float: + val: t.CDouble = string.atof(buf) + return float_val(s.pool, val) + else: + ival: t.CInt64T = string.atoll(buf) + return int_val(s.pool, ival) + + +def _parse_value(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + _skip_whitespace(s) + if s.pos >= s.len: + return null(s.pool) + + ch: t.CChar = _peek(s) + + if ch == '"': + sv: t.CChar | t.CPtr = _parse_string(s) + return string_val(s.pool, sv) + + if ch == '{': + return _parse_object(s) + + if ch == '[': + return _parse_array(s) + + if ch == '-' or (ch >= '0' and ch <= '9'): + return _parse_number(s) + + if ch == 't': + if s.pos + 3 < s.len: + if s.src[s.pos + 1] == 'r' and s.src[s.pos + 2] == 'u' and s.src[s.pos + 3] == 'e': + s.pos += 4 + return bool_val(s.pool, True) + return null(s.pool) + + if ch == 'f': + if s.pos + 4 < s.len: + if s.src[s.pos + 1] == 'a' and s.src[s.pos + 2] == 'l' and s.src[s.pos + 3] == 's' and s.src[s.pos + 4] == 'e': + s.pos += 5 + return bool_val(s.pool, False) + return null(s.pool) + + if ch == 'n': + if s.pos + 3 < s.len: + if s.src[s.pos + 1] == 'u' and s.src[s.pos + 2] == 'l' and s.src[s.pos + 3] == 'l': + s.pos += 4 + return null(s.pool) + return null(s.pool) + + return null(s.pool) + + +def _parse_array(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + if not _expect(s, '['): + return null(s.pool) + + arr: JsonValue | t.CPtr = array(s.pool) + + _skip_whitespace(s) + if s.pos < s.len and _peek(s) == ']': + _advance(s) + return arr + + item: JsonValue | t.CPtr = _parse_value(s) + arr._append_child(item) + + while True: + _skip_whitespace(s) + if s.pos >= s.len: + break + if _peek(s) != ',': + break + _advance(s) + item = _parse_value(s) + arr._append_child(item) + + _expect(s, ']') + return arr + + +def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + if not _expect(s, '{'): + return null(s.pool) + + obj: JsonValue | t.CPtr = object(s.pool) + + _skip_whitespace(s) + if s.pos < s.len and _peek(s) == '}': + _advance(s) + return obj + + _skip_whitespace(s) + key: t.CChar | t.CPtr = _parse_string(s) + _expect(s, ':') + val: JsonValue | t.CPtr = _parse_value(s) + if key != None and val != None: + klen: t.CSizeT = string.strlen(key) + kbuf: t.CChar | t.CPtr = s.pool.alloc(klen + 1) + if kbuf != None: + string.memcpy(kbuf, key, klen + 1) + val.key = kbuf + obj._append_child(val) + + while True: + _skip_whitespace(s) + if s.pos >= s.len: + break + if _peek(s) != ',': + break + _advance(s) + _skip_whitespace(s) + key = _parse_string(s) + _expect(s, ':') + val = _parse_value(s) + if key != None and val != None: + klen2: t.CSizeT = string.strlen(key) + kbuf2: t.CChar | t.CPtr = s.pool.alloc(klen2 + 1) + if kbuf2 != None: + string.memcpy(kbuf2, key, klen2 + 1) + val.key = kbuf2 + obj._append_child(val) + + _expect(s, '}') + return obj + + +def parse(pool: memhub.MemManager | t.CPtr, src: t.CChar | t.CPtr) -> JsonValue | t.CPtr: + """解析 JSON 字符串,返回 JsonValue 树""" + if src == None: + return null(pool) + s: ParseState | t.CPtr = ParseState(src, pool) + return _parse_value(s) diff --git a/json/__writer.vp b/json/__writer.vp new file mode 100644 index 0000000..4b6435b --- /dev/null +++ b/json/__writer.vp @@ -0,0 +1,119 @@ +import t, c +from stdint import * +import memhub +import string +from stdio import snprintf +from . import ( + JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT, + JSON_STRING, JSON_ARRAY, JSON_OBJECT, +) + + +def _write_char(buf: t.CChar | t.CPtr, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT: + buf[pos] = ch + return pos + 1 + +def _write_str(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: + if s == None: return pos + slen: t.CSizeT = string.strlen(s) + string.memcpy(t.CChar(t.CUInt64T(buf) + pos, t.CPtr), s, slen) + return pos + slen + +def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: + if s == None: + pos = _write_str(buf, pos, "null") + return pos + pos = _write_char(buf, pos, '"') + i: t.CSizeT = 0 + slen: t.CSizeT = string.strlen(s) + while i < slen: + ch: t.CChar = s[i] + if ch == '"': + pos = _write_str(buf, pos, "\\\"") + elif ch == '\\': + pos = _write_str(buf, pos, "\\\\") + elif ch == '\n': + pos = _write_str(buf, pos, "\\n") + elif ch == '\r': + pos = _write_str(buf, pos, "\\r") + elif ch == '\t': + pos = _write_str(buf, pos, "\\t") + else: + pos = _write_char(buf, pos, ch) + i += 1 + pos = _write_char(buf, pos, '"') + return pos + + +def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: memhub.MemManager | t.CPtr) -> t.CSizeT: + if val == None: + pos = _write_str(buf, pos, "null") + return pos + + if val.vtype == JSON_NULL: + pos = _write_str(buf, pos, "null") + + elif val.vtype == JSON_BOOL: + if val.bool_val != 0: + pos = _write_str(buf, pos, "true") + else: + pos = _write_str(buf, pos, "false") + + elif val.vtype == JSON_INT: + tmp: t.CChar | t.CPtr = pool.alloc(32) + if tmp != None: + snprintf(tmp, 32, "%lld", val.int_val) + pos = _write_str(buf, pos, tmp) + + elif val.vtype == JSON_FLOAT: + tmp2: t.CChar | t.CPtr = pool.alloc(32) + if tmp2 != None: + snprintf(tmp2, 32, "%.6g", val.float_val) + pos = _write_str(buf, pos, tmp2) + + elif val.vtype == JSON_STRING: + pos = _write_string_escaped(buf, pos, val.str_val) + + elif val.vtype == JSON_ARRAY: + if val.child == None: + pos = _write_str(buf, pos, "[]") + return pos + pos = _write_char(buf, pos, '[') + cur: JsonValue | t.CPtr = val.child + first: bool = True + while cur != None: + if not first: + pos = _write_char(buf, pos, ',') + pos = _write_value(buf, pos, cur, pool) + first = False + cur = cur.next + pos = _write_char(buf, pos, ']') + + elif val.vtype == JSON_OBJECT: + if val.child == None: + pos = _write_str(buf, pos, "{}") + return pos + pos = _write_char(buf, pos, '{') + cur2: JsonValue | t.CPtr = val.child + first2: bool = True + while cur2 != None: + if not first2: + pos = _write_char(buf, pos, ',') + pos = _write_string_escaped(buf, pos, cur2.key) + pos = _write_char(buf, pos, ':') + pos = _write_value(buf, pos, cur2, pool) + first2 = False + cur2 = cur2.next + pos = _write_char(buf, pos, '}') + + return pos + + +def write(pool: memhub.MemManager | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> t.CChar | t.CPtr: + """将 JsonValue 序列化为 JSON 字符串""" + buf: t.CChar | t.CPtr = pool.alloc(4096) + if buf == None: + return None + end_pos: t.CSizeT = _write_value(buf, 0, val, pool) + buf[end_pos] = '\0' + return buf diff --git a/linkedlist.vp b/linkedlist.vp new file mode 100644 index 0000000..770a6ee --- /dev/null +++ b/linkedlist.vp @@ -0,0 +1,479 @@ +import t, c +from stdint import * + + +# ============================================================ +# LinkedNode: Non-polymorphic base class (@t.NoVTable) +# +# Subclasses inheriting from this class gain standard linked list and tree capabilities: +# - Bidirectional sibling links (next/prev) → O(1) removal +# - Parent-child tree structure (child/last_child/parent) → O(1) child appending +# - Child counter (child_count) +# +# Fields are flattened and embedded into subclasses with no vtable overhead +# (equivalent to non-polymorphic inheritance in C++). +# OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers +# (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. +# +# Usage: +# class MyNode(LinkedNode): +# value: t.CInt +# root: MyNode = MyNode() +# child: MyNode = MyNode() +# root.append(child) # OOP invocation, self = root +# child.detach() # Remove self from sibling chain +# ============================================================ +@t.NoVTable +class LinkedNode: + next: "LinkedNode" | t.CPtr # Next sibling node + prev: "LinkedNode" | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) + child: "LinkedNode" | t.CPtr # First child node + last_child: "LinkedNode" | t.CPtr # Last child node (O(1) append) + parent: "LinkedNode" | t.CPtr # Parent node + child_count: t.CSizeT # Number of child nodes + + def append(self, node: "LinkedNode" | t.CPtr): + """Append node as the last child of self (O(1)). + + If node is already attached to any list, the caller shall invoke node.detach() prior to append. + """ + if self is None or node is None: return + node.parent = self + node.next = None + node.prev = self.last_child + if self.child is None: + self.child = node + else: + self.last_child.next = node + self.last_child = node + self.child_count += 1 + + def prepend(self, node: "LinkedNode" | t.CPtr): + """Insert node as the first child of self (O(1)).""" + if self is None or node is None: return + node.parent = self + node.prev = None + node.next = self.child + if self.child is not None: + self.child.prev = node + else: + self.last_child = node + self.child = node + self.child_count += 1 + + def insert_before(self, node: "LinkedNode" | t.CPtr, + new_node: "LinkedNode" | t.CPtr): + """Insert new_node before node (O(1)). node must be a direct child of self.""" + if self is None or node is None or new_node is None: return + new_node.parent = self + new_node.prev = node.prev + new_node.next = node + if node.prev is not None: + node.prev.next = new_node + else: + self.child = new_node + node.prev = new_node + self.child_count += 1 + + def insert_after(self, node: "LinkedNode" | t.CPtr, + new_node: "LinkedNode" | t.CPtr): + """Insert new_node after node (O(1)). node must be a direct child of self.""" + if self is None or node is None or new_node is None: return + new_node.parent = self + new_node.prev = node + new_node.next = node.next + if node.next is not None: + node.next.prev = new_node + else: + self.last_child = new_node + node.next = new_node + self.child_count += 1 + + def remove_child(self, node: "LinkedNode" | t.CPtr): + """Remove node from self's child linked list (O(1)). The node must be a direct child of self.""" + if self is None or node is None: + return + # Patch prev.next + if node.prev is not None: + node.prev.next = node.next + else: + self.child = node.next + # Patch next.prev + if node.next is not None: + node.next.prev = node.prev + else: + self.last_child = node.prev + # Clear sibling and parent links of node + node.next = None + node.prev = None + node.parent = None + if self.child_count > 0: + self.child_count -= 1 + + def detach(self): + """Detach self from its sibling linked list (O(1)). + + After invocation, self.next/self.prev/self.parent are cleared. The child chain remains untouched. + """ + if self is None: + return + # Patch prev.next + if self.prev is not None: + self.prev.next = self.next + elif self.parent is not None: + self.parent.child = self.next + # Patch next.prev + if self.next is not None: + self.next.prev = self.prev + elif self.parent is not None: + self.parent.last_child = self.prev + # Decrement parent child counter + if self.parent is not None: + if self.parent.child_count > 0: + self.parent.child_count -= 1 + # Clear links of self + self.next = None + self.prev = None + self.parent = None + + def unlink(self): + """Sever all links of self (siblings and parent). Child nodes are not processed recursively. + + After invocation, self becomes an isolated node, while its child chain still references original children + (the parent field of child nodes still points to self). For full isolation, the caller shall + invoke self.remove_child on each child beforehand. + """ + if self is None: + return + # First detach from sibling list + self.detach() + # Then break parent-child links + self.child = None + self.last_child = None + self.child_count = 0 + + def has_children(self) -> t.CInt: + """Return 1 if child nodes exist, otherwise return 0.""" + if self is None: + return 0 + if self.child is not None: + return 1 + return 0 + + def child_at(self, index: t.CSizeT) -> "LinkedNode" | t.CPtr: + """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" + if self is None: + return None + cur: "LinkedNode" | t.CPtr = self.child + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.next + return None + + def count_children(self) -> t.CSizeT: + """Count children by traversal (O(n)), used to validate child_count.""" + if self is None: return 0 + n: t.CSizeT = 0 + cur: "LinkedNode" | t.CPtr = self.child + while cur is not None: + n += 1 + cur = cur.next + return n + + def first_sibling(self) -> "LinkedNode" | t.CPtr: + """Return the head node of sibling linked list (traverse backward via prev pointers).""" + if self is None: return None + cur: "LinkedNode" | t.CPtr = self + while cur.prev is not None: + cur = cur.prev + return cur + + def last_sibling(self) -> "LinkedNode" | t.CPtr: + """Return the tail node of sibling linked list (traverse forward via next pointers).""" + if self is None: return None + cur: "LinkedNode" | t.CPtr = self + while cur.next is not None: + cur = cur.next + return cur + + +# ============================================================ +# SListNode: Singly linked list node (@t.NoVTable) +# +# Lightweight singly linked list with only Next pointer. No prev/parent/child. +# Suitable for queues, stacks and simple linked structures +# (such as Param/BasicBlock/Function/Line/Value in llvmlite). +# O(1) append requires caller to maintain tail pointer (append_after). +# O(n) append works with head pointer only (append). +# ============================================================ +@t.NoVTable +class SListNode: + Next: "SListNode" | t.CPtr # Next node + + def append(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + """Append node to the end of the linked list (O(n)). Return self (head). + + If self is None, the caller shall adopt node directly as the new head. + """ + if self is None: + return node + if node is None: + return self + node.Next = None + cur: "SListNode" | t.CPtr = self + while cur.Next is not None: + cur = cur.Next + cur.Next = node + return self + + def append_after(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + """Insert node immediately after self (O(1)). Return new tail (node). + + Caller must maintain the head pointer manually. Return node as head if self is None. + """ + if node is None: + return self + node.Next = None + if self is not None: + self.Next = node + return node + + def count(self) -> t.CSizeT: + """Calculate list length via full traversal (O(n)).""" + if self is None: + return 0 + n: t.CSizeT = 0 + cur: "SListNode" | t.CPtr = self + while cur is not None: + n += 1 + cur = cur.Next + return n + + def at(self, index: t.CSizeT) -> "SListNode" | t.CPtr: + """Return node at zero-based index (O(n)). Return None if index out of bounds.""" + if self is None: + return None + cur: "SListNode" | t.CPtr = self + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.Next + return None + + def remove(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + """Remove node from list (O(n)). Return updated head. + + The Next pointer of node will be cleared. If node is the original head, return head.Next. + """ + if self is None or node is None: + return self + if self is node: + new_head: "SListNode" | t.CPtr = self.Next + self.Next = None + return new_head + cur: "SListNode" | t.CPtr = self + while cur.Next is not None: + if cur.Next is node: + cur.Next = node.Next + node.Next = None + break + cur = cur.Next + return self + + +# ============================================================ +# GSListNode[T]: Generic singly linked list node (@t.NoVTable + PEP 695 generics) +# +# Unlike SListNode (non-generic, Next: SListNode|t.CPtr), the Next field of GSListNode[T] +# is typed as T|t.CPtr. After specialization it becomes a concrete node type directly, +# eliminating downcasts. +# +# Recursive generic usage pattern (subclass inherits from self-specialized variant): +# class GNode(GSListNode[GNode]): +# value: t.CInt +# # At this point GNode.Next: GNode|t.CPtr (strongly typed, no casting required) +# +# Technical validation targets: +# 1. Recursive generics: class GNode(GSListNode[GNode]) +# 2. Combination of @t.NoVTable attribute with generics +# 3. Generic class used as field type: list: GSList[GNode] +# 4. Inheritance of generic methods (GSList[T].append available after specialization) +# ============================================================ +@t.NoVTable +class GSListNode[T]: + Next: T | t.CPtr + + +# ============================================================ +# GSList[T]: Generic singly linked list container (@t.NoVTable + PEP 695 generics) +# +# Holds Head, Tail and Count. Provides O(1) append and O(n) indexed access. +# Node type T must inherit from GSListNode[T] (to acquire the Next field). +# +# Usage: +# list: GSList[GNode] | t.CPtr = GSList[GNode]() +# list.append(node) # Method invocation, not free function +# ============================================================ +@t.NoVTable +class GSList[T]: + Head: T | t.CPtr + Tail: T | t.CPtr + Count: t.CSizeT + + def __init__(self): + self.Head = None + self.Tail = None + self.Count = 0 + + def append(self, node: T): + """Append node to the end of the list (O(1)).""" + if node is None: + return + node.Next = None + if self.Head is None: + self.Head = node + else: + self.Tail.Next = node + self.Tail = node + self.Count += 1 + + def count(self) -> t.CSizeT: + """Return node count (O(1)).""" + return self.Count + + def at(self, index: t.CSizeT) -> T | t.CPtr: + """Return node at zero-based index (O(n)). Return None if index out of bounds.""" + if self.Head is None: + return None + cur: T | t.CPtr = self.Head + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.Next + return None + + +# ============================================================ +# GTreeNode[T]: Generic tree node (@t.NoVTable + PEP 695 generics) +# +# Type-safe variant of LinkedNode. All pointer fields are typed T|t.CPtr. +# Capabilities provided: +# - Bidirectional sibling linked list (Next/Prev) → O(1) removal +# - Parent-child tree structure (Child/LastChild/Parent) → O(1) child appending +# - Child counter (Count) +# +# Recursive generic usage pattern (subclass inherits self-specialized variant): +# @t.CVTable +# class AST(GTreeNode[AST]): +# def kind(self) -> t.CInt: +# return 0 +# # At this point AST.Next/Prev/Child/LastChild/Parent are all AST|t.CPtr (strongly typed) +# +# Fields are flattened and embedded into subclasses with no vtable overhead +# (equivalent to non-polymorphic inheritance in C++). +# If a subclass is marked @t.CVTable, it receives its own vtable (at offset 0), +# and GTreeNode fields are laid out after the vtable. +# +# OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers +# (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. +# ============================================================ +@t.NoVTable +class GTreeNode[T]: + Next: T | t.CPtr # Next sibling node + Prev: T | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) + Child: T | t.CPtr # First child node + LastChild: T | t.CPtr # Last child node (O(1) append) + Parent: T | t.CPtr # Parent node + Count: t.CSizeT # Number of child nodes + + def append(self, node: T | t.CPtr): + """Append node as the last child of self (O(1)). + + If node is already attached to any list, the caller shall invoke node.detach() prior to append. + """ + if self is None or node is None: + return + node.Parent = self + node.Next = None + node.Prev = self.LastChild + if self.Child is None: + self.Child = node + else: + self.LastChild.Next = node + self.LastChild = node + self.Count += 1 + + def prepend(self, node: T | t.CPtr): + """Insert node as the first child of self (O(1)).""" + if self is None or node is None: + return + node.Parent = self + node.Prev = None + node.Next = self.Child + if self.Child is not None: + self.Child.Prev = node + else: + self.LastChild = node + self.Child = node + self.Count += 1 + + def detach(self): + """Detach self from its sibling linked list (O(1)). + + After invocation, self.Next/self.Prev/self.Parent are cleared. The child chain remains untouched. + """ + if self is None: + return + if self.Prev is not None: + self.Prev.Next = self.Next + elif self.Parent is not None: + self.Parent.Child = self.Next + if self.Next is not None: + self.Next.Prev = self.Prev + elif self.Parent is not None: + self.Parent.LastChild = self.Prev + if self.Parent is not None: + if self.Parent.Count > 0: + self.Parent.Count -= 1 + self.Next = None + self.Prev = None + self.Parent = None + + def has_children(self) -> t.CInt: + """Return 1 if child nodes exist, otherwise return 0.""" + if self is None: + return 0 + if self.Child is not None: + return 1 + return 0 + + def child_at(self, index: t.CSizeT) -> T | t.CPtr: + """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" + if self is None: + return None + cur: T | t.CPtr = self.Child + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.Next + return None + + def count_children(self) -> t.CSizeT: + """Count children by traversal (O(n)), used to validate Count field.""" + if self is None: + return 0 + n: t.CSizeT = 0 + cur: T | t.CPtr = self.Child + while cur is not None: + n += 1 + cur = cur.Next + return n diff --git a/llvmlite/README.md b/llvmlite/README.md new file mode 100644 index 0000000..9d2e534 --- /dev/null +++ b/llvmlite/README.md @@ -0,0 +1,301 @@ +# llvmlite 设计方案 + +用 TransPyC 自身实现的轻量级 LLVM IR 文本生成库,替代 Python `llvmlite` 依赖,为自举(见 `wiki/13-bootstrapping.md` 路径 B)铺路。 + +## 1. 目标与定位 + +- **输入**:类型/值/指令的语义对象 +- **输出**:合法的 LLVM IR 文本(`.ll`),可直接喂给 `llc` +- **不做什么**:不解析 IR、不做优化、不绑定 LLVM C API(纯文本生成) +- **自举约束**:本库必须能用当前 TransPyC 编译器完整编译,不得依赖任何 Python 运行时 + +## 2. 核心设计决策 + +### 2.1 类型系统用 `t.REnum`(tagged union) + +LLVM 类型变体少、无通用字段、字段都是指针/小整数、操作主要通过 `match` 分派 —— 完全契合 REnum 的 tag+union 模型。 + +### 2.2 指令 opcode 用 `t.CEnum` + +指令类别(Binary/Unary/Cast/Memory/Terminator/Compare)与具体 opcode(Add/Sub/Load/Store/Br/Ret/...)用 `t.CEnum` 组织,类型安全且零开销。 + +### 2.3 IR 文本生成用 `viperlib.snprintf` + +所有 IR 文本通过 `viperlib.snprintf(buf, size, fmt, *args)` 格式化写入缓冲区,避免手写逐字符拼接。`snprintf` 已支持宽度/精度/符号/`%s`/`%d`/`%x` 等,足够覆盖 IR 语法。 + +### 2.4 对象分配用普通类 + `mpool` + +像 `mbuddy` 一样用普通类(无 `__new__`),由调用方注入 `mpool.MPool` 做批量分配。库内部不持有全局 `mbuddy`,遵循项目约定(`_mbuddy` 指针由 `os.vp` 或调用方设置)。 + +--- + +## 3. 为什么 AST 不用 REnum,而 llvmlite 用? + +用户质疑:REnum 是 tag+union(Rust enum),配合 `match` 模式匹配,按理很适合 AST。下面解释两者的适配性差异。 + +### 3.1 REnum 的硬限制(来自 `HandlesClassDef._EmitREnumLlvm`) + +1. **无通用字段共享**:每个 variant 独立声明字段,通用字段(如 `lineno`/`child`/`next`)必须在每 variant 重复声明。 +2. **共享最大变体尺寸**:布局为 `{ i32 __tag, }`,小变体浪费内存。 +3. **payload 仅位置绑定**:`match` 通过位置绑定 payload,不能直接 `node.child` 属性访问 payload 字段。 +4. **无方法**:variant 不能挂方法。 + +### 3.2 AST 不适合 REnum 的四个原因 + +| 维度 | AST 需求 | REnum 限制 | 冲突 | +|------|----------|------------|------| +| 变体数量 | 70+ 节点类型 | 共享最大变体尺寸 | 内存膨胀(每节点都占最大变体空间) | +| 通用字段 | lineno/child/next/parent 等 ~8 个字段全节点共享 | 无通用字段共享 | 要么每 variant 重复声明(冗长),要么放弃统一访问 | +| 访问模式 | 频繁直接 `node.child`/`node.next`/`node.lineno` | payload 仅位置绑定,需 match 分派 | 遍历代码爆炸(每次访问都要 match) | +| 字段复用 | `int_val`/`str_val`/`op` 等字段按 vtype 复用语义 | 每 variant 独立 payload | 无法复用 | + +AST 采用"胖节点"设计(所有节点共用一个 `AST` struct,用 `vtype` 区分):一次 `malloc`、统一链表遍历(`child`/`next`)、字段复用。这与 REnum"每变体独立 payload"的哲学根本冲突。 + +### 3.3 llvmlite 的 LLVMType 适合 REnum 的原因 + +| 维度 | LLVMType 需求 | REnum 特性 | 契合度 | +|------|---------------|------------|--------| +| 变体数量 | ~10 个(Int/Ptr/Func/Array/Struct/Void/Float/Label/...) | 共享最大变体尺寸 | 浪费可接受(最大变体 ~24 字节) | +| 通用字段 | 无(每变体字段不同) | 无通用字段共享 | 完美匹配 | +| 访问模式 | 类型操作天然通过 match 分派("是 Int 取 bits,是 Ptr 取 pointee") | payload 位置绑定 + match | 天然契合 | +| 字段尺寸 | 都是指针(8B)或小整数(4B) | 共享最大变体 | 浪费小 | + +**结论**:REnum 是"少变体、无共性、match 分派"场景的最佳工具 —— llvmlite 类型系统正好如此,AST 正好相反。 + +--- + +## 4. 文件结构 + +``` +includes/llvmlite/ +├── __init__.vp # 公共导出 + 便捷工厂函数 +├── __types.vp # LLVMType (REnum) + 类型构造/打印 +├── __values.vp # Value/Constant/SSA 值表示 +├── __module.vp # Module 容器(函数列表 + 目标三元组 + 输出 .ll) +├── __function.vp # Function + BasicBlock + 参数管理 +├── __builder.vp # IRBuilder(指令发射 + SSA 命名 + 块跳转) +└── README.md # 本文件 +``` + +### 职责划分 + +- `__types.vp`:`LLVMType` REnum 定义 + `TypePrint(buf, ty)` 将类型序列化为 IR 文本(如 `i32`/`i32*`/`{i32, i8*}`) +- `__values.vp`:`Value` 表示一个 SSA 值(`%0`/`%result`/常量),含类型指针 + 名字 + 是否常量 +- `__module.vp`:`Module` 持有函数链表 + 目标三元组 + 数据布局,`ModulePrint` 输出完整 `.ll` +- `__function.vp`:`Function` 持有基本块链表 + 参数 + 返回类型;`BasicBlock` 持有指令文本缓冲 +- `__builder.vp`:`IRBuilder` 游标式 API,`build_add`/`build_load`/`build_br`/... 发射指令到当前块 + +--- + +## 5. 类型系统设计(REnum) + +```python +import t +from stdint import * + +class LLVMType(t.REnum): + # 变体 Int:整数类型 + IntBits: t.CInt # 位宽 1/8/16/32/64/128 + + # 变体 Ptr:指针类型 + PtrPointee: LLVMType | t.CPtr # 指向的类型(自引用用指针) + + # 变体 Func:函数类型 + FuncRet: LLVMType | t.CPtr # 返回类型 + FuncParams: LLVMType | t.CPtr # 参数类型链表头 + FuncPCount: t.CInt # 参数数量 + + # 变体 Array:数组类型 + ArrayElem: LLVMType | t.CPtr # 元素类型 + ArrayCount: t.CInt # 元素数量 + + # 变体 Struct:结构体类型 + StructHead: LLVMType | t.CPtr # 字段类型链表头 + StructCount: t.CInt # 字段数量 + + # 变体 Float:浮点类型 + FloatBits: t.CInt # 16/32/64/128 + + # 变体 Void / Label / Metadata:无 payload + # (REnum 允许空变体,仅靠 __tag 区分) +``` + +### 类型工厂(`__init__.vp` 导出) + +```python +def Int1() -> LLVMType | t.CPtr: ... # i1 +def Int8() -> LLVMType | t.CPtr: ... # i8 +def Int32() -> LLVMType | t.CPtr: ... # i32 +def Int64() -> LLVMType | t.CPtr: ... # i64 +def Ptr(pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: ... +def Func(ret: LLVMType | t.CPtr, params: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: ... +def Void() -> LLVMType | t.CPtr: ... +``` + +### 类型打印(match 分派) + +```python +def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr): + match ty: + case LLVMType.Int: # 位置绑定 IntBits + viperlib.snprintf(buf, size, "i%d", ty.IntBits) + case LLVMType.Ptr: # 位置绑定 PtrPointee + TypePrint(inner, size2, ty.PtrPointee) + # 拼接 "*" + case LLVMType.Func: + # 打印 ret (params) + case LLVMType.Void: + string.strcpy(buf, "void") + ... +``` + +--- + +## 6. Value / SSA 设计 + +```python +class Value: + Ty: LLVMType | t.CPtr # 值的类型 + Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本 + IsConst: t.CInt # 1=常量字面量,0=SSA 临时值 + Next: Value | t.CPtr # 链表(函数内的值池) +``` + +`IRBuilder` 维护一个递增的 `%N` 计数器,每发射一条产生结果的指令就分配一个新名。 + +--- + +## 7. IRBuilder 设计 + +游标式 API,跟踪当前 `BasicBlock`,发射指令文本到块的缓冲区。 + +```python +class IRBuilder: + Func: Function | t.CPtr # 所属函数 + CurBlock: BasicBlock | t.CPtr # 当前插入点 + Counter: t.CInt # SSA 名计数器 + + def build_add(self, lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + # 1. 分配 SSA 名 %N + # 2. snprintf(buf, size, " %%%d = add %s %s, %s\n", N, ty, lhs, rhs) + # 3. 追加到 CurBlock 缓冲 + # 4. 返回新 Value + + def build_load(self, ty: LLVMType | t.CPtr, ptr: Value | t.CPtr) -> Value | t.CPtr: ... + def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr): ... + def build_br(self, target: BasicBlock | t.CPtr): ... + def build_cond_br(self, cond: Value | t.CPtr, then: BasicBlock | t.CPtr, else_: BasicBlock | t.CPtr): ... + def build_ret(self, val: Value | t.CPtr): ... + def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: ... + def build_gep(self, ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: ... + def build_call(self, callee: t.CChar | t.CPtr, args: Value | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: ... +``` + +### 指令 opcode(CEnum) + +```python +class IROp(t.CEnum): + # Terminator + Ret: t.CEnum = 1 + Br: t.CEnum = 2 + CondBr: t.CEnum = 3 + Switch: t.CEnum = 4 + # Binary + Add: t.CEnum = 10 + Sub: t.CEnum = 11 + Mul: t.CEnum = 12 + SDiv: t.CEnum = 13 + # Memory + Load: t.CEnum = 20 + Store: t.CEnum = 21 + Alloca: t.CEnum = 22 + Gep: t.CEnum = 23 + # Cast + BitCast: t.CEnum = 30 + SExt: t.CEnum = 31 + Trunc: t.CEnum = 32 + # Compare + ICmp: t.CEnum = 40 + # Call + Call: t.CEnum = 50 +``` + +--- + +## 8. IR 文本生成(snprintf 用法) + +每条指令发射用 `viperlib.snprintf` 格式化到块缓冲区。示例: + +```python +import viperlib + +def _emit_add(block: BasicBlock | t.CPtr, name: t.CChar | t.CPtr, + ty_str: t.CChar | t.CPtr, lhs: t.CChar | t.CPtr, rhs: t.CChar | t.CPtr): + line: t.CChar | t.CPtr = mpool.alloc(128) # 行缓冲 + viperlib.snprintf(line, 128, " %s = add %s %s, %s\n", name, ty_str, lhs, rhs) + _block_append(block, line) +``` + +### Module 输出 + +```python +def ModulePrint(mod: Module | t.CPtr, out_path: t.CChar | t.CPtr): + # 1. 写头部:target triple / datalayout + # 2. 遍历函数,写 declare/define + # 3. 每函数:签名 + 基本块 + 指令 + # 用 snprintf 拼接,写到文件(viperio 或 w32/win32file) +``` + +--- + +## 9. 内存管理 + +- 库内所有对象从 `mpool.MPool` 分配(像 `ast` 库一样) +- `IRBuilder`/`Module`/`Function` 不持有 `mbuddy`,由调用方传入 `mpool` +- 文本缓冲区按行分配(每指令一行,128 字节起步),避免频繁 realloc + +--- + +## 10. 基础构建范围(第一阶段) + +最小可用集,能生成一个完整的小程序 IR: + +1. **类型**:`IntType`(1/8/16/32/64) + `PointerType` + `FunctionType` + `VoidType` + `StructType` +2. **值**:`Value` + 常量整数字面量 +3. **Module/Function/BasicBlock**:容器与链表 +4. **IRBuilder** 指令子集: + - `alloca` / `load` / `store` + - `add` / `sub` / `mul` / `sdiv` + - `icmp` (eq/ne/sgt/sge/slt/sle) + - `br` / `cond_br` / `ret` + - `call`(外部函数) + - `bitcast` / `sext` / `trunc` + - `getelementptr` +5. **ModulePrint**:输出完整 `.ll` 文件 + +### 后续扩展路线 + +- **第二阶段**:浮点指令、`phi` 节点、`switch`、字符串常量全局、属性(`nounwind`/`nocapture`) +- **第三阶段**:内联汇编、`atomic` 指令、`va_arg`、精确的 SSA 验证(支配边界、phi 完整性) +- **第四阶段**:对接 TransPyC 的 `LLVMCG`,替换 Python `llvmlite`,完成路径 B 自举 + +--- + +## 11. 测试计划 + +独立测试项目(`Test/LLvmLiteTest/`): + +1. **类型打印测试**:构造各 `LLVMType`,`TypePrint` 输出,对比预期字符串 +2. **小函数生成**:用 `IRBuilder` 生成 `i32 add(i32 a, i32 b) { ret i32 %r }`,`ModulePrint` 写 `.ll`,用 `llc` 编译验证语法合法 +3. **match 分派测试**:构造各变体 `LLVMType`,`match` 正确绑定 payload +4. **snprintf 格式测试**:验证 `%d`/`%s`/`%x` 在 IR 文本中的正确性 + +--- + +## 12. 与现有架构的对接点 + +- **`lib/core/Codegen/LLVMCG.py`**:当前用 Python `llvmlite` 生成 IR,自举时改用本库 +- **`includes/viperlib.vp`**:提供 `snprintf` / `sprintf` +- **`includes/mpool.vp`**:提供 `MPool` 内存池 +- **`includes/string.vp`**:提供 `strcpy`/`strlen`/`memcpy` +- **`includes/ast/`**:参考其"胖节点 + mpool + CEnum 常量"的组织方式(但类型系统用 REnum 而非胖节点) diff --git a/llvmlite/__builder.vp b/llvmlite/__builder.vp new file mode 100644 index 0000000..8c949a9 --- /dev/null +++ b/llvmlite/__builder.vp @@ -0,0 +1,1827 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import stdio +import stdlib +from linkedlist import GSListNode, GSList +from .__types import LLVMType, TypePrint +from .__values import Value, new_value, SSAValue +from .__function import Function, BasicBlock, block_append_text, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote, block_insert_text_before_terminator + +# ============================================================ +# IRBuilder: 游标式 IR 指令发射器 +# +# 跟踪当前 BasicBlock,将指令文本追加到块的指令链表。 +# 维护递增的 SSA 名计数器(%0, %1, %2, ...)。 +# +# 用法: +# builder = new_builder(pool, func) +# builder.PositionAtEnd(entry_block) +# a = builder.build_alloca(i32_ty) +# b = builder.build_alloca(i32_ty) +# builder.build_store(ConstInt(42), a) +# r = builder.build_load(i32_ty, a) +# builder.build_ret(r) +# +# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=32 保持一致 +# (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。 +# ============================================================ +@t.NoVTable +class IRBuilder: + Pool: memhub.MemBuddy | t.CPtr # 内存池 + Func: Function | t.CPtr # 所属函数 + CurBlock: BasicBlock | t.CPtr # 当前插入点 + Counter: t.CInt # SSA 名计数器 + + # ============================================================ + # 内部辅助 + # ============================================================ + def _alloc_ssa_name(self) -> t.CChar | t.CPtr: + """分配一个 SSA 名字符串 "%N" 并递增计数器""" + pool: memhub.MemBuddy | t.CPtr = self.Pool + buf: t.CChar | t.CPtr = pool.alloc(16) + if buf is None: return None + viperlib.snprintf(buf, 16, "%%%d", self.Counter) + self.Counter += 1 + return buf + + + def _type_str(self, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr: + """获取类型的 IR 文本(从 pool 分配 512 字节缓冲区) + + 注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节, + 必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。 + """ + pool: memhub.MemBuddy | t.CPtr = self.Pool + buf: t.CChar | t.CPtr = pool.alloc(512) + if buf is None: return None + buf[0] = '\0' + TypePrint(buf, 512, ty, pool) + return buf + + + def _emit(self, text: t.CChar | t.CPtr): + """将指令文本追加到当前块""" + if self is None or self.CurBlock is None: return + block_append_text(self.Pool, self.CurBlock, text) + + + def _mark_terminated(self): + """标记当前块已终止""" + if self is None or self.CurBlock is None: return + block_set_terminated(self.CurBlock, 1) + + + def _build_binop(self, op: t.CChar | t.CPtr, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """二元运算通用实现""" + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(lhs.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = %s %s %s, %s", name, op, ty_s, lhs.Name, rhs.Name) + self._emit(line) + return SSAValue(pool, lhs.Ty, name) + + + # ============================================================ + # 块定位 + # ============================================================ + def position_at_end(self, block: BasicBlock | t.CPtr): + """将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。 + + 移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致, + 避免 SSA 名在文本中非单调递增导致 llc 编译失败。 + """ + if self is None: return + self.CurBlock = block + if self.Func is not None: + function_move_block_to_end(self.Func, block) + + + def builder_cur_block_is_terminated(self) -> t.CInt: + """检查当前块的 IsTerminated 标志 + + 通过 block_get_terminated 辅助函数访问,避免链式属性 + self.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque + 导致的 GEP 静默跳过问题。 + """ + if self is None or self.CurBlock is None: + return 1 + return block_get_terminated(self.CurBlock) + + + # ============================================================ + # 内存指令 + # ============================================================ + def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca + + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s", name, ty_s) + self._emit(line) + + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_alloca_aligned(self, ty: LLVMType | t.CPtr, + align: int) -> Value | t.CPtr: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s, align %d", name, ty_s, align) + self._emit(line) + + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_alloca_at_entry(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca (在函数入口块生成,确保支配性) + + 在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca + 导致的支配性违规(Instruction does not dominate all uses)。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + func: Function | t.CPtr = self.Func + if func is None or func.Blocks is None: + return self.build_alloca(ty) + entry_blk: BasicBlock | t.CPtr = func.Blocks.Head + if entry_blk is None: + return self.build_alloca(ty) + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + line_text: t.CChar | t.CPtr = pool.alloc(128) + if line_text is None: return None + viperlib.snprintf(line_text, 128, "%s = alloca %s", name, ty_s) + # 在入口块终止指令之前插入 + block_insert_text_before_terminator(pool, entry_blk, line_text) + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_load(self, ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr) -> Value | t.CPtr: + """%N = load , """ + if self is None or ptr is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) + self._emit(line) + return SSAValue(pool, ty, name) + + + def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr): + """store , """ + if self is None or val is None or ptr is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + val_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return + viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) + self._emit(line) + + + # ============================================================ + # 二元运算指令 + # ============================================================ + def build_add(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = add , """ + return self._build_binop("add", lhs, rhs) + + + def build_sub(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sub , """ + return self._build_binop("sub", lhs, rhs) + + + def build_mul(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = mul , """ + return self._build_binop("mul", lhs, rhs) + + + def build_sdiv(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sdiv , """ + return self._build_binop("sdiv", lhs, rhs) + + + def build_udiv(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = udiv , """ + return self._build_binop("udiv", lhs, rhs) + + + def build_srem(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = srem , """ + return self._build_binop("srem", lhs, rhs) + + + def build_urem(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = urem , """ + return self._build_binop("urem", lhs, rhs) + + + def build_and(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = and , """ + return self._build_binop("and", lhs, rhs) + + + def build_or(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = or , """ + return self._build_binop("or", lhs, rhs) + + + def build_xor(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = xor , """ + return self._build_binop("xor", lhs, rhs) + + + def build_shl(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = shl , """ + return self._build_binop("shl", lhs, rhs) + + + def build_lshr(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = lshr , """ + return self._build_binop("lshr", lhs, rhs) + + + def build_ashr(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = ashr , """ + return self._build_binop("ashr", lhs, rhs) + + + # ============================================================ + # 浮点二元运算指令 + # ============================================================ + def build_fadd(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fadd , """ + return self._build_binop("fadd", lhs, rhs) + + + def build_fsub(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fsub , """ + return self._build_binop("fsub", lhs, rhs) + + + def build_fmul(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fmul , """ + return self._build_binop("fmul", lhs, rhs) + + + def build_fdiv(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fdiv , """ + return self._build_binop("fdiv", lhs, rhs) + + + def build_frem(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = frem , """ + return self._build_binop("frem", lhs, rhs) + + + def build_fneg(self, val: Value | t.CPtr) -> Value | t.CPtr: + """%N = fneg """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = fneg %s %s", name, ty_s, val.Name) + self._emit(line) + return SSAValue(pool, val.Ty, name) + + + # ============================================================ + # 比较指令 + # ============================================================ + def build_icmp(self, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = icmp , + + 返回类型为 i1 的 SSA 值 + """ + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(lhs.Ty) + pred_s: t.CChar | t.CPtr = _icmp_pred_str(pred) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = icmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name) + self._emit(line) + + # 结果类型是 i1 + i1_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if i1_ty is not None: + string.memset(i1_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i1_ty, LLVMType.Int(1)) + return SSAValue(pool, i1_ty, name) + + + def build_fcmp(self, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fcmp , + + 返回类型为 i1 的 SSA 值 + """ + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(lhs.Ty) + pred_s: t.CChar | t.CPtr = _fcmp_pred_str(pred) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fcmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name) + self._emit(line) + + # 结果类型是 i1 + i1_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if i1_ty is not None: + string.memset(i1_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i1_ty, LLVMType.Int(1)) + return SSAValue(pool, i1_ty, name) + + + # ============================================================ + # 终止指令 + # ============================================================ + def build_br(self, target: BasicBlock | t.CPtr): + """br label %""" + if self is None or target is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(64) + if line is None: return + viperlib.snprintf(line, 64, "br label %%%s", target.Name) + self._emit(line) + self._mark_terminated() + + + def build_cond_br(self, cond: Value | t.CPtr, + then_blk: BasicBlock | t.CPtr, else_blk: BasicBlock | t.CPtr): + """br i1 , label %, label %""" + if self is None or cond is None or then_blk is None or else_blk is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return + viperlib.snprintf(line, 128, "br i1 %s, label %%%s, label %%%s", + cond.Name, then_blk.Name, else_blk.Name) + self._emit(line) + self._mark_terminated() + + + def build_ret(self, val: Value | t.CPtr): + """ret """ + if self is None or val is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return + viperlib.snprintf(line, 128, "ret %s %s", ty_s, val.Name) + self._emit(line) + self._mark_terminated() + + + def build_ret_void(self): + """ret void""" + if self is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(16) + if line is None: return + string.strcpy(line, "ret void") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # 调用指令 + # ============================================================ + def build_call(self, callee: t.CChar | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr, + is_variadic: t.CInt = 0) -> Value | t.CPtr: + """%N = call @() + + args 是 Value 链表头,arg_count 是参数数量。 + 若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。 + is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + + # 判断返回类型是否为 void + is_void: t.CInt = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: t.CChar | t.CPtr = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: t.CChar | t.CPtr = self._type_str(ret_ty) + + # 构建参数列表文本 + 变参函数类型签名 + args_buf: t.CChar | t.CPtr = pool.alloc(1024) + if args_buf is None: return None + args_buf[0] = '\0' + func_ty_buf: t.CChar | t.CPtr = pool.alloc(1024) + if func_ty_buf is None: return None + func_ty_buf[0] = '\0' + cur: Value | t.CPtr = args + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(args_buf, 1024, ", ") + _append_cstr(func_ty_buf, 1024, ", ") + arg_ty_s: t.CChar | t.CPtr = self._type_str(cur.Ty) + _append_cstr(args_buf, 1024, arg_ty_s) + _append_cstr(args_buf, 1024, " ") + if cur.Name is not None: + _append_cstr(args_buf, 1024, cur.Name) + _append_cstr(func_ty_buf, 1024, arg_ty_s) + cur = cur.Next + first = 0 + if is_variadic == 1: + if first == 0: + _append_cstr(func_ty_buf, 1024, ", ") + _append_cstr(func_ty_buf, 1024, "...") + + # 构造带引号的 callee 名字(SHA1 前缀名含 '.' 或以数字开头需要加引号) + callee_buf: t.CChar | t.CPtr = pool.alloc(128) + if callee_buf is None: return None + callee_buf[0] = '\0' + if _ll_name_needs_quote(callee) != 0: + _append_cstr(callee_buf, 128, "\"") + _append_cstr(callee_buf, 128, callee) + _append_cstr(callee_buf, 128, "\"") + else: + _append_cstr(callee_buf, 128, callee) + + line: t.CChar | t.CPtr = pool.alloc(2048) + if line is None: return None + if is_variadic == 1: + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf) + else: + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + + # ============================================================ + # 间接调用指令: call %callee() + # + # callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*) + # ============================================================ + def build_call_indirect(self, callee_val: Value | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = call %callee() + + 间接调用:callee_val 是函数指针 SSA 值。 + """ + if self is None or callee_val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + + is_void: t.CInt = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: t.CChar | t.CPtr = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: t.CChar | t.CPtr = self._type_str(ret_ty) + + # 构建参数列表文本 + args_buf: t.CChar | t.CPtr = pool.alloc(1024) + if args_buf is None: return None + args_buf[0] = '\0' + cur: Value | t.CPtr = args + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(args_buf, 1024, ", ") + arg_ty_s: t.CChar | t.CPtr = self._type_str(cur.Ty) + _append_cstr(args_buf, 1024, arg_ty_s) + _append_cstr(args_buf, 1024, " ") + if cur.Name is not None: + _append_cstr(args_buf, 1024, cur.Name) + cur = cur.Next + first = 0 + + line: t.CChar | t.CPtr = pool.alloc(2048) + if line is None: return None + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + + # ============================================================ + # 类型转换指令 + # ============================================================ + def build_bitcast(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = bitcast to """ + if self is None or val is None: + return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + if val.Name is None: + return None + viperlib.snprintf(line, 256, "%s = bitcast %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + ret: Value | t.CPtr = SSAValue(pool, to_ty, name) + return ret + + + def build_sext(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = sext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_trunc(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = trunc to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = trunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_zext(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = zext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = zext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_ptrtoint(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = ptrtoint to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = ptrtoint %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_inttoptr(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = inttoptr to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = inttoptr %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + # ============================================================ + # 浮点转换指令 + # ============================================================ + def build_fpext(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fpext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fpext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fptrunc(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptrunc to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptrunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fp2si(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptosi to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptosi %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_si2fp(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sitofp to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = sitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fp2ui(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptoui to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptoui %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_ui2fp(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = uitofp to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = uitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + # ============================================================ + # GEP 指令 + # ============================================================ + def build_gep(self, elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr , , """ + if self is None or ptr is None or idx is None: return None + # 防御性检查: ptr.Ty 必须是指针类型,否则 llc 报错 + # "base of getelementptr must be a pointer" + # 当 translate_value 返回非指针值(如 i32 常量 0)时, + # 直接 GEP 会导致 llc 编译失败 + if _is_ptr_type(ptr.Ty) == 0: + return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + elem_ty_s: t.CChar | t.CPtr = self._type_str(elem_ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + idx_ty_s: t.CChar | t.CPtr = self._type_str(idx.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, %s %s", + name, elem_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name) + self._emit(line) + + # GEP 结果类型是 elem_ty* + result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty is not None: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(elem_ty)) + return SSAValue(pool, result_ty, name) + + + # ============================================================ + # build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx + # ============================================================ + def build_gep_array(self, array_ty: LLVMType | t.CPtr, + elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx + + 结果类型是 elem_ty* + """ + if self is None or ptr is None or idx is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + array_ty_s: t.CChar | t.CPtr = self._type_str(array_ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + idx_ty_s: t.CChar | t.CPtr = self._type_str(idx.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, i32 0, %s %s", + name, array_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name) + self._emit(line) + + # GEP 结果类型是 elem_ty* + result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty is not None: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(elem_ty)) + return SSAValue(pool, result_ty, name) + + + # ============================================================ + # build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + # ============================================================ + def build_gep_struct(self, struct_ty: LLVMType | t.CPtr, + field_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, field_idx: t.CInt) -> Value | t.CPtr: + """%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + + 结果类型是 field_ty* + """ + if self is None or ptr is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + struct_ty_s: t.CChar | t.CPtr = self._type_str(struct_ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + line: t.CChar | t.CPtr = pool.alloc(2048) + if line is None: + stdio.printf("[BGS] line alloc None\n") + return None + viperlib.snprintf(line, 2048, "%s = getelementptr %s, %s %s, i32 0, i32 %d", + name, struct_ty_s, ptr_ty_s, ptr.Name, field_idx) + self._emit(line) + + # GEP 结果类型是 field_ty* + result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty is None: + stdio.printf("[BGS] result_ty alloc None\n") + else: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(field_ty)) + rv: Value | t.CPtr = SSAValue(pool, result_ty, name) + if rv is None: + stdio.printf("[BGS] SSAValue None\n") + return rv + + + # ============================================================ + # Phi 指令 + # ============================================================ + def build_phi(self, ty: LLVMType | t.CPtr, + incoming_head: PhiIncoming | t.CPtr, count: t.CInt) -> Value | t.CPtr: + """%N = phi [val1, %blk1], [val2, %blk2], ... + + incoming_head 是 PhiIncoming 链表头,count 是入边数量。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + + # 构建入边列表文本: [val, %blk], [val, %blk], ... + # 入边可能很多(如 30+ 个 or 链的 bool.merge),需要大缓冲区 + parts: t.CChar | t.CPtr = pool.alloc(4096) + if parts is None: return None + parts[0] = '\0' + cur: PhiIncoming | t.CPtr = incoming_head + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(parts, 4096, ", ") + _append_cstr(parts, 4096, "[") + # 使用中间变量避免链式结构体成员访问被编译器丢弃 + inc_val: Value | t.CPtr = cur.Val + if inc_val is not None: + inc_val_name: t.CChar | t.CPtr = inc_val.Name + if inc_val_name is not None: + _append_cstr(parts, 4096, inc_val_name) + _append_cstr(parts, 4096, ", %") + inc_blk: BasicBlock | t.CPtr = cur.Block + if inc_blk is not None: + inc_blk_name: t.CChar | t.CPtr = inc_blk.Name + if inc_blk_name is not None: + _append_cstr(parts, 4096, inc_blk_name) + _append_cstr(parts, 4096, "]") + cur = cur.Next + first = 0 + + line: t.CChar | t.CPtr = pool.alloc(8192) + if line is None: return None + viperlib.snprintf(line, 8192, "%s = phi %s %s", name, ty_s, parts) + self._emit(line) + return SSAValue(pool, ty, name) + + + # ============================================================ + # Switch 指令 + # ============================================================ + def build_switch(self, val: Value | t.CPtr, + default_blk: BasicBlock | t.CPtr, + cases_head: SwitchCase | t.CPtr, case_count: t.CInt): + """switch , label % [, label % ...]""" + if self is None or val is None or default_blk is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + + # 构建主体: switch , label %default + line: t.CChar | t.CPtr = pool.alloc(512) + if line is None: return + viperlib.snprintf(line, 512, "switch %s %s, label %%%s", + ty_s, val.Name, default_blk.Name) + _append_cstr(line, 512, " [") + _append_cstr(line, 512, "\n") + + # 遍历 case 列表 + cur: SwitchCase | t.CPtr = cases_head + case_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + while cur is not None: + case_line: t.CChar | t.CPtr = pool.alloc(128) + if case_line is not None: + # 使用中间变量避免链式结构体成员访问被编译器丢弃 + cv: Value | t.CPtr = cur.CaseVal + cb: BasicBlock | t.CPtr = cur.Block + if cv is not None and cb is not None: + cv_name: t.CChar | t.CPtr = cv.Name + cb_name: t.CChar | t.CPtr = cb.Name + if cv_name is not None and cb_name is not None: + viperlib.snprintf(case_line, 128, " %s %s, label %%%s\n", + case_ty_s, cv_name, cb_name) + _append_cstr(line, 512, case_line) + cur = cur.Next + + _append_cstr(line, 512, "]") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # Select 指令 + # ============================================================ + def build_select(self, cond: Value | t.CPtr, + true_val: Value | t.CPtr, false_val: Value | t.CPtr) -> Value | t.CPtr: + """%N = select i1 , , """ + if self is None or cond is None or true_val is None or false_val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(true_val.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = select i1 %s, %s %s, %s %s", + name, cond.Name, ty_s, true_val.Name, ty_s, false_val.Name) + self._emit(line) + return SSAValue(pool, true_val.Ty, name) + + + # ============================================================ + # Unreachable 指令 + # ============================================================ + def build_unreachable(self): + """unreachable""" + if self is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(16) + if line is None: return + string.strcpy(line, "unreachable") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # 原子指令 (Phase 3) + # ============================================================ + def build_atomicrmw(self, op: t.CInt, + ptr: Value | t.CPtr, val: Value | t.CPtr, + order: t.CInt) -> Value | t.CPtr: + """%N = atomicrmw , """ + if self is None or ptr is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + val_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + op_s: t.CChar | t.CPtr = _atomic_op_str(op) + ord_s: t.CChar | t.CPtr = _atomic_order_str(order) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = atomicrmw %s %s %s, %s %s %s", + name, op_s, ptr_ty_s, ptr.Name, val_ty_s, val.Name, ord_s) + self._emit(line) + return SSAValue(pool, val.Ty, name) + + + def build_cmpxchg(self, ptr: Value | t.CPtr, + cmp_val: Value | t.CPtr, new_val: Value | t.CPtr, + succ_order: t.CInt, fail_order: t.CInt) -> Value | t.CPtr: + """%N = cmpxchg , , + + 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) + """ + if self is None or ptr is None or cmp_val is None or new_val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + cmp_ty_s: t.CChar | t.CPtr = self._type_str(cmp_val.Ty) + new_ty_s: t.CChar | t.CPtr = self._type_str(new_val.Ty) + succ_s: t.CChar | t.CPtr = _atomic_order_str(succ_order) + fail_s: t.CChar | t.CPtr = _atomic_order_str(fail_order) + line: t.CChar | t.CPtr = pool.alloc(384) + if line is None: return None + viperlib.snprintf(line, 384, "%s = cmpxchg %s %s, %s %s, %s %s %s %s", + name, ptr_ty_s, ptr.Name, cmp_ty_s, cmp_val.Name, + new_ty_s, new_val.Name, succ_s, fail_s) + self._emit(line) + # 返回原始值的类型 + return SSAValue(pool, new_val.Ty, name) + + + # ============================================================ + # va_arg 指令: 从 va_list 读取下一个变长参数 + # ============================================================ + def build_va_arg(self, + va_list_ptr: Value | t.CPtr, + arg_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = va_arg , """ + if self is None or va_list_ptr is None or arg_ty is None: + return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + va_list_ty_s: t.CChar | t.CPtr = self._type_str(va_list_ptr.Ty) + arg_ty_s: t.CChar | t.CPtr = self._type_str(arg_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + if va_list_ptr.Name is None: + return None + viperlib.snprintf(line, 256, "%s = va_arg %s %s, %s", + name, va_list_ty_s, va_list_ptr.Name, arg_ty_s) + self._emit(line) + return SSAValue(pool, arg_ty, name) + + + # ============================================================ + # 内联汇编 (Phase 3) + # ============================================================ + def build_inline_asm(self, ret_ty: LLVMType | t.CPtr, + asm_text: t.CChar | t.CPtr, constraints: t.CChar | t.CPtr, + has_side_effects: t.CInt) -> Value | t.CPtr: + """%N = call asm [sideeffect] "" ""() + + 简化的内联汇编调用,无参数版本。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + + # 判断返回类型是否为 void + is_void: t.CInt = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: t.CChar | t.CPtr = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: t.CChar | t.CPtr = self._type_str(ret_ty) + line: t.CChar | t.CPtr = pool.alloc(512) + if line is None: return None + + if has_side_effects != 0: + if is_void == 1: + viperlib.snprintf(line, 512, "call %s asm sideeffect \"%s\", \"%s\"()", + ret_ty_s, asm_text, constraints) + else: + viperlib.snprintf(line, 512, "%s = call %s asm sideeffect \"%s\", \"%s\"()", + name, ret_ty_s, asm_text, constraints) + else: + if is_void == 1: + viperlib.snprintf(line, 512, "call %s asm \"%s\", \"%s\"()", + ret_ty_s, asm_text, constraints) + else: + viperlib.snprintf(line, 512, "%s = call %s asm \"%s\", \"%s\"()", + name, ret_ty_s, asm_text, constraints) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) = 32 字节 +BUILDER_SIZE: t.CDefine = 32 + +def new_builder(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr) -> IRBuilder | t.CPtr: + """创建 IRBuilder,关联到函数 func""" + ptr: IRBuilder | t.CPtr = pool.alloc(BUILDER_SIZE) + if ptr is None: return None + string.memset(ptr, 0, BUILDER_SIZE) + ptr.Pool = pool + ptr.Func = func + ptr.CurBlock = None + ptr.Counter = 0 + return ptr + + +# ============================================================ +# 块定位 +# ============================================================ +def position_at_end(builder: IRBuilder | t.CPtr, block: BasicBlock | t.CPtr): + """将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。 + + 移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致, + 避免 SSA 名在文本中非单调递增导致 llc 编译失败。 + """ + builder.position_at_end(block) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _alloc_ssa_name(builder: IRBuilder | t.CPtr) -> t.CChar | t.CPtr: + """分配一个 SSA 名字符串 "%N" 并递增计数器""" + return builder._alloc_ssa_name() + + +def _type_str(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr: + """获取类型的 IR 文本(从 pool 分配 512 字节缓冲区) + + 注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节, + 必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。 + """ + return builder._type_str(ty) + + +def _emit(builder: IRBuilder | t.CPtr, text: t.CChar | t.CPtr): + """将指令文本追加到当前块""" + builder._emit(text) + + +def _mark_terminated(builder: IRBuilder | t.CPtr): + """标记当前块已终止""" + builder._mark_terminated() + + +def builder_cur_block_is_terminated(builder: IRBuilder | t.CPtr) -> t.CInt: + """检查当前块的 IsTerminated 标志 + + 通过 block_get_terminated 辅助函数访问,避免链式属性 + builder.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque + 导致的 GEP 静默跳过问题。 + """ + return builder.builder_cur_block_is_terminated() + + +# ============================================================ +# 内存指令 +# ============================================================ +def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca + + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 + """ + return builder.build_alloca(ty) + + +def build_alloca_aligned(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + align: int) -> Value | t.CPtr: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + return builder.build_alloca_aligned(ty, align) + + +def build_alloca_at_entry(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca (在函数入口块生成,确保支配性) + + 在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca + 导致的支配性违规(Instruction does not dominate all uses)。 + """ + return builder.build_alloca_at_entry(ty) + + +def build_load(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr) -> Value | t.CPtr: + """%N = load , """ + return builder.build_load(ty, ptr) + + +def build_store(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, ptr: Value | t.CPtr): + """store , """ + builder.build_store(val, ptr) + + +# ============================================================ +# 二元运算指令 +# ============================================================ +def build_add(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = add , """ + return builder.build_add(lhs, rhs) + + +def build_sub(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sub , """ + return builder.build_sub(lhs, rhs) + + +def build_mul(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = mul , """ + return builder.build_mul(lhs, rhs) + + +def build_sdiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sdiv , """ + return builder.build_sdiv(lhs, rhs) + + +def build_udiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = udiv , """ + return builder.build_udiv(lhs, rhs) + + +def build_srem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = srem , """ + return builder.build_srem(lhs, rhs) + + +def build_urem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = urem , """ + return builder.build_urem(lhs, rhs) + + +def build_and(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = and , """ + return builder.build_and(lhs, rhs) + + +def build_or(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = or , """ + return builder.build_or(lhs, rhs) + + +def build_xor(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = xor , """ + return builder.build_xor(lhs, rhs) + + +def build_shl(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = shl , """ + return builder.build_shl(lhs, rhs) + + +def build_lshr(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = lshr , """ + return builder.build_lshr(lhs, rhs) + + +def build_ashr(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = ashr , """ + return builder.build_ashr(lhs, rhs) + + +# ============================================================ +# 浮点二元运算指令 +# ============================================================ +def build_fadd(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fadd , """ + return builder.build_fadd(lhs, rhs) + + +def build_fsub(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fsub , """ + return builder.build_fsub(lhs, rhs) + + +def build_fmul(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fmul , """ + return builder.build_fmul(lhs, rhs) + + +def build_fdiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fdiv , """ + return builder.build_fdiv(lhs, rhs) + + +def build_frem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = frem , """ + return builder.build_frem(lhs, rhs) + + +def build_fneg(builder: IRBuilder | t.CPtr, val: Value | t.CPtr) -> Value | t.CPtr: + """%N = fneg """ + return builder.build_fneg(val) + + +def _build_binop(builder: IRBuilder | t.CPtr, op: t.CChar | t.CPtr, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """二元运算通用实现""" + return builder._build_binop(op, lhs, rhs) + + +# ============================================================ +# 比较指令 +# ============================================================ +# ICMP 谓词常量 +ICMP_EQ: t.CDefine = 0 +ICMP_NE: t.CDefine = 1 +ICMP_SGT: t.CDefine = 2 +ICMP_SGE: t.CDefine = 3 +ICMP_SLT: t.CDefine = 4 +ICMP_SLE: t.CDefine = 5 +ICMP_UGT: t.CDefine = 6 +ICMP_UGE: t.CDefine = 7 +ICMP_ULT: t.CDefine = 8 +ICMP_ULE: t.CDefine = 9 + +# FCMP 谓词常量 +FCMP_FALSE: t.CDefine = 0 +FCMP_OEQ: t.CDefine = 1 +FCMP_OGT: t.CDefine = 2 +FCMP_OGE: t.CDefine = 3 +FCMP_OLT: t.CDefine = 4 +FCMP_OLE: t.CDefine = 5 +FCMP_ONE: t.CDefine = 6 +FCMP_ORD: t.CDefine = 7 +FCMP_UNO: t.CDefine = 8 +FCMP_UEQ: t.CDefine = 9 +FCMP_UGT: t.CDefine = 10 +FCMP_UGE: t.CDefine = 11 +FCMP_ULT: t.CDefine = 12 +FCMP_ULE: t.CDefine = 13 +FCMP_UNE: t.CDefine = 14 +FCMP_TRUE: t.CDefine = 15 + + +def _icmp_pred_str(pred: t.CInt) -> t.CChar | t.CPtr: + if pred == ICMP_EQ: return "eq" + if pred == ICMP_NE: return "ne" + if pred == ICMP_SGT: return "sgt" + if pred == ICMP_SGE: return "sge" + if pred == ICMP_SLT: return "slt" + if pred == ICMP_SLE: return "sle" + if pred == ICMP_UGT: return "ugt" + if pred == ICMP_UGE: return "uge" + if pred == ICMP_ULT: return "ult" + if pred == ICMP_ULE: return "ule" + return "eq" + + +def _fcmp_pred_str(pred: t.CInt) -> t.CChar | t.CPtr: + if pred == FCMP_FALSE: return "false" + if pred == FCMP_OEQ: return "oeq" + if pred == FCMP_OGT: return "ogt" + if pred == FCMP_OGE: return "oge" + if pred == FCMP_OLT: return "olt" + if pred == FCMP_OLE: return "ole" + if pred == FCMP_ONE: return "one" + if pred == FCMP_ORD: return "ord" + if pred == FCMP_UNO: return "uno" + if pred == FCMP_UEQ: return "ueq" + if pred == FCMP_UGT: return "ugt" + if pred == FCMP_UGE: return "uge" + if pred == FCMP_ULT: return "ult" + if pred == FCMP_ULE: return "ule" + if pred == FCMP_UNE: return "une" + if pred == FCMP_TRUE: return "true" + return "oeq" + + +def build_icmp(builder: IRBuilder | t.CPtr, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = icmp , + + 返回类型为 i1 的 SSA 值 + """ + return builder.build_icmp(pred, lhs, rhs) + + +def build_fcmp(builder: IRBuilder | t.CPtr, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fcmp , + + 返回类型为 i1 的 SSA 值 + """ + return builder.build_fcmp(pred, lhs, rhs) + + +# ============================================================ +# 终止指令 +# ============================================================ +def build_br(builder: IRBuilder | t.CPtr, target: BasicBlock | t.CPtr): + """br label %""" + builder.build_br(target) + + +def build_cond_br(builder: IRBuilder | t.CPtr, cond: Value | t.CPtr, + then_blk: BasicBlock | t.CPtr, else_blk: BasicBlock | t.CPtr): + """br i1 , label %, label %""" + builder.build_cond_br(cond, then_blk, else_blk) + + +def build_ret(builder: IRBuilder | t.CPtr, val: Value | t.CPtr): + """ret """ + builder.build_ret(val) + + +def build_ret_void(builder: IRBuilder | t.CPtr): + """ret void""" + builder.build_ret_void() + + +# ============================================================ +# 调用指令 +# ============================================================ +def build_call(builder: IRBuilder | t.CPtr, callee: t.CChar | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr, + is_variadic: t.CInt = 0) -> Value | t.CPtr: + """%N = call @() + + args 是 Value 链表头,arg_count 是参数数量。 + 若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。 + is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 + """ + return builder.build_call(callee, args, arg_count, ret_ty, is_variadic) + + +# ============================================================ +# 间接调用指令: call %callee() +# +# callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*) +# ============================================================ +def build_call_indirect(builder: IRBuilder | t.CPtr, callee_val: Value | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = call %callee() + + 间接调用:callee_val 是函数指针 SSA 值。 + """ + return builder.build_call_indirect(callee_val, args, arg_count, ret_ty) + + +# ============================================================ +# 类型转换指令 +# ============================================================ +def build_bitcast(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = bitcast to """ + return builder.build_bitcast(val, to_ty) + + +def build_sext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sext to """ + return builder.build_sext(val, to_ty) + + +def build_trunc(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = trunc to """ + return builder.build_trunc(val, to_ty) + + +def build_zext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = zext to """ + return builder.build_zext(val, to_ty) + + +def build_ptrtoint(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = ptrtoint to """ + return builder.build_ptrtoint(val, to_ty) + + +def build_inttoptr(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = inttoptr to """ + return builder.build_inttoptr(val, to_ty) + + +# ============================================================ +# 浮点转换指令 +# ============================================================ +def build_fpext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fpext to """ + return builder.build_fpext(val, to_ty) + + +def build_fptrunc(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptrunc to """ + return builder.build_fptrunc(val, to_ty) + + +def build_fp2si(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptosi to """ + return builder.build_fp2si(val, to_ty) + + +def build_si2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sitofp to """ + return builder.build_si2fp(val, to_ty) + + +def build_fp2ui(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptoui to """ + return builder.build_fp2ui(val, to_ty) + + +def build_ui2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = uitofp to """ + return builder.build_ui2fp(val, to_ty) + + +# ============================================================ +# GEP 指令 +# ============================================================ +def _is_ptr_type(ty: LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Ptr 类型(独立函数,避免嵌套 match 的编译器 BUG)""" + if ty is None: + return 0 + match ty: + case LLVMType.Ptr(pointee): + return 1 + case _: + return 0 + + +def build_gep(builder: IRBuilder | t.CPtr, elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr , , """ + return builder.build_gep(elem_ty, ptr, idx) + + +# ============================================================ +# build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx +# ============================================================ +def build_gep_array(builder: IRBuilder | t.CPtr, array_ty: LLVMType | t.CPtr, + elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx + + 结果类型是 elem_ty* + """ + return builder.build_gep_array(array_ty, elem_ty, ptr, idx) + + +# ============================================================ +# build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx +# ============================================================ +def build_gep_struct(builder: IRBuilder | t.CPtr, struct_ty: LLVMType | t.CPtr, + field_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, field_idx: t.CInt) -> Value | t.CPtr: + """%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + + 结果类型是 field_ty* + """ + return builder.build_gep_struct(struct_ty, field_ty, ptr, field_idx) + + +# ============================================================ +# PhiIncoming: phi 节点的入边 (value, block) 对 +# 继承 GSListNode[PhiIncoming] 获取强类型 Next +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class PhiIncoming(GSListNode[PhiIncoming]): + Val: Value | t.CPtr + Block: BasicBlock | t.CPtr + + +# PhiIncoming 硬编码大小: Next(8) + Val(8) + Block(8) = 24 字节 +PHIINC_SIZE: t.CDefine = 24 + +def new_phi_incoming(pool: memhub.MemBuddy | t.CPtr, + val: Value | t.CPtr, block: BasicBlock | t.CPtr) -> PhiIncoming | t.CPtr: + ptr: PhiIncoming | t.CPtr = pool.alloc(PHIINC_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PHIINC_SIZE) + ptr.Val = val + ptr.Block = block + return ptr + + +# ============================================================ +# Phi 指令 +# ============================================================ +def build_phi(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + incoming_head: PhiIncoming | t.CPtr, count: t.CInt) -> Value | t.CPtr: + """%N = phi [val1, %blk1], [val2, %blk2], ... + + incoming_head 是 PhiIncoming 链表头,count 是入边数量。 + """ + return builder.build_phi(ty, incoming_head, count) + + +# ============================================================ +# SwitchCase: switch 指令的 case 分支 +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class SwitchCase(GSListNode[SwitchCase]): + CaseVal: Value | t.CPtr + Block: BasicBlock | t.CPtr + + +# SwitchCase 硬编码大小: Next(8) + CaseVal(8) + Block(8) = 24 字节 +SWCASE_SIZE: t.CDefine = 24 + +def new_switch_case(pool: memhub.MemBuddy | t.CPtr, + case_val: Value | t.CPtr, block: BasicBlock | t.CPtr) -> SwitchCase | t.CPtr: + ptr: SwitchCase | t.CPtr = pool.alloc(SWCASE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, SWCASE_SIZE) + ptr.CaseVal = case_val + ptr.Block = block + return ptr + + +# ============================================================ +# Switch 指令 +# ============================================================ +def build_switch(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + default_blk: BasicBlock | t.CPtr, + cases_head: SwitchCase | t.CPtr, case_count: t.CInt): + """switch , label % [, label % ...]""" + builder.build_switch(val, default_blk, cases_head, case_count) + + +# ============================================================ +# Select 指令 +# ============================================================ +def build_select(builder: IRBuilder | t.CPtr, cond: Value | t.CPtr, + true_val: Value | t.CPtr, false_val: Value | t.CPtr) -> Value | t.CPtr: + """%N = select i1 , , """ + return builder.build_select(cond, true_val, false_val) + + +# ============================================================ +# Unreachable 指令 +# ============================================================ +def build_unreachable(builder: IRBuilder | t.CPtr): + """unreachable""" + builder.build_unreachable() + + +# ============================================================ +# 原子指令 (Phase 3) +# ============================================================ +# AtomicRMW 操作常量 +ATOMIC_XCHG: t.CDefine = 0 +ATOMIC_ADD: t.CDefine = 1 +ATOMIC_SUB: t.CDefine = 2 +ATOMIC_AND: t.CDefine = 3 +ATOMIC_NAND: t.CDefine = 4 +ATOMIC_OR: t.CDefine = 5 +ATOMIC_XOR: t.CDefine = 6 +ATOMIC_MAX: t.CDefine = 7 +ATOMIC_MIN: t.CDefine = 8 +ATOMIC_UMAX: t.CDefine = 9 +ATOMIC_UMIN: t.CDefine = 10 + +# 内存序常量 +ATOMIC_ORDER_NOTATOMIC: t.CDefine = 0 +ATOMIC_ORDER_UNORDERED: t.CDefine = 1 +ATOMIC_ORDER_MONOTONIC: t.CDefine = 2 +ATOMIC_ORDER_ACQUIRE: t.CDefine = 3 +ATOMIC_ORDER_RELEASE: t.CDefine = 4 +ATOMIC_ORDER_ACQ_REL: t.CDefine = 5 +ATOMIC_ORDER_SEQ_CST: t.CDefine = 6 + + +def _atomic_op_str(op: t.CInt) -> t.CChar | t.CPtr: + if op == ATOMIC_XCHG: return "xchg" + if op == ATOMIC_ADD: return "add" + if op == ATOMIC_SUB: return "sub" + if op == ATOMIC_AND: return "and" + if op == ATOMIC_NAND: return "nand" + if op == ATOMIC_OR: return "or" + if op == ATOMIC_XOR: return "xor" + if op == ATOMIC_MAX: return "max" + if op == ATOMIC_MIN: return "min" + if op == ATOMIC_UMAX: return "umax" + if op == ATOMIC_UMIN: return "umin" + return "xchg" + + +def _atomic_order_str(ord: t.CInt) -> t.CChar | t.CPtr: + if ord == ATOMIC_ORDER_UNORDERED: return "unordered" + if ord == ATOMIC_ORDER_MONOTONIC: return "monotonic" + if ord == ATOMIC_ORDER_ACQUIRE: return "acquire" + if ord == ATOMIC_ORDER_RELEASE: return "release" + if ord == ATOMIC_ORDER_ACQ_REL: return "acq_rel" + if ord == ATOMIC_ORDER_SEQ_CST: return "seq_cst" + return "monotonic" + + +def build_atomicrmw(builder: IRBuilder | t.CPtr, op: t.CInt, + ptr: Value | t.CPtr, val: Value | t.CPtr, + order: t.CInt) -> Value | t.CPtr: + """%N = atomicrmw , """ + return builder.build_atomicrmw(op, ptr, val, order) + + +def build_cmpxchg(builder: IRBuilder | t.CPtr, ptr: Value | t.CPtr, + cmp_val: Value | t.CPtr, new_val: Value | t.CPtr, + succ_order: t.CInt, fail_order: t.CInt) -> Value | t.CPtr: + """%N = cmpxchg , , + + 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) + """ + return builder.build_cmpxchg(ptr, cmp_val, new_val, succ_order, fail_order) + + +# ============================================================ +# va_arg 指令: 从 va_list 读取下一个变长参数 +# ============================================================ +def build_va_arg(builder: IRBuilder | t.CPtr, + va_list_ptr: Value | t.CPtr, + arg_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = va_arg , """ + return builder.build_va_arg(va_list_ptr, arg_ty) + + +# ============================================================ +# 内联汇编 (Phase 3) +# ============================================================ +def build_inline_asm(builder: IRBuilder | t.CPtr, ret_ty: LLVMType | t.CPtr, + asm_text: t.CChar | t.CPtr, constraints: t.CChar | t.CPtr, + has_side_effects: t.CInt) -> Value | t.CPtr: + """%N = call asm [sideeffect] "" ""() + + 简化的内联汇编调用,无参数版本。 + """ + return builder.build_inline_asm(ret_ty, asm_text, constraints, has_side_effects) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' diff --git a/llvmlite/__function.vp b/llvmlite/__function.vp new file mode 100644 index 0000000..8e0577e --- /dev/null +++ b/llvmlite/__function.vp @@ -0,0 +1,811 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import stdio +from linkedlist import GSListNode, GSList +from .__types import LLVMType, ParamNode, TypePrint + + +# ============================================================ +# Line: 指令文本行 +# +# 每条 LLVM IR 指令序列化为一行文本,通过链表组织。 +# 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr +# +# 注意: 必须加 @t.NoVTable。否则 TransPyC 为子类添加 vtable 指针(T*), +# 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位, +# 所有字段访问读取垃圾值(见续 XV 会话根因分析)。 +# ============================================================ +@t.NoVTable +class Line(GSListNode[Line]): + Buf: t.CChar | t.CPtr # 行文本(NUL 结尾) + Len: t.CSizeT # 文本长度(不含 NUL) + + +# ============================================================ +# BasicBlock: 基本块 +# +# 持有名称 + 指令行链表 + 终止指令标志。 +# 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr +# Lines 为 GSList[Line] 指针,提供 O(1) 追加。 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +@t.NoVTable +class BasicBlock(GSListNode[BasicBlock]): + Name: t.CChar | t.CPtr # 块名(如 "entry"/"if.then") + Lines: GSList[Line] | t.CPtr # 指令行链表容器(Head/Tail/Count) + IsTerminated: t.CInt # 1=已有终止指令(br/ret) + + +# ============================================================ +# Param: 函数参数 +# +# 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr +# Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"),None=无属性 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +@t.NoVTable +class Param(GSListNode[Param]): + Ty: LLVMType | t.CPtr # 参数类型 + Name: t.CChar | t.CPtr # 参数名(如 "%0"/"%a") + Attrs: t.CChar | t.CPtr # 参数属性文本(None=无属性) + + +# ============================================================ +# Function: 函数 +# +# 持有名称 + 返回类型 + 参数链表 + 基本块链表。 +# 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr +# Params/Blocks 为 GSList 指针,提供 O(1) 追加。 +# Attrs 存储函数级属性文本(如 "nounwind"/"noinline"),None=无属性 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +@t.NoVTable +class Function(GSListNode[Function]): + Name: t.CChar | t.CPtr # 函数名 + RetTy: LLVMType | t.CPtr # 返回类型 + Params: GSList[Param] | t.CPtr # 参数链表容器 + Blocks: GSList[BasicBlock] | t.CPtr # 基本块链表容器 + IsDeclared: t.CInt # 1=仅声明(declare), 0=定义(define) + IsVarArg: t.CInt # 1=变参函数(...) + Attrs: t.CChar | t.CPtr # 函数属性文本(None=无属性) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节 +LINE_SIZE: t.CDefine = 24 + +def new_line(pool: memhub.MemBuddy | t.CPtr, text: t.CChar | t.CPtr) -> Line | t.CPtr: + """创建一个指令行,复制 text 到新分配的缓冲区""" + ptr: Line | t.CPtr = pool.alloc(LINE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, LINE_SIZE) + if text is not None: + slen: t.CSizeT = string.strlen(text) + buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + if buf is not None: + string.strcpy(buf, text) + ptr.Buf = buf + ptr.Len = slen + return ptr + + +def _new_gslist(pool: memhub.MemBuddy | t.CPtr, list_size: t.CSizeT) -> t.CPtr: + """从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)""" + gsl: t.CPtr = pool.alloc(list_size) + if gsl is None: return None + string.memset(gsl, 0, list_size) + return gsl + + +# BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节 +BLOCK_SIZE: t.CDefine = 32 + +def new_basic_block(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: + """创建一个基本块""" + ptr: BasicBlock | t.CPtr = pool.alloc(BLOCK_SIZE) + if ptr is None: return None + string.memset(ptr, 0, BLOCK_SIZE) + ptr.Name = name + ptr.Lines = _new_gslist(pool, 24) # GSList: Head+Tail+Count + ptr.IsTerminated = 0 + return ptr + + +# Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节 +PARAM_SIZE: t.CDefine = 32 + +def new_param(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Param | t.CPtr: + """创建一个函数参数""" + ptr: Param | t.CPtr = pool.alloc(PARAM_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PARAM_SIZE) + ptr.Ty = ty + ptr.Name = name + ptr.Attrs = None + return ptr + + +# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) = 56 字节 +FUNC_SIZE: t.CDefine = 56 + +def new_function(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr, + ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建一个函数""" + ptr: Function | t.CPtr = pool.alloc(FUNC_SIZE) + if ptr is None: return None + string.memset(ptr, 0, FUNC_SIZE) + ptr.Name = name + ptr.RetTy = ret_ty + ptr.Params = _new_gslist(pool, 24) # GSList: Head+Tail+Count + ptr.Blocks = _new_gslist(pool, 24) + ptr.IsDeclared = 0 + ptr.Attrs = None + return ptr + + +# ============================================================ +# 链表操作(委托 GSList.append) +# ============================================================ +def function_add_param(func: Function | t.CPtr, param: Param | t.CPtr): + """将参数追加到函数参数链表""" + if func is None or param is None: return + if func.Params is None: return + func.Params.append(param) + + +def function_add_block(func: Function | t.CPtr, block: BasicBlock | t.CPtr): + """将基本块追加到函数块链表""" + if func is None or block is None: return + if func.Blocks is None: return + func.Blocks.append(block) + + +def function_move_block_to_end(func: Function | t.CPtr, block: BasicBlock | t.CPtr): + """将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。 + + 用于解决 SSA 名非单调问题:BB 按创建顺序排列,但指令按控制流顺序生成, + 导致 SSA 编号在文本输出时非单调递增,llc 报错。 + 在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。 + + 注意:必须使用 GSList[BasicBlock] 带类型参数,否则 TransPyC 创建不完整 + struct 类型,导致 blocks.Head/Tail/Count 字段访问读取垃圾值。 + """ + if func is None or block is None: return + blocks: GSList[BasicBlock] | t.CPtr = func.Blocks + if blocks is None: return + + # 已经是 Tail,无需移动 + if blocks.Tail is block: + return + + # 从链表中移除 block + if blocks.Head is block: + # block 是 Head,直接后移 Head + blocks.Head = block.Next + else: + # 遍历找前驱 + prev: BasicBlock | t.CPtr = blocks.Head + while prev is not None and prev.Next is not block: + prev = prev.Next + if prev is None: + # block 不在链表中,直接 append + blocks.append(block) + return + prev.Next = block.Next + + # block.Next 由移除逻辑处理,重置为 None + block.Next = None + + # append 到末尾(不调用 blocks.append 以避免 Count 重复递增) + if blocks.Tail is not None: + blocks.Tail.Next = block + blocks.Tail = block + + +def block_append_line(block: BasicBlock | t.CPtr, line: Line | t.CPtr): + """将指令行追加到基本块""" + if block is None or line is None: return + if block.Lines is None: return + block.Lines.append(line) + + +def block_set_terminated(block: BasicBlock | t.CPtr, val: t.CInt): + """设置块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)""" + if block is None: return + block.IsTerminated = val + + +def block_get_terminated(block: BasicBlock | t.CPtr) -> t.CInt: + """获取块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)""" + if block is None: + return 1 + return block.IsTerminated + + +def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr, + text: t.CChar | t.CPtr): + """创建指令行并追加到基本块""" + if block is None or text is None: return + line: Line | t.CPtr = new_line(pool, text) + if line is not None: + block_append_line(block, line) + + +def block_insert_text_before_terminator(pool: memhub.MemBuddy | t.CPtr, + block: BasicBlock | t.CPtr, + text: t.CChar | t.CPtr): + """创建指令行并插入到基本块终止指令之前 + + 如果块未终止,追加到末尾。 + 如果块已终止(有 br/ret),在终止指令之前插入,确保 alloca 等指令 + 不出现在终止指令之后。 + """ + if block is None or text is None: return + if block.Lines is None: return + line: Line | t.CPtr = new_line(pool, text) + if line is None: return + # 块未终止:直接追加 + if block.IsTerminated == 0: + block_append_line(block, line) + return + # 块已终止:在 Tail(终止指令)之前插入 + lines: GSList[Line] | t.CPtr = block.Lines + if lines.Head is None: + block_append_line(block, line) + return + # 只有一个节点:在 Head 之前插入 + if lines.Head is lines.Tail: + line.Next = lines.Head + lines.Head = line + lines.Count += 1 + return + # 找到 Tail 的前驱节点 + prev: Line | t.CPtr = lines.Head + while prev is not None and prev.Next is not lines.Tail: + prev = prev.Next + if prev is None: + # 找不到前驱,回退到追加 + block_append_line(block, line) + return + # 在 prev 和 Tail 之间插入 line + line.Next = lines.Tail + prev.Next = line + lines.Count += 1 + + +# ============================================================ +# 属性设置 +# ============================================================ +def function_set_attrs(func: Function | t.CPtr, attrs: t.CChar | t.CPtr): + """设置函数级属性文本(如 "nounwind"/"noinline")""" + if func is None: return + func.Attrs = attrs + + +def param_set_attrs(param: Param | t.CPtr, attrs: t.CChar | t.CPtr): + """设置参数属性文本(如 "noundef"/"nocapture"/"readonly")""" + if param is None: return + param.Attrs = attrs + + +# ============================================================ +# _ll_name_needs_quote - 检查 LLVM 标识符是否需要加引号 +# +# LLVM IR 规范:标识符合法字符集为 [-a-zA-Z$._][-a-zA-Z$._0-9]* +# 以数字开头或含非合法字符(如 '['、']'、' '、'@' 等)时必须用双引号包围。 +# '.' 是合法字符,不需要加引号(如 @.str、@llvm.memcpy 都不加引号)。 +# SHA1 命名空间的函数名(如 "4dad2ba72ed7ba09.GSListNode[Param]")含 '['、']', +# 需要加引号;但纯 hex+点 的名字(如 "abc.def")不需要。 +# ============================================================ +def _ll_name_needs_quote(name: str) -> t.CInt: + """检查 LLVM 标识符是否需要加引号(以数字开头或含非合法字符) + + LLVM IR 合法字符:a-z, A-Z, 0-9, -, $, ., _ + 首字符是数字时需要加引号(LLVM 要求局部/全局标识符首字符非数字,除非加引号)。 + 含其他字符(如 '['、']'、空格)时需要加引号。 + """ + if name is None: + return 0 + c0: t.CChar = name[0] + if c0 >= '0' and c0 <= '9': + return 1 + name_len: t.CSizeT = string.strlen(name) + i: t.CSizeT = 0 + while i < name_len: + ch: t.CChar = name[i] + # 合法字符:a-z, A-Z, 0-9, -, $, ., _ + if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or + (ch >= '0' and ch <= '9') or ch == '-' or ch == '$' or + ch == '.' or ch == '_'): + return 1 + i += 1 + return 0 + + +# ============================================================ +# RenumberSSA: 重编号函数内数字 SSA 名 +# +# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致 +# SSA 名在文本输出中非单调递增的问题(llc 报错: +# "instruction expected to be numbered '%N' or greater")。 +# +# 现象: entry 块原指令 %0-%6 + br,alloca_at_entry 插入 %28/%41 到 br 之前, +# 文本输出顺序为 entry(%0..%6, %28, %41) → if.then(%7..%27), +# 导致 %28 出现在 %7 之前,llc 拒绝编译。 +# +# 算法: +# 1. 扫描所有 BB 指令行,按文本输出顺序收集数字 SSA 名 %N +# 2. 按首次出现顺序建立 old→new 映射(从 0 递增) +# 3. 替换所有指令行文本中的 %N 为新编号 +# +# 注意: +# - 仅重编号纯数字 SSA 名(%0, %1, ...) +# - 命名 SSA 名(%entry, %.tmp, %self)、块标签、全局符号 @N 不重编号 +# - 仅对 define(有函数体)调用,declare 无函数体无需处理 +# - 当前 TransPyV 参数多为命名(%self/%env/%n),非数字,无需重编号参数 +# ============================================================ + +# 判定字符是否为十进制数字 +def _is_digit_ch(ch: t.CChar) -> t.CInt: + """判断字符是否是 '0'-'9' + + ch 是值类型 (t.CChar = i8),TPC 已修复值类型 is None 处理: + 值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。 + """ + if ch is None: + return 0 + if ch >= '0' and ch <= '9': + return 1 + return 0 + + +# ============================================================ +# i32 数组的安全访问(显式字节偏移) +# +# TransPyC 的 ptr[i] 指针索引可能被当作字节索引(i8*)而非 i32* 索引, +# 导致内存损坏。必须显式计算字节偏移:addr = base + idx * 4,再转型为 i32*。 +# 参见 HandlesTranslator.py:358 的 t.CUInt64T(ptr) + offset * sizeof 用法。 +# ============================================================ +def _map_get_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt) -> t.CInt: + """读取 i32 数组 map_arr[idx](显式字节偏移 idx*4) + + 使用 (t.CInt | t.CPtr)(uint64) 强转将字节偏移转为 i32*,再用 c.Deref 解引用。 + TPC 已修复类型联合强转(_HandleTypeUnionCastLlvm 添加 fallback),此写法可用。 + """ + if map_arr is None: + return -1 + byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4 + elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off) + return c.Deref(elem_ptr) + + +def _map_set_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt, val: t.CInt): + """写入 map_arr[idx] = val(i32 数组,显式字节偏移 idx*4) + + 使用 (t.CInt | t.CPtr)(uint64) 强转 + c.DerefAs 解引用赋值。 + TPC 已修复类型联合强转,此写法可用。 + """ + if map_arr is None: + return + byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4 + elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off) + c.DerefAs(elem_ptr, val) + + +def _scan_max_ssa_in_text(text: t.CChar | t.CPtr, cur_max: t.CInt) -> t.CInt: + """扫描文本,找出 %N(N 为数字)中最大的 N,与 cur_max 比较返回更大值 + + 仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。 + """ + result: t.CInt = cur_max + p: t.CChar | t.CPtr = text + while p is not None and p[0] != '\0': + if p[0] == '%': + nxt: t.CChar | t.CPtr = p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: t.CInt = string.atoi(nxt) + if num > result: + result = num + p = p + 1 + return result + + +def _find_max_ssa_number(func: Function | t.CPtr) -> t.CInt: + """遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1""" + max_n: t.CInt = -1 + if func is None or func.Blocks is None: + return max_n + blk: BasicBlock | t.CPtr = func.Blocks.Head + while blk is not None: + if blk.Lines is not None: + line: Line | t.CPtr = blk.Lines.Head + while line is not None: + if line.Buf is not None: + max_n = _scan_max_ssa_in_text(line.Buf, max_n) + line = line.Next + blk = blk.Next + return max_n + + +def _assign_new_numbers(text: t.CChar | t.CPtr, + map_arr: t.CChar | t.CPtr, + max_n: t.CInt, next_new: t.CInt) -> t.CInt: + """扫描文本,对每个 %N(数字),若 map_arr[N]==-1 则分配 next_new + + 返回更新后的 next_new。按文本首次出现顺序建立映射。 + """ + result: t.CInt = next_new + p: t.CChar | t.CPtr = text + while p is not None and p[0] != '\0': + if p[0] == '%': + nxt: t.CChar | t.CPtr = p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: t.CInt = string.atoi(nxt) + if num >= 0 and num <= max_n: + if _map_get_i32(map_arr, num) == -1: + _map_set_i32(map_arr, num, result) + result += 1 + p = p + 1 + return result + + +def _replace_ssa_numbers(text: t.CChar | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + map_arr: t.CChar | t.CPtr, + max_n: t.CInt) -> t.CChar | t.CPtr: + """构建新文本,将 %N 替换为映射后的新编号 + + 逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。 + 返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。 + """ + src_len: t.CSizeT = string.strlen(text) + # 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64 + new_size: t.CSizeT = src_len * 2 + 64 + new_buf: t.CChar | t.CPtr = pool.alloc(new_size) + if new_buf is None: + return None + # 一次性分配数字缓冲区(循环中复用) + num_buf: t.CChar | t.CPtr = pool.alloc(16) + if num_buf is None: + new_buf[0] = '\0' + return new_buf + + dst_idx: t.CSizeT = 0 + src_p: t.CChar | t.CPtr = text + while src_p is not None and src_p[0] != '\0': + if dst_idx + 16 >= new_size: + # 缓冲区不足,截断 + break + if src_p[0] == '%': + nxt: t.CChar | t.CPtr = src_p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: t.CInt = string.atoi(nxt) + # 先做范围检查再读 map_arr:num 超 max_n 时 map_arr 只有 + # (max_n+1)*4 字节,先读后查会越界读远端内存 + if num >= 0 and num <= max_n: + new_num: t.CInt = _map_get_i32(map_arr, num) + if new_num != -1: + # 写入 '%' + new_buf[dst_idx] = '%' + dst_idx += 1 + # 写入新编号 + num_buf[0] = '\0' + viperlib.snprintf(num_buf, 16, "%d", new_num) + k: t.CSizeT = 0 + while num_buf[k] != '\0' and dst_idx + 1 < new_size: + new_buf[dst_idx] = num_buf[k] + dst_idx += 1 + k += 1 + # 跳过旧数字字符 + src_p = src_p + 1 + while src_p is not None and _is_digit_ch(src_p[0]) != 0: + src_p = src_p + 1 + continue + # 普通字符:直接复制 + new_buf[dst_idx] = src_p[0] + dst_idx += 1 + src_p = src_p + 1 + + new_buf[dst_idx] = '\0' + return new_buf + + +def RenumberSSA(func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增 + + 在 FunctionPrint 序列化函数体之前调用。 + 仅对 define(IsDeclared==0)且 Blocks 非空 的函数生效。 + """ + if func is None or pool is None: + return + if func.IsDeclared == 1: + return # declare 无函数体 + if func.Blocks is None: + return + + # 1. 第一遍扫描:找出最大 SSA 编号 + max_n: t.CInt = _find_max_ssa_number(func) + if max_n < 0: + return # 无数字 SSA 名 + + # 2. 分配并初始化映射数组 map_arr[0..max_n] = -1 + # 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。 + # 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。 + # 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。 + map_bytes: t.CSizeT = (max_n + 1) * 4 # t.CInt = 4 字节 + map_arr: t.CChar | t.CPtr = pool.alloc(map_bytes) + if map_arr is None: + return + string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1 + + # 3. 第二遍扫描:按文本顺序分配新编号 + next_new: t.CInt = 0 + blk: BasicBlock | t.CPtr = func.Blocks.Head + while blk is not None: + if blk.Lines is not None: + line: Line | t.CPtr = blk.Lines.Head + while line is not None: + if line.Buf is not None: + next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new) + line = line.Next + blk = blk.Next + + # 4. 检查是否有需要重编号的(old != new) + need_renumber: t.CInt = 0 + i: t.CInt = 0 + while i <= max_n: + v: t.CInt = _map_get_i32(map_arr, i) + if v != -1 and v != i: + need_renumber = 1 + break + i += 1 + if need_renumber == 0: + return # 编号已单调,无需替换 + + # 5. 第三遍扫描:替换所有指令行文本 + blk = func.Blocks.Head + while blk is not None: + if blk.Lines is not None: + line: Line | t.CPtr = blk.Lines.Head + while line is not None: + if line.Buf is not None: + new_buf: t.CChar | t.CPtr = _replace_ssa_numbers( + line.Buf, pool, map_arr, max_n) + if new_buf is not None: + line.Buf = new_buf + line.Len = string.strlen(new_buf) + line = line.Next + blk = blk.Next + + +# ============================================================ +# FunctionPrint: 将函数序列化为 IR 文本 +# +# 格式: +# define @() { +# : +# +# +# : +# +# } +# ============================================================ +def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """将函数 func 序列化为 IR 文本写入 buf""" + if func is None or buf is None or size == 0: return + + # 在序列化前重编号数字 SSA 名,确保按文本输出顺序单调递增。 + # 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致 + # SSA 名非单调(llc 报错 "instruction expected to be numbered '%N' or greater")。 + # RenumberSSA 内部会跳过 declare 函数(IsDeclared==1),无需在此判断。 + RenumberSSA(func, pool) + + ty_buf: t.CChar | t.CPtr = pool.alloc(128) + if ty_buf is None: return + ty_buf[0] = '\0' + + # define @() + if func.IsDeclared == 1: + _append_cstr(buf, size, "declare ") + else: + # 泛型特化类方法(如 GSList[NameEntry].__before_init__):多个模块各自 + # 特化生成同名定义 → ld.lld duplicate symbol warning。特化方法代码由 + # 相同模板+类型参数生成,定义相同,输出 linkonce_odr 让链接器合并。 + if func.Name is not None and string.strchr(func.Name, 91) is not None: + _append_cstr(buf, size, "define linkonce_odr ") + else: + _append_cstr(buf, size, "define ") + ty_buf[0] = '\0' + TypePrint(ty_buf, 128, func.RetTy, pool) + _append_cstr(buf, size, ty_buf) + _append_cstr(buf, size, " @") + if func.Name is not None: + if _ll_name_needs_quote(func.Name) != 0: + _append_cstr(buf, size, "\"") + _append_cstr(buf, size, func.Name) + _append_cstr(buf, size, "\"") + else: + _append_cstr(buf, size, func.Name) + _append_cstr(buf, size, "(") + + # 参数列表(从 GSList[Param].Head 遍历) + cur: Param | t.CPtr = None + if func.Params is not None: + cur = func.Params.Head + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(buf, size, ", ") + # 参数属性(如 "noundef"/"nocapture")在类型之前 + if cur.Attrs is not None: + _append_cstr(buf, size, cur.Attrs) + _append_cstr(buf, size, " ") + ty_buf[0] = '\0' + TypePrint(ty_buf, 128, cur.Ty, pool) + _append_cstr(buf, size, ty_buf) + # declare 和 define 都打印参数名(如果有) + if cur.Name is not None: + _append_cstr(buf, size, " ") + # LLVM IR 要求参数名以 % 开头 + if cur.Name[0] != '%': + _append_cstr(buf, size, "%") + _append_cstr(buf, size, cur.Name) + cur = cur.Next + first = 0 + # 变参函数追加 ... + if func.IsVarArg == 1: + if func.Params is not None and func.Params.Head is not None: + _append_cstr(buf, size, ", ...") + else: + _append_cstr(buf, size, "...") + _append_cstr(buf, size, ")") + + # 函数级属性(如 "nounwind"/"noinline")在 ) 之后 + if func.Attrs is not None: + _append_cstr(buf, size, " ") + _append_cstr(buf, size, func.Attrs) + + if func.IsDeclared == 1: + _append_cstr(buf, size, "\n") + return + + # 函数体 + _append_cstr(buf, size, " {\n") + + blk: BasicBlock | t.CPtr = None + if func.Blocks is not None: + blk = func.Blocks.Head + while blk is not None: + # 块标签 + if blk.Name is not None: + _append_cstr(buf, size, blk.Name) + _append_cstr(buf, size, ":\n") + # 指令行(从 GSList[Line].Head 遍历) + line: Line | t.CPtr = None + if blk.Lines is not None: + line = blk.Lines.Head + has_lines: t.CInt = 0 + while line is not None: + if line.Buf is not None: + _append_cstr(buf, size, " ") + _append_cstr(buf, size, line.Buf) + _append_cstr(buf, size, "\n") + has_lines = 1 + line = line.Next + # 块未终止兜底:LLVM IR 要求每个基本块以终止指令(br/ret/unreachable)结尾。 + # 两种情况需要补 unreachable: + # 1. 空块(has_lines==0):标签后无任何指令 + # 2. 有指令但未终止(IsTerminated==0):如 break/continue 后的 dead.N 块 + # 被后续语句填入指令但缺少终止符,导致下一个标签处报 + # "expected instruction opcode" + if has_lines == 0 or blk.IsTerminated == 0: + _append_cstr(buf, size, " unreachable\n") + blk = blk.Next + + _append_cstr(buf, size, "}\n") + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型 +# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过 +# 字段访问(不生成 GEP,不报错),字段值永远为 null。 +# +# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问 +# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。 +# ============================================================ +def function_get_name(func: Function | t.CPtr) -> t.CChar | t.CPtr: + """获取函数名""" + if func is None: + return None + return func.Name + + +def function_get_ret_ty(func: Function | t.CPtr) -> LLVMType | t.CPtr: + """获取函数返回类型""" + if func is None: + return None + return func.RetTy + + +def function_get_params(func: Function | t.CPtr) -> GSList[Param] | t.CPtr: + """获取函数参数链表容器""" + if func is None: + return None + return func.Params + + +def function_get_param_head(func: Function | t.CPtr) -> Param | t.CPtr: + """获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)""" + if func is None: + return None + if func.Params is None: + return None + return func.Params.Head + + +def function_get_next(func: Function | t.CPtr) -> Function | t.CPtr: + """获取链表下一个函数""" + if func is None: + return None + return func.Next + + +def function_is_declared(func: Function | t.CPtr) -> t.CInt: + """获取函数是否为声明(1=declare 仅声明, 0=define 定义)""" + if func is None: + return 0 + return func.IsDeclared + + +def param_get_name(param: Param | t.CPtr) -> t.CChar | t.CPtr: + """获取参数名""" + if param is None: + return None + return param.Name + + +def param_get_ty(param: Param | t.CPtr) -> LLVMType | t.CPtr: + """获取参数类型""" + if param is None: + return None + return param.Ty + + +def param_get_next(param: Param | t.CPtr) -> Param | t.CPtr: + """获取链表下一个参数""" + if param is None: + return None + return param.Next diff --git a/llvmlite/__init__.vp b/llvmlite/__init__.vp new file mode 100644 index 0000000..581560a --- /dev/null +++ b/llvmlite/__init__.vp @@ -0,0 +1,423 @@ +import t, c +from stdint import * +import memhub +import string +import viperlib + +# 导入子模块 +from .__types import ( + LLVMType, ParamNode, LLVMTypeCore, + Int1, Int8, Int16, Int32, Int64, Ptr, Func, Void, Array, Struct, + Half, Float, Double, FP128, Label, + new_param_node, param_list_append, + paramnode_get_ty, paramnode_get_next, paramnode_set_ty, paramnode_set_next, + TypePrint, PrintStructDefinition, get_struct_name, + get_struct_fields, get_struct_fcount, DeepCopyType, +) +from .__values import ( + Value, new_value, ConstInt, ConstNull, ConstZero, ConstFloat, SSAValue, ValuePrint, + value_get_ty, value_get_next, + value_set_ty, value_set_next, value_set_name, value_set_isconst, +) +from .__function import ( + Line, BasicBlock, Param, Function, + new_line, new_basic_block, new_param, new_function, + function_add_param, function_add_block, + block_append_line, block_append_text, + function_set_attrs, param_set_attrs, + function_get_name, function_get_ret_ty, function_get_params, + function_get_param_head, function_get_next, function_is_declared, + param_get_name, param_get_ty, param_get_next, + FunctionPrint, +) +from .__module import ( + LLVMModule, GlobalVariable, NamedTypeNode, new_module, new_global_variable, + module_add_function, module_add_global, module_add_named_type, + module_set_target, module_set_datalayout, + global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section, + LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT, + module_ensure_opaque_for_type, +) +from .__builder import ( + IRBuilder, new_builder, position_at_end, + builder_cur_block_is_terminated, + build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store, + build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem, + build_and, build_or, build_xor, build_shl, build_lshr, build_ashr, + build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg, + build_icmp, build_fcmp, + build_br, build_cond_br, build_ret, build_ret_void, + build_call, build_call_indirect, build_bitcast, build_sext, build_trunc, build_zext, + build_ptrtoint, build_inttoptr, + build_fpext, build_fptrunc, build_fp2si, build_si2fp, build_fp2ui, build_ui2fp, + build_gep, build_gep_array, build_gep_struct, + build_phi, build_switch, build_select, build_unreachable, + build_atomicrmw, build_cmpxchg, build_inline_asm, build_va_arg, + PhiIncoming, new_phi_incoming, SwitchCase, new_switch_case, + ICMP_EQ, ICMP_NE, ICMP_SGT, ICMP_SGE, ICMP_SLT, ICMP_SLE, + ICMP_UGT, ICMP_UGE, ICMP_ULT, ICMP_ULE, + FCMP_FALSE, FCMP_OEQ, FCMP_OGT, FCMP_OGE, FCMP_OLT, FCMP_OLE, + FCMP_ONE, FCMP_ORD, FCMP_UNO, FCMP_UEQ, FCMP_UGT, FCMP_UGE, + FCMP_ULT, FCMP_ULE, FCMP_UNE, FCMP_TRUE, + ATOMIC_XCHG, ATOMIC_ADD, ATOMIC_SUB, ATOMIC_AND, ATOMIC_NAND, + ATOMIC_OR, ATOMIC_XOR, ATOMIC_MAX, ATOMIC_MIN, ATOMIC_UMAX, ATOMIC_UMIN, + ATOMIC_ORDER_NOTATOMIC, ATOMIC_ORDER_UNORDERED, ATOMIC_ORDER_MONOTONIC, + ATOMIC_ORDER_ACQUIRE, ATOMIC_ORDER_RELEASE, ATOMIC_ORDER_ACQ_REL, + ATOMIC_ORDER_SEQ_CST, +) +from .__verify import ( + VerifyResult, NameEntry, + verify_function, verify_module, + VERIFY_OK, VERIFY_ERR_NO_TERMINATOR, VERIFY_ERR_DUPLICATE_DEF, + VERIFY_ERR_UNDEFINED_USE, VERIFY_ERR_PHI_NOT_FIRST, + _new_verify_result, +) + + +# ============================================================ +# 便捷工厂: 字符串复制 +# ============================================================ +def _str_dup(pool: memhub.MemBuddy | t.CPtr, src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """从 pool 分配并复制一个 C 字符串""" + if src is None: return None + slen: t.CSizeT = string.strlen(src) + buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + if buf is None: return None + string.strcpy(buf, src) + return buf + + +# ============================================================ +# 便捷工厂: 创建带名称的基本块 +# ============================================================ +def create_block(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr, + name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: + """创建基本块并添加到函数""" + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + blk: BasicBlock | t.CPtr = new_basic_block(pool, name_dup) + if blk is not None: + function_add_block(func, blk) + return blk + + +# ============================================================ +# 便捷工厂: 创建整数常量值 +# ============================================================ +def const_int(pool: memhub.MemBuddy | t.CPtr, bits: t.CInt, + val: t.CInt64T) -> Value | t.CPtr: + """创建整数常量值(自动创建类型 + 名字文本) + + 参数: + bits: 位宽 (1/8/16/32/64) + val: 整数值 + """ + # 创建类型 + ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if ty is None: return None + string.memset(ty, 0, LLVMType.__sizeof__()) + c.DerefAs(ty, LLVMType.Int(bits)) + + # 创建名字文本 + name: t.CChar | t.CPtr = pool.alloc(32) + if name is None: return None + viperlib.snprintf(name, 32, "%lld", val) + + return ConstInt(pool, ty, val, name) + + +def const_int32(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr: + """便捷: 创建 i32 整数常量""" + return const_int(pool, 32, val) + + +def const_int64(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr: + """便捷: 创建 i64 整数常量""" + return const_int(pool, 64, val) + + +# ============================================================ +# 便捷工厂: 创建函数并添加到模块 +# ============================================================ +def create_function(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建函数并添加到模块""" + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + func: Function | t.CPtr = new_function(pool, name_dup, ret_ty) + if func is not None: + module_add_function(mod, func) + return func + + +def add_param(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr, + ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Param | t.CPtr: + """创建参数并添加到函数""" + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + param: Param | t.CPtr = new_param(pool, ty, name_dup) + if param is not None: + function_add_param(func, param) + return param + + +# ============================================================ +# 便捷工厂: 创建函数声明(declare) +# ============================================================ +def create_declare(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建函数声明(declare,无函数体)并添加到模块 + + 与 create_function 不同,声明不生成函数体,仅生成: + declare @() + """ + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + func: Function | t.CPtr = new_function(pool, name_dup, ret_ty) + if func is not None: + func.IsDeclared = 1 + module_add_function(mod, func) + return func + + +# ============================================================ +# 便捷工厂: 创建字符串常量全局变量 +# +# 生成 LLVM IR: +# @.str = private unnamed_addr constant [N x i8] c"contents\00" +# ============================================================ +def create_global_string(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr: + """创建字符串常量全局变量并添加到模块 + + 参数: + name: 全局变量名(如 ".str") + text: 字符串内容(C 字符串,不含末尾 NUL,NUL 由本函数自动添加) + + 返回: GlobalVariable 指针,其类型为 [len+1 x i8] + """ + if text is None: return None + slen: t.CSizeT = string.strlen(text) + count: t.CInt = slen + 1 # 含末尾 NUL + + # 创建 i8 类型 + i8_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if i8_ty is None: return None + string.memset(i8_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i8_ty, LLVMType.Int(8)) + + # 创建 [count x i8] 数组类型 + arr_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if arr_ty is None: return None + string.memset(arr_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(arr_ty, LLVMType.Array(i8_ty, count)) + + # 创建全局变量 + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, arr_ty) + if gv is None: return None + + # 设置属性: private + unnamed_addr + constant + global_set_linkage(gv, "private") + global_set_unnamed_addr(gv, 1) + global_set_constant(gv, 1) + + # 构造初始化值文本: c"contents\00" + # LLVM IR 字符串字面量格式: c"" 其中 " 和 \ 及非打印字符用 \xx 转义 + # 缓冲区大小: 最坏情况每个字符4字节(\xx)+ c"..." + \00 + " + init_buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8) + if init_buf is None: return None + pos: t.CSizeT = 0 + init_buf[pos] = 'c' + pos += 1 + init_buf[pos] = '"' + pos += 1 + i: t.CSizeT = 0 + while i < slen: + ch: t.CUInt8T = text[i] + if ch == 0x22 or ch == 0x5C or ch < 0x20 or ch >= 0x7F: + # 需要转义: " → \22, \ → \5c, 非打印字符 → \xx + init_buf[pos] = '\\' + pos += 1 + hi: t.CInt = (ch >> 4) & 0x0F + lo: t.CInt = ch & 0x0F + if hi < 10: + init_buf[pos] = 0x30 + hi + else: + init_buf[pos] = 0x61 + hi - 10 + pos += 1 + if lo < 10: + init_buf[pos] = 0x30 + lo + else: + init_buf[pos] = 0x61 + lo - 10 + pos += 1 + else: + init_buf[pos] = ch + pos += 1 + i += 1 + # 末尾 NUL 字节 + init_buf[pos] = '\\' + pos += 1 + init_buf[pos] = '0' + pos += 1 + init_buf[pos] = '0' + pos += 1 + init_buf[pos] = '"' + pos += 1 + init_buf[pos] = '\0' + gv.Initializer = init_buf + + module_add_global(mod, gv) + return gv + + +# ============================================================ +# 便捷工厂: 创建带初始化值的整数全局变量 +# ============================================================ +def create_global_int(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr: + """创建整数全局变量并添加到模块 + + 生成 LLVM IR: + @ = global i + """ + # 创建整数类型 + ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if ty is None: return None + string.memset(ty, 0, LLVMType.__sizeof__()) + c.DerefAs(ty, LLVMType.Int(bits)) + + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, ty) + if gv is None: return None + + # 构造初始化值文本: "42" (类型由 _print_global 单独打印) + init_buf: t.CChar | t.CPtr = pool.alloc(48) + if init_buf is None: return None + viperlib.snprintf(init_buf, 48, "%lld", val) + gv.Initializer = init_buf + + module_add_global(mod, gv) + return gv + + +# ============================================================ +# LLVMModuleCore: 模块/函数/值创建核心,封装 pool 避免重复传参 +# +# 用法: +# mcore: LLVMModuleCore | t.CPtr = LLVMModuleCore(pool) +# mod: LLVMModule | t.CPtr = mcore.NewModule("test") +# func: Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) +# val: Value | t.CPtr = mcore.ConstInt32(42) +# ============================================================ +@t.NoVTable +class LLVMModuleCore: + """模块/函数/值创建核心,封装 pool 避免每次创建都传 pool""" + Pool: memhub.MemBuddy | t.CPtr + + def __init__(self, pool: memhub.MemBuddy | t.CPtr): + self.Pool = pool + + # ---- 模块操作 ---- + def NewModule(self, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr: + return new_module(self.Pool, name) + + def CreateFunction(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + return create_function(self.Pool, mod, name, ret_ty) + + def CreateDeclare(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建函数声明(declare,无函数体)""" + return create_declare(self.Pool, mod, name, ret_ty) + + def AddParam(self, func: Function | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Param | t.CPtr: + return add_param(self.Pool, func, ty, name) + + def FunctionSetAttrs(self, func: Function | t.CPtr, attrs: t.CChar | t.CPtr): + """设置函数级属性文本""" + function_set_attrs(func, attrs) + + def ParamSetAttrs(self, param: Param | t.CPtr, attrs: t.CChar | t.CPtr): + """设置参数属性文本""" + param_set_attrs(param, attrs) + + def CreateBlock(self, func: Function | t.CPtr, + name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: + return create_block(self.Pool, func, name) + + def NewBuilder(self, func: Function | t.CPtr) -> IRBuilder | t.CPtr: + return new_builder(self.Pool, func) + + # ---- 全局变量 ---- + def NewGlobal(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr: + """创建全局变量并添加到模块""" + name_dup: t.CChar | t.CPtr = _str_dup(self.Pool, name) + gv: GlobalVariable | t.CPtr = new_global_variable(self.Pool, name_dup, ty) + if gv is not None: + module_add_global(mod, gv) + return gv + + def CreateGlobalString(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr: + """创建字符串常量全局变量""" + return create_global_string(self.Pool, mod, name, text) + + def CreateGlobalInt(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr: + """创建带初始化值的整数全局变量""" + return create_global_int(self.Pool, mod, name, bits, val) + + def GlobalSetConstant(self, gv: GlobalVariable | t.CPtr, is_const: t.CInt): + global_set_constant(gv, is_const) + + def GlobalSetLinkage(self, gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr): + global_set_linkage(gv, linkage) + + def GlobalSetUnnamedAddr(self, gv: GlobalVariable | t.CPtr, level: t.CInt): + global_set_unnamed_addr(gv, level) + + def GlobalSetSection(self, gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr): + global_set_section(gv, section) + + # ---- 值创建 ---- + def ConstInt(self, bits: t.CInt, val: t.CInt64T) -> Value | t.CPtr: + return const_int(self.Pool, bits, val) + + def ConstInt32(self, val: t.CInt64T) -> Value | t.CPtr: + return const_int32(self.Pool, val) + + def ConstInt64(self, val: t.CInt64T) -> Value | t.CPtr: + return const_int64(self.Pool, val) + + def ConstFloat(self, ty: LLVMType | t.CPtr, val: t.CDouble) -> Value | t.CPtr: + return ConstFloat(self.Pool, ty, val) + + def SSAValue(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr: + return SSAValue(self.Pool, ty, name) + + def ConstNull(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr: + return ConstNull(self.Pool, ty, name) + + # ---- 打印 ---- + def PrintValue(self, buf: t.CChar | t.CPtr, size: t.CSizeT, val: Value | t.CPtr): + ValuePrint(buf, size, val, self.Pool) + + def PrintFunction(self, buf: t.CChar | t.CPtr, size: t.CSizeT, func: Function | t.CPtr): + FunctionPrint(buf, size, func, self.Pool) + + def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, mod: LLVMModule | t.CPtr): + LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL) + + # ---- SSA 验证 ---- + def NewVerifyResult(self, buf_size: t.CSizeT) -> VerifyResult | t.CPtr: + """创建验证结果对象(buf_size 为错误消息缓冲区大小)""" + return _new_verify_result(self.Pool, buf_size) + + def VerifyFunction(self, func: Function | t.CPtr, + result: VerifyResult | t.CPtr) -> t.CInt: + """验证单个函数的 SSA 正确性,返回错误数(0=通过)""" + return verify_function(self.Pool, func, result) + + def VerifyModule(self, mod: LLVMModule | t.CPtr, + result: VerifyResult | t.CPtr) -> t.CInt: + """验证模块中所有函数的 SSA 正确性,返回错误数(0=通过)""" + return verify_module(self.Pool, mod, result) diff --git a/llvmlite/__module.vp b/llvmlite/__module.vp new file mode 100644 index 0000000..cc96d15 --- /dev/null +++ b/llvmlite/__module.vp @@ -0,0 +1,638 @@ +import t, c +from stdint import * +import string +import stdio +import stdlib +import viperlib +import memhub +from linkedlist import GSList, GSListNode +from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, ParamNode +from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param + + +# ============================================================ +# GlobalVariable: LLVM IR 全局变量 +# +# 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。 +# 继承 GSListNode[GlobalVariable] 获取强类型 Next。 +# ============================================================ +@t.NoVTable +class GlobalVariable(GSListNode[GlobalVariable]): + Name: t.CChar | t.CPtr # 全局变量名(如 ".str" / "my_global") + Ty: LLVMType | t.CPtr # 变量类型 + Initializer: t.CVoid | t.CPtr # 初始化值 Value*(None = 无初始化) + IsConstant: t.CInt # 1=constant, 0=variable + Linkage: t.CChar | t.CPtr # 链接类型("private"/"internal"/"external"/...) + Section: t.CChar | t.CPtr # 段名(None = 默认) + UnnamedAddr: t.CInt # 1=unnamed_addr, 2=local_unnamed_addr, 0=none + + +# ============================================================ +# NamedTypeNode: 命名结构体类型链表节点 +# +# 持有 LLVMType* 指针(必须是命名 Struct 类型)。 +# 继承 GSListNode[NamedTypeNode] 获取强类型 Next。 +# ============================================================ +@t.NoVTable +class NamedTypeNode(GSListNode[NamedTypeNode]): + Ty: LLVMType | t.CPtr # 命名结构体类型指针 + + +# ============================================================ +# LLVMModule: LLVM IR 模块容器 +# +# 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针, +# 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。 +# LLVMModulePrint 输出完整 .ll 文件内容。 +# 注意: 类名必须为 LLVMModule 而非 Module,避免与 ast.Module 命名冲突 +# ============================================================ +@t.NoVTable +class LLVMModule: + Name: t.CChar | t.CPtr # 模块名 + FuncHead: Function | t.CPtr # 函数链表头 + FuncTail: Function | t.CPtr # 函数链表尾 + FuncCount: t.CSizeT # 函数计数 + GlobalHead: GlobalVariable | t.CPtr # 全局变量链表头 + GlobalTail: GlobalVariable | t.CPtr # 全局变量链表尾 + GlobalCount: t.CSizeT # 全局变量计数 + TargetTriple: t.CChar | t.CPtr # 目标三元组(如 "x86_64-pc-linux-gnu") + DataLayout: t.CChar | t.CPtr # 数据布局(如 "e-m:e-p270:32:32-...") + NamedTypeHead: NamedTypeNode | t.CPtr # 命名结构体类型链表头 + NamedTypeTail: NamedTypeNode | t.CPtr # 命名结构体类型链表尾 + NamedTypeCount: t.CSizeT # 命名结构体类型计数 + # 总计: 12 字段 * 8 = 96 字节(无 vtable) + + # ============================================================ + # 实例方法(对象化重构:原 module_* 顶层函数改写为方法, + # 原顶层函数保留为一行委托) + # ============================================================ + + # ---- 链表操作 ---- + def add_function(self, func: Function | t.CPtr): + """将函数追加到模块函数链表(O(1))""" + if self is None or func is None: return + func.Next = None + if self.FuncHead is None: + self.FuncHead = func + else: + self.FuncTail.Next = func + self.FuncTail = func + self.FuncCount += 1 + + def add_global(self, gv: GlobalVariable | t.CPtr): + """将全局变量追加到模块全局变量链表(O(1))""" + if self is None or gv is None: return + gv.Next = None + if self.GlobalHead is None: + self.GlobalHead = gv + else: + self.GlobalTail.Next = gv + self.GlobalTail = gv + self.GlobalCount += 1 + + # ---- 目标属性 ---- + def set_target(self, triple: t.CChar | t.CPtr): + """设置目标三元组""" + if self is None: return + self.TargetTriple = triple + + def set_datalayout(self, layout: t.CChar | t.CPtr): + """设置数据布局""" + if self is None: return + self.DataLayout = layout + + # ---- 命名结构体类型管理 ---- + def add_named_type(self, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr): + """将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行) + + 非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。 + 按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。 + """ + if self is None or pool is None or ty is None: + return + name: t.CChar | t.CPtr = get_struct_name(ty) + if name is None: + return + # 去重检查(opaque 声明可被完整定义替换) + cur: NamedTypeNode | t.CPtr = self.NamedTypeHead + cnt_dedup: t.CInt = 0 + while cur is not None: + # 步数守卫:NamedTypeHead 链表成环(内存损坏/插入 bug)会导致 + # 无限遍历挂起(G3 编译 LinkedNode.prepend 挂起根因)。 + # 正常链表节点数远小于此上限,超限即链表损坏 → 立即报错终止。 + cnt_dedup += 1 + if cnt_dedup > 100000: + stdio.printf("[ANT-LOOP] NamedTypeHead 链表疑似成环, name=%s, 遍历节点=%d, 强制终止\n", + name if name is not None else "(null)", cnt_dedup) + stdlib.exit(1) + if cur.Ty is not None: + existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty) + if existing_name is not None: + if string.strcmp(existing_name, name) == 0: + # 已有完整定义则无需替换 + if _is_opaque_struct(cur.Ty) == 0: + return + # 已有 opaque,新类型也是 opaque 则不重复 + if _is_opaque_struct(ty) != 0: + return + # 用完整定义替换 opaque 声明(原地替换 Ty 指针) + cur.Ty = ty + return + cur = cur.Next + # 创建新节点 + node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE) + if node is None: + return + string.memset(node, 0, NAMED_TYPE_NODE_SIZE) + node.Ty = ty + # opaque 类型插入链表头部,确保在引用它的完整定义之前声明。 + # 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明 + # 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。 + # 完整定义追加到链表尾部,保持原有顺序。 + if _is_opaque_struct(ty) != 0: + node.Next = self.NamedTypeHead + if self.NamedTypeHead is None: + self.NamedTypeTail = node + self.NamedTypeHead = node + else: + node.Next = None + if self.NamedTypeHead is None: + self.NamedTypeHead = node + else: + self.NamedTypeTail.Next = node + self.NamedTypeTail = node + self.NamedTypeCount += 1 + + def _is_type_defined_in_module(self, name: t.CChar | t.CPtr) -> int: + """检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义""" + if self is None or name is None: + return 0 + cur: NamedTypeNode | t.CPtr = self.NamedTypeHead + cnt_tdm: t.CInt = 0 + while cur is not None: + # 步数守卫:同上,防 NamedTypeHead 链表成环无限遍历 + cnt_tdm += 1 + if cnt_tdm > 100000: + stdio.printf("[TDM-LOOP] NamedTypeHead 链表疑似成环, name=%s, 强制终止\n", + name if name is not None else "(null)") + stdlib.exit(1) + if cur.Ty is not None: + existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty) + if existing_name is not None: + if string.strcmp(existing_name, name) == 0: + return 1 + cur = cur.Next + return 0 + + def ensure_opaque_for_type(self, pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr): + """为类型中的跨模块结构体引用添加 opaque 声明 + + 当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, + 如果该名称未在模块中定义,则添加 opaque 声明。 + """ + _scan_type_for_cross_module_refs(pool, self, ty) + + # ---- 打印 ---- + def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pool: memhub.MemBuddy | t.CPtr, mode: t.CInt): + """将模块序列化为 .ll 文本写入 buf""" + if self is None or buf is None or size == 0: return + + # 头部注释(stub 和 full 模式输出,text 模式不输出) + if mode == OUTPUT_FULL or mode == OUTPUT_STUB: + _append_cstr(buf, size, "; ModuleID = '") + if self.Name is not None: + _append_cstr(buf, size, self.Name) + _append_cstr(buf, size, "'\n") + + # 目标三元组 + if self.TargetTriple is not None: + _append_cstr(buf, size, "target triple = \"") + _append_cstr(buf, size, self.TargetTriple) + _append_cstr(buf, size, "\"\n") + + # 数据布局 + if self.DataLayout is not None: + _append_cstr(buf, size, "target datalayout = \"") + _append_cstr(buf, size, self.DataLayout) + _append_cstr(buf, size, "\"\n") + + # 空行 + _append_cstr(buf, size, "\n") + + # 命名结构体类型定义(stub 和 full 模式输出,text 模式不输出) + if mode == OUTPUT_FULL or mode == OUTPUT_STUB: + # 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义 + # 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义 + # 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册 + func_scan: Function | t.CPtr = self.FuncHead + while func_scan is not None: + if func_scan.RetTy is not None: + self.ensure_opaque_for_type(pool, func_scan.RetTy) + if func_scan.Params is not None: + param_scan: Param | t.CPtr = func_scan.Params.Head + while param_scan is not None: + if param_scan.Ty is not None: + self.ensure_opaque_for_type(pool, param_scan.Ty) + param_scan = param_scan.Next + func_scan = func_scan.Next + nt: NamedTypeNode | t.CPtr = self.NamedTypeHead + # 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够 + # 在循环外分配一次并复用,减少 pool 碎片 + ty_buf: t.CChar | t.CPtr = pool.alloc(4096) + while nt is not None: + if nt.Ty is not None: + if ty_buf is not None: + ty_buf[0] = '\0' + PrintStructDefinition(ty_buf, 4096, nt.Ty, pool) + _append_cstr(buf, size, ty_buf) + _append_cstr(buf, size, "\n") + nt = nt.Next + + if self.NamedTypeHead is not None: + _append_cstr(buf, size, "\n") + + # 全局变量 + gv: GlobalVariable | t.CPtr = self.GlobalHead + if mode == OUTPUT_STUB: + # stub 模式:输出 external global(无初值) + while gv is not None: + _print_global_stub(buf, size, gv, pool) + _append_cstr(buf, size, "\n") + gv = gv.Next + else: + # full 和 text 模式:输出完整全局变量 + # text 模式跳过无初值的全局变量(纯声明) + gv_idx: t.CInt = 0 + while gv is not None: + if mode == OUTPUT_TEXT and gv.Initializer is None: + gv = gv.Next + gv_idx += 1 + continue + _print_global(buf, size, gv, pool) + _append_cstr(buf, size, "\n") + gv = gv.Next + gv_idx += 1 + + if self.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB): + _append_cstr(buf, size, "\n") + elif self.GlobalHead is not None and mode == OUTPUT_TEXT: + # text 模式下如果输出了全局变量,也加空行 + had_global: t.CInt = 0 + gv2: GlobalVariable | t.CPtr = self.GlobalHead + while gv2 is not None: + if gv2.Initializer is not None: + had_global = 1 + break + gv2 = gv2.Next + if had_global != 0: + _append_cstr(buf, size, "\n") + + # 遍历函数 + func: Function | t.CPtr = self.FuncHead + func_idx: t.CInt = 0 + while func is not None: + if mode == OUTPUT_STUB: + # stub 模式:仅输出 declare(IsDeclared==1) + if func.IsDeclared == 1: + FunctionPrint(buf, size, func, pool) + _append_cstr(buf, size, "\n") + elif mode == OUTPUT_TEXT: + # text 模式:仅输出 define(IsDeclared==0) + if func.IsDeclared == 0: + FunctionPrint(buf, size, func, pool) + _append_cstr(buf, size, "\n") + else: + # full 模式:输出所有函数 + FunctionPrint(buf, size, func, pool) + _append_cstr(buf, size, "\n") + func = func.Next + func_idx += 1 + + +# ============================================================ +# 工厂函数 +# ============================================================ +def new_module(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr: + """创建一个模块""" + # 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable) + ptr: LLVMModule | t.CPtr = pool.alloc(96) + if ptr is None: return None + string.memset(ptr, 0, 96) + ptr.Name = name + ptr.FuncHead = None + ptr.FuncTail = None + ptr.FuncCount = 0 + ptr.GlobalHead = None + ptr.GlobalTail = None + ptr.GlobalCount = 0 + ptr.TargetTriple = None + ptr.DataLayout = None + ptr.NamedTypeHead = None + ptr.NamedTypeTail = None + ptr.NamedTypeCount = 0 + return ptr + + +# GlobalVariable 硬编码大小: Next(8) + Name(8) + Ty(8) + Initializer(8) + IsConstant(4) + Linkage(8) + Section(8) + UnnamedAddr(4) = 64 字节 +GV_SIZE: t.CDefine = 64 + +# NamedTypeNode 硬编码大小: Next(8) + Ty(8) = 16 字节 +NAMED_TYPE_NODE_SIZE: t.CDefine = 16 + +def new_global_variable(pool: memhub.MemBuddy | t.CPtr, + name: t.CChar | t.CPtr, ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr: + """创建一个全局变量""" + ptr: GlobalVariable | t.CPtr = pool.alloc(GV_SIZE) + if ptr is None: return None + string.memset(ptr, 0, GV_SIZE) + ptr.Name = name + ptr.Ty = ty + ptr.Initializer = None + ptr.IsConstant = 0 + ptr.Linkage = "external" + ptr.Section = None + ptr.UnnamedAddr = 0 + return ptr + + +# ============================================================ +# 链表操作(嵌入式 Head/Tail/Count,O(1) 追加) +# ============================================================ +def module_add_function(mod: LLVMModule | t.CPtr, func: Function | t.CPtr): + return mod.add_function(func) + + +def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr): + return mod.add_global(gv) + + +def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr): + return mod.set_target(triple) + + +def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr): + return mod.set_datalayout(layout) + + +# ============================================================ +# 命名结构体类型管理 +# ============================================================ + +# ============================================================ +# _is_opaque_struct - 检查类型是否是 opaque 结构体 +# +# opaque 结构体特征: Struct 类型,fcount == -1(哨兵标记,跨模块前向 +# 声明,仅名称无字段定义)。通过 Struct(pool, None, -1, name) 创建, +# IR 输出为 %"name" = type opaque。注意区分空结构体(fcount==0, +# fields==None,无字段类)——它是合法完整定义(= type {},可 alloca)。 +# 用于在 module_add_named_type 中区分 opaque 声明和完整定义, +# 确保 opaque 声明插入链表头部(在使用之前声明)。 +# +# Returns: 1=是 opaque / 0=否 +# ============================================================ +def _is_opaque_struct(ty: LLVMType | t.CPtr) -> int: + """检查类型是否是 opaque 结构体 + + opaque 是跨模块前向声明(仅名称无字段定义),由 + _scan_type_for_cross_module_refs 创建,fcount=-1 哨兵标记。 + 空结构体(fcount==0, fields==None,无字段类)是合法完整定义 + (LLVM {} 类型,可 alloca),必须与 opaque 区分——此前混淆导致 + 空类结构体被输出为 "= type opaque",alloca 报 Cannot allocate + unsized type。 + """ + if ty is None: + return 0 + match ty: + case LLVMType.Struct(fields, fcount, name): + # opaque: fcount == -1(哨兵) + if fcount < 0: + return 1 + return 0 + case _: + return 0 + + +def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr): + return mod.add_named_type(pool, ty) + + +# ============================================================ +# module_ensure_opaque_for_type - 为类型中的跨模块结构体引用添加 opaque 声明 +# +# 递归扫描 LLVMType 树,当遇到 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, +# 如果该名称未在模块中定义,则添加 opaque 声明(%"name" = type opaque)。 +# 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。 +# ============================================================ +def _is_type_defined_in_module(mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr) -> int: + return mod._is_type_defined_in_module(name) + + +def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr, + mod: LLVMModule | t.CPtr, + ty: LLVMType | t.CPtr, + depth: t.CInt = 0): + """递归扫描类型树,为跨模块结构体引用添加 opaque 声明""" + if ty is None or mod is None or pool is None: + return + # 深度守卫:自引用结构体(链表/树节点,如 Node{...; Ptr(Node) next}) + # 会无限递归栈溢出,与其他递归(TypePrint/DeepCopyType)一致设上限 + if depth >= 100: + return + match ty: + case LLVMType.Ptr(pointee): + if pointee is not None: + match pointee: + case LLVMType.Struct(sfields, sfcount, sname): + if sname is not None: + # 检查是否为跨模块引用(名称包含 '.') + if string.strchr(sname, 46) is not None: + # 检查是否已在模块中定义 + if _is_type_defined_in_module(mod, sname) == 0: + # 创建 opaque 类型并添加到模块 + # fcount=-1 哨兵标记 opaque(区别于空结构体 {}, + # 后者 fcount==0 是合法完整定义,可 alloca) + opaque_ty: LLVMType | t.CPtr = Struct(pool, None, -1, sname) + if opaque_ty is not None: + module_add_named_type(mod, pool, opaque_ty) + # 递归扫描结构体字段中的跨模块引用 + # 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用 + if sfields is not None: + fld: ParamNode | t.CPtr = sfields + while fld is not None: + if fld.Ty is not None: + _scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1) + fld = fld.Next + case _: + _scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1) + case LLVMType.Struct(sfields2, sfcount2, sname2): + # 顶层结构体(非指针):递归扫描字段 + if sfields2 is not None: + fld2: ParamNode | t.CPtr = sfields2 + while fld2 is not None: + if fld2.Ty is not None: + _scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1) + fld2 = fld2.Next + case LLVMType.Array(elem_ty, acount): + if elem_ty is not None: + _scan_type_for_cross_module_refs(pool, mod, elem_ty, depth + 1) + case _: + pass + + +def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr): + return mod.ensure_opaque_for_type(pool, ty) + + +# ============================================================ +# 全局变量属性设置 +# ============================================================ +def global_set_constant(gv: GlobalVariable | t.CPtr, is_const: t.CInt): + """设置全局变量是否为常量""" + if gv is None: return + gv.IsConstant = is_const + + +def global_set_linkage(gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr): + """设置链接类型 (private/internal/external/... )""" + if gv is None: return + gv.Linkage = linkage + + +def global_set_unnamed_addr(gv: GlobalVariable | t.CPtr, level: t.CInt): + """设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)""" + if gv is None: return + gv.UnnamedAddr = level + + +def global_set_section(gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr): + """设置段名""" + if gv is None: return + gv.Section = section + + +# ============================================================ +# 输出模式常量 +# ============================================================ +OUTPUT_FULL: t.CDefine = 0 # 完整 IR(stub + text) +OUTPUT_STUB: t.CDefine = 1 # 仅声明(header + 类型定义 + declare + external global) +OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值) + + +# ============================================================ +# LLVMModulePrint: 将模块序列化为 .ll 文本 +# +# mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码 +# ============================================================ +def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + mode: t.CInt): + return mod.PrintModule(buf, size, pool, mode) + + +# ============================================================ +# 全局变量打印 +# ============================================================ +def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT, + gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """打印单个全局变量: @ = [linkage] [unnamed_addr] [constant] """ + if gv is None: return + + _append_cstr(buf, size, "@") + if gv.Name is not None: + if _ll_name_needs_quote(gv.Name) != 0: + _append_cstr(buf, size, "\"") + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, "\"") + else: + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, " = ") + + # 链接类型(有初始值时不输出 external,因为 external + 初始值是非法 IR) + if gv.Linkage is not None: + if gv.Initializer is not None and string.strcmp(gv.Linkage, "external") == 0: + pass + else: + _append_cstr(buf, size, gv.Linkage) + _append_cstr(buf, size, " ") + + # unnamed_addr + if gv.UnnamedAddr == 1: + _append_cstr(buf, size, "unnamed_addr ") + elif gv.UnnamedAddr == 2: + _append_cstr(buf, size, "local_unnamed_addr ") + + # constant / global + if gv.IsConstant == 1: + _append_cstr(buf, size, "constant ") + else: + _append_cstr(buf, size, "global ") + + # 类型 + ty_buf: t.CChar | t.CPtr = pool.alloc(512) + if ty_buf is not None: + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, gv.Ty, pool) + _append_cstr(buf, size, ty_buf) + + # 初始化值 + if gv.Initializer is not None: + _append_cstr(buf, size, " ") + _append_cstr(buf, size, gv.Initializer) + + # 段名 + if gv.Section is not None: + _append_cstr(buf, size, ", section \"") + _append_cstr(buf, size, gv.Section) + _append_cstr(buf, size, "\"") + + +# ============================================================ +# _print_global_stub - 打印全局变量的声明形式(external global,无初值) +# ============================================================ +def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT, + gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """打印全局变量声明: @ = external global """ + if gv is None: return + + _append_cstr(buf, size, "@") + if gv.Name is not None: + if _ll_name_needs_quote(gv.Name) != 0: + _append_cstr(buf, size, "\"") + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, "\"") + else: + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, " = external global ") + + # 类型 + ty_buf: t.CChar | t.CPtr = pool.alloc(512) + if ty_buf is not None: + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, gv.Ty, pool) + _append_cstr(buf, size, ty_buf) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' \ No newline at end of file diff --git a/llvmlite/__types.vp b/llvmlite/__types.vp new file mode 100644 index 0000000..d3afb58 --- /dev/null +++ b/llvmlite/__types.vp @@ -0,0 +1,765 @@ +import t, c +from stdint import * +import viperlib +import string +import memhub +import stdio +import stdlib +from linkedlist import GSListNode + + +# ============================================================ +# ParamNode: 函数参数类型链表节点 +# 继承 GSListNode[ParamNode] 获取强类型 Next: ParamNode|CPtr +# Ty 用 t.CVoid | t.CPtr 前向引用,使用时转型为 (LLVMType | t.CPtr) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class ParamNode(GSListNode[ParamNode]): + Ty: t.CVoid | t.CPtr # LLVMType*(前向引用,使用时转型) + + +# ============================================================ +# LLVMType: LLVM IR 类型系统(t.REnum tagged union) +# +# 变体少、无通用字段、操作通过 match 分派 —— 契合 REnum 模型。 +# 布局: { i32 __tag, } +# ============================================================ +class LLVMType(t.REnum): + # 整数类型: i1/i8/i16/i32/i64 + class Int: + Bits: t.CInt + + # 指针类型: pointee* + class Ptr: + Pointee: LLVMType | t.CPtr + + # 函数类型: ret (params) + class Func: + Ret: LLVMType | t.CPtr + Params: ParamNode | t.CPtr + PCount: t.CInt + + # 数组类型: [N x elem_ty] + class Array: + ElemTy: LLVMType | t.CPtr + Count: t.CInt + + # 结构体类型: {ty1, ty2, ...} 或 %"name" = type {ty1, ty2, ...} + # Fields 复用 ParamNode 链表(ParamNode.Ty 即字段类型) + # Name 非 None 时为命名结构体,TypePrint 输出 %"name" 而非 {...} + class Struct: + Fields: ParamNode | t.CPtr + FCount: t.CInt + Name: t.CChar | t.CPtr + + # 浮点类型: half/float/double/fp128 + class Float: + Bits: t.CInt # 16=half, 32=float, 64=double, 128=fp128 + + # 无值类型 + class Void: + pass + + # 标签类型 + class Label: + pass + + # 元数据类型 + class Metadata: + pass + + +# ============================================================ +# 内部分配辅助 +# ============================================================ +def _new_type(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """从 mpool 分配一个零初始化的 LLVMType""" + ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if ptr: + string.memset(ptr, 0, LLVMType.__sizeof__()) + return ptr + + +# ============================================================ +# 类型工厂函数 +# ============================================================ +def Int1(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(1)) + return ptr + + +def Int8(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(8)) + return ptr + + +def Int16(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(16)) + return ptr + + +def Int32(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(32)) + return ptr + + +def Int64(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(64)) + return ptr + + +def Ptr(pool: memhub.MemBuddy | t.CPtr, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: + """创建指针类型 Ptr(pointee) + + LLVM IR 中 **不允许 void* 指针**("pointers to void are invalid"), + 因此: + - 若 pointee == None → 回退 Ptr(Int8) + - 若 pointee 是 LLVMType.Void → 回退 Ptr(Int8)(对应 C 的 void* 语法在 TPV 中写 Ptr(t.CVoid)) + 其他类型正常构造 Ptr(pointee)。 + """ + # ============== 前置校验: 拦截 Void / None pointee(void* 非法)============== + safe_pointee: LLVMType | t.CPtr = pointee + if safe_pointee is None: + safe_pointee = Int8(pool) + else: + match safe_pointee: + case LLVMType.Void(): + safe_pointee = Int8(pool) + case _: + pass + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Ptr(safe_pointee)) + return ptr + + +def Func(pool: memhub.MemBuddy | t.CPtr, ret: LLVMType | t.CPtr, + params: ParamNode | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Func(ret, params, count)) + return ptr + + +def Void(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Void()) + return ptr + + +def Array(pool: memhub.MemBuddy | t.CPtr, elem_ty: LLVMType | t.CPtr, + count: t.CInt) -> LLVMType | t.CPtr: + """创建数组类型 [count x elem_ty]""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Array(elem_ty, count)) + return ptr + + +def Struct(pool: memhub.MemBuddy | t.CPtr, fields: ParamNode | t.CPtr, + fcount: t.CInt, name: t.CChar | t.CPtr) -> LLVMType | t.CPtr: + """创建结构体类型 {ty1, ty2, ...} + + fields 为 ParamNode 链表头,fcount 为字段数量。 + name 非 None 时为命名结构体(如 "sha1.ClassName"),TypePrint 输出 %"name"。 + name 为 None 时为匿名结构体,TypePrint 输出 {ty1, ty2, ...}。 + """ + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Struct(fields, fcount, name)) + return ptr + + +def Half(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建半精度浮点类型 half (16-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(16)) + return ptr + + +def Float(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建单精度浮点类型 float (32-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(32)) + return ptr + + +def Double(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建双精度浮点类型 double (64-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(64)) + return ptr + + +def FP128(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建四精度浮点类型 fp128 (128-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(128)) + return ptr + + +def Label(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建标签类型 label""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Label()) + return ptr + + +# ============================================================ +# ParamNode 辅助 +# ============================================================ +# ParamNode 硬编码大小: Next(8) + Ty(8) = 16 字节 +PNODE_SIZE: t.CDefine = 16 + +def new_param_node(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr: + """创建一个参数节点,Ty 设为给定类型指针""" + ptr: ParamNode | t.CPtr = pool.alloc(PNODE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PNODE_SIZE) + ptr.Ty = ty + ptr.Next = None + return ptr + + +def param_list_append(head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr, + node: ParamNode | t.CPtr) -> ParamNode | t.CPtr: + """将 node 追加到参数链表尾部,返回 head 和更新后的 tail""" + if node is None: return head + node.Next = None + if head is None: + return node + if tail is not None: + tail.Next = node + return node + + +# ============================================================ +# ParamNode 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 ParamNode 的 stub 类型, +# 导致 TransPyC 静默跳过字段访问。这些访问器在拥有完整类型定义的 +# 本模块内执行,能正确访问所有字段。 +# ============================================================ +def paramnode_get_ty(node: ParamNode | t.CPtr) -> LLVMType | t.CPtr: + """获取参数节点的类型""" + if node is None: + return None + return (LLVMType | t.CPtr)(node.Ty) + + +def paramnode_get_next(node: ParamNode | t.CPtr) -> ParamNode | t.CPtr: + """获取链表下一个参数节点""" + if node is None: + return None + return node.Next + + +def paramnode_set_ty(node: ParamNode | t.CPtr, ty: LLVMType | t.CPtr): + """设置参数节点的类型""" + if node is None: + return + node.Ty = ty + + +def paramnode_set_next(node: ParamNode | t.CPtr, nxt: ParamNode | t.CPtr): + """设置链表下一个参数节点""" + if node is None: + return + node.Next = nxt + + +# ============================================================ +# LLVMTypeCore: 类型创建核心,封装 pool 避免重复传参 +# +# 用法: +# core: LLVMTypeCore | t.CPtr = LLVMTypeCore(pool) +# ty_i32: LLVMType | t.CPtr = core.Int32() +# ty_ptr: LLVMType | t.CPtr = core.Ptr(ty_i32) +# ty_void: LLVMType | t.CPtr = core.Void() +# ============================================================ +@t.NoVTable +class LLVMTypeCore: + """类型创建核心,封装 pool 避免每次创建类型都传 pool""" + Pool: memhub.MemBuddy | t.CPtr + + def __init__(self, pool: memhub.MemBuddy | t.CPtr): + self.Pool = pool + + def Int1(self) -> LLVMType | t.CPtr: + return Int1(self.Pool) + + def Int8(self) -> LLVMType | t.CPtr: + return Int8(self.Pool) + + def Int16(self) -> LLVMType | t.CPtr: + return Int16(self.Pool) + + def Int32(self) -> LLVMType | t.CPtr: + return Int32(self.Pool) + + def Int64(self) -> LLVMType | t.CPtr: + return Int64(self.Pool) + + def Ptr(self, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: + return Ptr(self.Pool, pointee) + + def Func(self, ret: LLVMType | t.CPtr, params: ParamNode | t.CPtr, + count: t.CInt) -> LLVMType | t.CPtr: + return Func(self.Pool, ret, params, count) + + def Array(self, elem_ty: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: + return Array(self.Pool, elem_ty, count) + + def Struct(self, fields: ParamNode | t.CPtr, fcount: t.CInt, + name: t.CChar | t.CPtr = None) -> LLVMType | t.CPtr: + return Struct(self.Pool, fields, fcount, name) + + def Void(self) -> LLVMType | t.CPtr: + return Void(self.Pool) + + def Half(self) -> LLVMType | t.CPtr: + return Half(self.Pool) + + def Float(self) -> LLVMType | t.CPtr: + return Float(self.Pool) + + def Double(self) -> LLVMType | t.CPtr: + return Double(self.Pool) + + def FP128(self) -> LLVMType | t.CPtr: + return FP128(self.Pool) + + def Label(self) -> LLVMType | t.CPtr: + return Label(self.Pool) + + def NewParamNode(self, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr: + return new_param_node(self.Pool, ty) + + # ---- 链表辅助 ---- + def ParamListAppend(self, head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr, + node: ParamNode | t.CPtr) -> ParamNode | t.CPtr: + """将 node 追加到参数/字段链表,返回新的 tail""" + return param_list_append(head, tail, node) + + # ---- 打印 ---- + def PrintType(self, buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr): + TypePrint(buf, size, ty, self.Pool) + + +# ============================================================ +# TypePrint: 将 LLVMType 序列化为 IR 文本 +# +# 示例: +# Int(32) -> "i32" +# Int(8) -> "i8" +# Ptr(Int(32)) -> "i32*" +# Void -> "void" +# Array(Int(32),4) -> "[4 x i32]" +# Struct(...) -> "{i32, i8*}" +# Func(...) -> "i32 (i32, i8*)" +# +# pool 用于复杂类型(Array/Struct/Func)递归打印子类型时分配临时缓冲区。 +# ============================================================ +def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """将类型 ty 序列化为 IR 文本写入 buf(容量 size) + + pool 用于递归打印子类型时分配临时缓冲区。 + """ + _TypePrintDepth(buf, size, ty, pool, 0) + + +# 递归深度上限:悬空/自引用的 LLVMType 树(1b reset 后内存被复用)会导致 +# Ptr(pointee)/Struct(fields)/Func(params) 无限递归,每次递归分配临时缓冲 +# 造成 OOM(单文件暴涨 900MB 根因)。超过 100 层即停止打印。 +TYPEPRINT_MAX_DEPTH: t.CDefine = 100 + +def _TypePrintDepth(buf: t.CChar | t.CPtr, size: t.CSizeT, + ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + depth: t.CInt): + """带递归深度上限的 TypePrint 内部实现""" + if ty is None or buf is None or size == 0: + return + if depth >= TYPEPRINT_MAX_DEPTH: + viperlib.snprintf(buf, size, "...") + return + buf[0] = '\0' + match ty: + case LLVMType.Int(bits): + viperlib.snprintf(buf, size, "i%d", bits) + case LLVMType.Ptr(pointee): + # ================================================================ + # LLVM IR 不允许 "void*",必须是 "i8*"。 + # 兜底处理: + # pointee == None / Void() / Label() / Metadata() → 统一打印 i8* + # ================================================================ + # 先判断是否 Struct(name) 的快速路径(需先判断 pointee 非None) + if pointee is not None: + match pointee: + case LLVMType.Struct(sfields, sfcount, sname): + if sname is not None: + # 悬空防护:sname 可能指向被 reset 回收/部分复用的 pool 内存。 + # viperlib 的 %s 未实现 precision(%.40s 会全量读 sname), + # 手动 strncpy 限长拷贝后再打印,读侧限制在缓冲内。 + # 类型名含 sha1 前缀可超 40 字符(如 + # "bbdf3bbd4c3bc28c.CONSOLE_SCREEN_BUFFER_INFO"=42), + # 原 40 字节截断会产生未定义类型引用(llc: undefined type)。 + sn_cp: t.CChar | t.CPtr = pool.alloc(256) + if sn_cp is not None: + string.strncpy(sn_cp, sname, 255) + sn_cp[255] = '\0' + viperlib.snprintf(buf, size, "%%\"%s\"*", sn_cp) + return + case LLVMType.Void(): + # Ptr(Void) → i8*(LLVM IR void* 非法) + viperlib.snprintf(buf, size, "%s", "i8*") + return + case LLVMType.Label(): + viperlib.snprintf(buf, size, "%s", "i8*") + return + case LLVMType.Metadata(): + viperlib.snprintf(buf, size, "%s", "i8*") + return + case _: + pass + # pointee == None 时也兜底 Ptr(Int8) 打印 i8* + if pointee is None: + viperlib.snprintf(buf, size, "%s", "i8*") + return + # 通用路径: 递归打印 pointee 后追加 '*' + _TypePrintDepth(buf, size, pointee, pool, depth + 1) + pos: t.CSizeT = string.strlen(buf) + if pos + 1 < size: + buf[pos] = '*' + buf[pos + 1] = '\0' + case LLVMType.Array(elem_ty, count): + # [N x elem_ty] + viperlib.snprintf(buf, size, "[%d x ", count) + # SHA1 限定类型名(如 %"21a7fcfc665f75ef.NamedTypeNode")可达 ~50 字节, + # 嵌套指针/数组更易超过 128,使用 512 字节避免截断 + tmp: t.CChar | t.CPtr = pool.alloc(512) + if tmp is not None: + _TypePrintDepth(tmp, 512, elem_ty, pool, depth + 1) + _strappend(buf, size, tmp) + _strappend(buf, size, "]") + case LLVMType.Struct(fields, fcount, name): + if name is not None: + # 命名结构体: %"name" + viperlib.snprintf(buf, size, "%%\"%s\"", name) + else: + # 匿名结构体: {ty1, ty2, ...} + _print_struct_body(buf, size, fields, pool, depth) + case LLVMType.Func(ret, params, count): + # ret (ty1, ty2, ...) + _TypePrintDepth(buf, size, ret, pool, depth + 1) + _strappend(buf, size, " (") + cur2: ParamNode | t.CPtr = params + first2: t.CInt = 1 + _pc2: t.CInt = 0 + # 函数参数类型可能为 SHA1 限定命名结构体指针,512 字节避免截断 + tmp3: t.CChar | t.CPtr = pool.alloc(512) + while cur2 is not None: + # 悬空保护:参数链若被 reset 回收后内容复用,可能成环无限循环 + _pc2 += 1 + if _pc2 > 200: + _strappend(buf, size, "...)") + break + if first2 == 0: + _strappend(buf, size, ", ") + if tmp3 is not None: + _TypePrintDepth(tmp3, 512, cur2.Ty, pool, depth + 1) + _strappend(buf, size, tmp3) + cur2 = cur2.Next + first2 = 0 + _strappend(buf, size, ")") + case LLVMType.Void(): + viperlib.snprintf(buf, size, "%s", "void") + case LLVMType.Label(): + viperlib.snprintf(buf, size, "%s", "label") + case LLVMType.Metadata(): + viperlib.snprintf(buf, size, "%s", "metadata") + case LLVMType.Float(bits): + if bits == 16: + viperlib.snprintf(buf, size, "%s", "half") + elif bits == 32: + viperlib.snprintf(buf, size, "%s", "float") + elif bits == 64: + viperlib.snprintf(buf, size, "%s", "double") + elif bits == 128: + viperlib.snprintf(buf, size, "%s", "fp128") + else: + viperlib.snprintf(buf, size, "float%x", bits) + case _: + viperlib.snprintf(buf, size, "%s", "void") + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾(不超过 dst_size)""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到 GB 外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# _print_struct_body - 打印结构体字段部分 {ty1, ty2, ...} +# +# 供 TypePrint(匿名结构体)和 PrintStructDefinition(命名结构体定义行)复用 +# ============================================================ +def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT, + fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + depth: t.CInt = 0): + """打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容) + + 直接在 buf 当前末尾写入字段类型,避免 pool.alloc 返回与 buf 重叠的内存 + 导致 TypePrint 写入 tmp 时覆盖 buf 已有内容。 + """ + if buf is None or size == 0: + return + _strappend(buf, size, "{") + cur: ParamNode | t.CPtr = fields + first: t.CInt = 1 + fidx: t.CInt = 0 + while cur is not None: + # 悬空保护:ParamNode 链若被 reset 回收后内容复用,Next 指针可能成环或 + # 指向垃圾,无限循环。最多打印 200 个字段即停止,防止 OOM。 + if fidx >= 200: + _strappend(buf, size, "...}") + return + if first == 0: + _strappend(buf, size, ", ") + # 直接在 buf 当前末尾位置写入字段类型 + # TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0') + pos: t.CSizeT = string.strlen(buf) + if pos + 2 < size: + _TypePrintDepth(buf + pos, size - pos, cur.Ty, pool, depth + 1) + cur = cur.Next + first = 0 + fidx += 1 + _strappend(buf, size, "}") + + +# ============================================================ +# PrintStructDefinition - 打印命名结构体类型定义行 +# +# 输出格式: %"name" = type { ty1, ty2, ... } +# 供 LLVMModulePrint 在全局变量/函数之前输出类型定义 +# ============================================================ +def PrintStructDefinition(buf: t.CChar | t.CPtr, size: t.CSizeT, + ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """打印命名结构体类型定义行 %"name" = type { ty1, ty2, ... } + + 当 fcount == -1(哨兵)时输出 opaque 声明: %"name" = type opaque。 + 空结构体(fcount==0, fields==None,无字段类)是完整定义,输出 "= type {}"。 + """ + if ty is None or buf is None or size == 0: + return + match ty: + case LLVMType.Struct(fields, fcount, name): + if name is None: + return + # 使用 snprintf 构建 "%%"name" = type" 前缀,避免 _strappend 截断 + # opaque 类型: fcount == -1(哨兵,跨模块前向声明) + if fcount < 0: + viperlib.snprintf(buf, size, "%%\"%s\" = type opaque", name) + else: + viperlib.snprintf(buf, size, "%%\"%s\" = type ", name) + _print_struct_body(buf, size, fields, pool) + case _: + return + + +# ============================================================ +# get_struct_name - 获取命名结构体的名称 +# +# 返回 Name 字段(如 "sha1.ClassName"),非 Struct 类型或匿名 Struct 返回 None +# 供 module_add_named_type 检查是否为命名结构体及去重 +# ============================================================ +def get_struct_name(ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr: + """获取命名结构体的名称,非命名结构体返回 None""" + if ty is None: + return None + match ty: + case LLVMType.Struct(fields, fcount, name): + return name + case _: + return None + + +def get_struct_fields(ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr: + """获取结构体的字段链表(供跨模块重建 Struct 类型用)""" + if ty is None: + return None + match ty: + case LLVMType.Struct(fields, fcount, name): + return fields + case _: + return None + + +def get_struct_fcount(ty: LLVMType | t.CPtr) -> t.CInt: + """获取结构体的字段数量(供跨模块重建 Struct 类型用)""" + if ty is None: + return 0 + match ty: + case LLVMType.Struct(fields, fcount, name): + return fcount + case _: + return 0 + + +# ============================================================ +# DeepCopyType - 深拷贝 LLVMType 到 stdlib 区(跨文件 reset 存活) +# +# 背景: 1b 阶段(mark1 之后)新注册的结构体(泛型特化类等),其 +# struct_ty 是 pool 分配的 LLVMType,所在文件翻译完 reset_to(mark1) +# 后指针悬空。_struct_table 中的 entry.Ty 指向它,后续文件遍历 +# _struct_table(find_struct_by_type/lookup_field 等)时解引用悬空 +# 指针导致崩溃(0xC0000005)。 +# +# 本函数递归拷贝整棵 LLVMType 树到 stdlib(含 ParamNode 字段链和 +# 字符串名),保证 entry.Ty 跨文件永久存活。 +# +# 注意: 自引用类型(如 Value 含 Ptr(Value) 字段)会导致无限递归, +# 用深度上限防护(超过即返回浅拷贝副本,后续不再递归)。 +# ============================================================ +DEEPCOPY_MAX_DEPTH: t.CDefine = 64 + +def DeepCopyType(pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr) -> LLVMType | t.CPtr: + """深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None""" + return _DeepCopyDepth(pool, ty, 0) + + +def _DeepCopyDepth(pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr, depth: t.CInt) -> LLVMType | t.CPtr: + """带深度上限的深拷贝实现 + + 分配源用传入的 pool 参数(调用方决定):传主 pool 为瞬时拷贝 + (随 mark/reset 回收),传永久 pool(CompilerFactory.get_perm_pool()) + 为跨 mark 持久拷贝(代替 stdlib.malloc,buddy 分配更快)。 + """ + if ty is None: + return None + new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(pool.alloc(LLVMType.__sizeof__())) + if new_ty is None: + return None + string.memset(new_ty, 0, LLVMType.__sizeof__()) + if depth >= DEEPCOPY_MAX_DEPTH: + # 深度超限:浅拷贝 tag 后停止递归(复制当前变体但不深拷子类型) + match ty: + case LLVMType.Int(bits): + c.DerefAs(new_ty, LLVMType.Int(bits)) + case LLVMType.Float(bits): + c.DerefAs(new_ty, LLVMType.Float(bits)) + case LLVMType.Void(): + c.DerefAs(new_ty, LLVMType.Void()) + case LLVMType.Label(): + c.DerefAs(new_ty, LLVMType.Label()) + case LLVMType.Metadata(): + c.DerefAs(new_ty, LLVMType.Metadata()) + case _: + c.DerefAs(new_ty, LLVMType.Void()) + return new_ty + match ty: + case LLVMType.Int(bits): + c.DerefAs(new_ty, LLVMType.Int(bits)) + case LLVMType.Float(bits): + c.DerefAs(new_ty, LLVMType.Float(bits)) + case LLVMType.Void(): + c.DerefAs(new_ty, LLVMType.Void()) + case LLVMType.Label(): + c.DerefAs(new_ty, LLVMType.Label()) + case LLVMType.Metadata(): + c.DerefAs(new_ty, LLVMType.Metadata()) + case LLVMType.Ptr(pointee): + c.DerefAs(new_ty, LLVMType.Ptr(_DeepCopyDepth(pool, pointee, depth + 1))) + case LLVMType.Array(elem_ty, count): + c.DerefAs(new_ty, LLVMType.Array(_DeepCopyDepth(pool, elem_ty, depth + 1), count)) + case LLVMType.Func(ret, params, pcount): + c.DerefAs(new_ty, LLVMType.Func( + _DeepCopyDepth(pool, ret, depth + 1), + _DeepCopyParamChain(pool, params, depth + 1), pcount)) + case LLVMType.Struct(fields, fcount, name): + c.DerefAs(new_ty, LLVMType.Struct( + _DeepCopyParamChain(pool, fields, depth + 1), + fcount, _DeepCopyStr(pool, name))) + case _: + stdlib.free(new_ty) + return None + return new_ty + + +def _DeepCopyParamChain(pool: memhub.MemBuddy | t.CPtr, + head: ParamNode | t.CPtr, depth: t.CInt) -> ParamNode | t.CPtr: + """深拷贝 ParamNode 链表到 stdlib""" + if head is None: + return None + first: ParamNode | t.CPtr = None + prev: ParamNode | t.CPtr = None + cur: ParamNode | t.CPtr = head + guard: t.CInt = 0 + while cur is not None: + guard += 1 + if guard > 512: + break + node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(pool.alloc(PNODE_SIZE)) + if node is None: + break + string.memset(node, 0, PNODE_SIZE) + node.Ty = _DeepCopyDepth(pool, paramnode_get_ty(cur), depth + 1) + node.Next = None + if first is None: + first = node + if prev is not None: + prev.Next = node + prev = node + cur = paramnode_get_next(cur) + return first + + +def _DeepCopyStr(pool: memhub.MemBuddy | t.CPtr, s: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """深拷贝字符串到 stdlib""" + if s is None: + return None + slen: t.CSizeT = string.strlen(s) + copy: t.CChar | t.CPtr = pool.alloc(slen + 1) + if copy is None: + return None + string.strcpy(copy, s) + return copy + + + + diff --git a/llvmlite/__values.vp b/llvmlite/__values.vp new file mode 100644 index 0000000..af44781 --- /dev/null +++ b/llvmlite/__values.vp @@ -0,0 +1,234 @@ +import t, c +from stdint import * +import string +import viperlib +import stdio +import memhub +from linkedlist import GSListNode +from .__types import LLVMType, TypePrint + + +# ============================================================ +# Value: SSA 值表示 +# +# 表示一个 LLVM IR 值:SSA 临时值(%0/%result)或常量字面量(42/0)。 +# 每个值有类型指针、名字、是否常量标志。 +# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr(值池链表) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class Value(GSListNode[Value]): + Ty: LLVMType | t.CPtr # 值的类型 + Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本("42"/"1.5e+00") + IsConst: t.CInt # 1=常量字面量, 0=SSA 临时值 + IntVal: t.CInt64T # 整数常量值(当 IsConst=1 时使用) + FloatVal: t.CDouble # 浮点常量值(当 IsConst=1 且 Ty 为 Float 时使用) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# Value 硬编码大小: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 字节 +VALUE_SIZE: t.CDefine = 48 + +def new_value(pool: memhub.MemBuddy | t.CPtr) -> Value | t.CPtr: + """从 mpool 分配一个零初始化的 Value""" + ptr: Value | t.CPtr = pool.alloc(VALUE_SIZE) + if ptr: + string.memset(ptr, 0, VALUE_SIZE) + return ptr + + +def ConstInt(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + val: t.CInt64T, name: t.CChar | t.CPtr) -> Value | t.CPtr: + """创建整数常量值 + + 参数: + ty: 整数类型(Int1/Int8/Int32/Int64) + val: 整数值 + name: 常量文本(如 "42"),由调用方提供 + """ + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 1 + v.IntVal = val + return v + + +def ConstNull(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Value | t.CPtr: + """创建 null 指针常量""" + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 1 + v.IntVal = 0 + return v + + +def ConstZero(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """创建 zeroinitializer 常量(零初始化聚合类型:结构体/数组)""" + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = "zeroinitializer" + v.IsConst = 1 + v.IntVal = 0 + return v + + +def ConstFloat(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + val: t.CDouble) -> Value | t.CPtr: + """创建浮点常量值 + + 参数: + ty: 浮点类型(Half/Float/Double/FP128) + val: 浮点数值 + 名字自动格式化为 LLVM IR 科学计数法文本(如 "1.500000e+00")。 + """ + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.IsConst = 1 + v.FloatVal = val + v.IntVal = 0 + # 格式化名字: LLVM IR 浮点常量文本用十六进制位模式(0x%016llx / 0x%08x) + # 原因: %.17e 科学计数法文本经 llc 解析对部分值产生 ±1 ulp 误差 + # (如 "1.10000000000000000e+01" 解析为 11.000000000000002 而非 11.0, + # 导致 add_scalar[0]==11 等浮点常量比较失败)。位模式无精度损失。 + # 原 %e 默认 6 位小数还会截断精度(3.1415926535897931 -> 3.141593e+00)。 + # 用 CRT stdio.snprintf: viperlib 自实现 %g 有小数位反转 bug。 + f_bits: t.CInt = 64 + match ty: + case llvmlite.LLVMType.Float(ftb): + f_bits = ftb + fv_bits: t.CUInt64T = 0 + c.Load(c.Addr(fv_bits), c.Addr(val)) + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is not None: + if f_bits == 32: + stdio.snprintf(name_buf, 32, "0x%08x", t.CUInt32T(fv_bits)) + else: + stdio.snprintf(name_buf, 32, "0x%016llx", fv_bits) + v.Name = name_buf + return v + + +def SSAValue(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Value | t.CPtr: + """创建 SSA 临时值 + + 参数: + ty: 值类型 + name: SSA 名(如 "%0"/"%result"),由调用方提供 + """ + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 0 + v.IntVal = 0 + return v + + +# ============================================================ +# ValuePrint: 将值序列化为 IR 文本 +# +# 示例: +# ConstInt(i32, 42, "42") -> "i32 42" +# SSAValue(i32, "%0") -> "i32 %0" +# ============================================================ +def ValuePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + val: Value | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """将值 val 序列化为 IR 文本写入 buf + + 格式: + pool 用于复杂类型(Array/Struct/Func)递归打印时分配临时缓冲区。 + """ + if val is None or buf is None or size == 0: + return + # 先写类型 + TypePrint(buf, size, val.Ty, pool) + # 追加空格 + pos: t.CSizeT = string.strlen(buf) + if pos + 1 < size: + buf[pos] = ' ' + buf[pos + 1] = '\0' + # 追加名字 + if val.Name is not None: + pos = string.strlen(buf) + _append_str(buf, size, val.Name) + + +# ============================================================ +# Value 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 Value 的 stub 类型(字段不足或偏移错误), +# 导致 TransPyC 静默跳过字段访问(不生成 GEP,不报错)。 +# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问所有字段。 +# ============================================================ +def value_get_ty(val: Value | t.CPtr) -> LLVMType | t.CPtr: + """获取值的类型""" + if val is None: + return None + return val.Ty + + +def value_get_next(val: Value | t.CPtr) -> Value | t.CPtr: + """获取链表下一个值""" + if val is None: + return None + return val.Next + + +def value_set_ty(val: Value | t.CPtr, ty: LLVMType | t.CPtr): + """设置值的类型""" + if val is None: + return + val.Ty = ty + + +def value_set_next(val: Value | t.CPtr, nxt: Value | t.CPtr): + """设置链表下一个值""" + if val is None: + return + val.Next = nxt + + +def value_set_name(val: Value | t.CPtr, name: t.CChar | t.CPtr): + """设置值的名字""" + if val is None: + return + val.Name = name + + +def value_set_isconst(val: Value | t.CPtr, is_const: t.CInt): + """设置是否为常量""" + if val is None: + return + val.IsConst = is_const + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_str(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' diff --git a/llvmlite/__verify.vp b/llvmlite/__verify.vp new file mode 100644 index 0000000..1c21e86 --- /dev/null +++ b/llvmlite/__verify.vp @@ -0,0 +1,403 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +from linkedlist import GSListNode, GSList +from .__function import Function, BasicBlock, Line, Param +from .__module import LLVMModule + + +# ============================================================ +# SSA 验证器 +# +# 检查项: +# 1. 块终止: 每个基本块必须以终止指令结尾 (ret/br/switch/unreachable) +# 2. SSA 唯一性: 每个 %name 只能被定义一次 +# 3. 未定义引用: 所有 %name 使用必须有对应定义 +# 4. Phi 位置: phi 指令只能出现在块首(非 phi 指令之前) +# ============================================================ + +# 错误码 +VERIFY_OK: t.CDefine = 0 +VERIFY_ERR_NO_TERMINATOR: t.CDefine = 1 +VERIFY_ERR_DUPLICATE_DEF: t.CDefine = 2 +VERIFY_ERR_UNDEFINED_USE: t.CDefine = 3 +VERIFY_ERR_PHI_NOT_FIRST: t.CDefine = 4 + + +# ============================================================ +# NameEntry: 已定义 SSA 名条目(链表节点) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class NameEntry(GSListNode[NameEntry]): + Name: t.CChar | t.CPtr # SSA 名(如 "%0"/"%result") + + +# ============================================================ +# VerifyResult: 验证结果 +# ============================================================ +class VerifyResult: + ErrorCount: t.CInt # 错误总数 + WarningCount: t.CInt # 警告总数 + ErrorCode: t.CInt # 第一个错误码 + ErrorBuf: t.CChar | t.CPtr # 错误消息缓冲区 + ErrorBufSize: t.CSizeT # 缓冲区大小 + + +# ============================================================ +# 辅助函数 +# ============================================================ +def _new_verify_result(pool: memhub.MemBuddy | t.CPtr, + buf_size: t.CSizeT) -> VerifyResult | t.CPtr: + """创建验证结果对象""" + ptr: VerifyResult | t.CPtr = pool.alloc(VerifyResult.__sizeof__()) + if ptr is None: return None + string.memset(ptr, 0, VerifyResult.__sizeof__()) + ptr.ErrorCount = 0 + ptr.WarningCount = 0 + ptr.ErrorCode = VERIFY_OK + buf: t.CChar | t.CPtr = pool.alloc(buf_size) + if buf is not None: + buf[0] = '\0' + ptr.ErrorBuf = buf + ptr.ErrorBufSize = buf_size + return ptr + + +def _report_error(result: VerifyResult | t.CPtr, code: t.CInt, msg: t.CChar | t.CPtr): + """记录一个错误""" + if result is None: return + result.ErrorCount += 1 + if result.ErrorCode == VERIFY_OK: + result.ErrorCode = code + if result.ErrorBuf is not None and msg is not None: + _append_cstr(result.ErrorBuf, result.ErrorBufSize, msg) + _append_cstr(result.ErrorBuf, result.ErrorBufSize, "\n") + + +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# SSA 名表操作 +# ============================================================ +def _new_name_table(pool: memhub.MemBuddy | t.CPtr) -> GSList[NameEntry] | t.CPtr: + """创建空名表""" + gsl: GSList[NameEntry] | t.CPtr = pool.alloc(24) # GSList: Head+Tail+Count + if gsl is None: return None + string.memset(gsl, 0, 24) + return gsl + + +# NameEntry 硬编码大小: Next(8) + Name(8) = 16 字节 +NENTRY_SIZE: t.CDefine = 16 + +def _name_table_add(table: GSList[NameEntry] | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + name: t.CChar | t.CPtr) -> t.CInt: + """添加名到表。返回 1=重复, 0=成功添加""" + if table is None or name is None: return 0 + # 检查重复 + cur: NameEntry | t.CPtr = table.Head + while cur is not None: + if string.strcmp(cur.Name, name) == 0: + return 1 + cur = cur.Next + # 添加新条目 + entry: NameEntry | t.CPtr = pool.alloc(NENTRY_SIZE) + if entry is None: return 0 + string.memset(entry, 0, NENTRY_SIZE) + entry.Name = name + table.append(entry) + return 0 + + +def _name_table_contains(table: GSList[NameEntry] | t.CPtr, + name: t.CChar | t.CPtr) -> t.CInt: + """检查名是否在表中。返回 1=存在, 0=不存在""" + if table is None or name is None: return 0 + cur: NameEntry | t.CPtr = table.Head + while cur is not None: + if string.strcmp(cur.Name, name) == 0: + return 1 + cur = cur.Next + return 0 + + +# ============================================================ +# 文本分析辅助 +# ============================================================ +def _is_char_name(ch: t.CChar) -> t.CInt: + """判断字符是否为 SSA 名字符 [a-zA-Z0-9._]""" + if ch >= 'a' and ch <= 'z': return 1 + if ch >= 'A' and ch <= 'Z': return 1 + if ch >= '0' and ch <= '9': return 1 + if ch == '.' or ch == '_': return 1 + return 0 + + +def _extract_def_name(pool: memhub.MemBuddy | t.CPtr, + text: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """从定义行提取被定义的 SSA 名。 + + 定义行格式: "% = " + 返回分配的 NUL 结尾名串(如 "%0"),或 None 若非定义行。 + """ + if text is None: return None + if text[0] != '%': return None + # 扫描 " = " 模式 + i: t.CInt = 1 + while text[i] != '\0': + if text[i] == ' ' and text[i + 1] == '=' and text[i + 2] == ' ': + # 找到 " = " 在位置 i + name_len: t.CInt = i + name: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if name is None: return None + j: t.CInt = 0 + while j < name_len: + name[j] = text[j] + j += 1 + name[name_len] = '\0' + return name + i += 1 + return None + + +def _is_terminator(text: t.CChar | t.CPtr) -> t.CInt: + """判断文本是否为终止指令""" + if text is None: return 0 + if string.strncmp(text, "ret", 3) == 0: return 1 + if string.strncmp(text, "br ", 3) == 0: return 1 + if string.strncmp(text, "switch ", 7) == 0: return 1 + if string.strncmp(text, "unreachable", 11) == 0: return 1 + if string.strncmp(text, "indirectbr ", 11) == 0: return 1 + if string.strncmp(text, "resume ", 7) == 0: return 1 + return 0 + + +def _is_phi(text: t.CChar | t.CPtr) -> t.CInt: + """判断文本是否为 phi 指令""" + if text is None: return 0 + if string.strstr(text, " = phi ") is not None: return 1 + return 0 + + +def _check_uses_in_line(table: GSList[NameEntry] | t.CPtr, + text: t.CChar | t.CPtr, + def_name: t.CChar | t.CPtr) -> t.CInt: + """检查行中所有 SSA 名使用是否已定义。 + + 跳过 def_name(定义位置的名字)。 + 返回未定义使用数量。 + """ + if text is None: return 0 + i: t.CInt = 0 + undef_count: t.CInt = 0 + while text[i] != '\0': + if text[i] == '%': + # 提取名 + name_start: t.CInt = i + i += 1 + while text[i] != '\0' and _is_char_name(text[i]) == 1: + i += 1 + name_len: t.CInt = i - name_start + if name_len > 1: + # 构建临时名串进行比较 + # 由于无法在栈上分配,用 strstr 进行简化检查 + # 这里采用逐字符比较方式 + if _name_matches_at(text, name_start, name_len, table) == 0: + # 检查是否是 def_name(定义本身的位置) + if def_name is not None: + if _str_matches_at(text, name_start, name_len, def_name) == 0: + undef_count += 1 + else: + undef_count += 1 + else: + i += 1 + return undef_count + + +def _name_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt, + table: GSList[NameEntry] | t.CPtr) -> t.CInt: + """检查 text[start:start+length] 是否匹配名表中的某个条目。 + 返回 1=匹配, 0=不匹配 + """ + if table is None: return 0 + cur: NameEntry | t.CPtr = table.Head + while cur is not None: + if cur.Name is not None: + if _str_matches_at(text, start, length, cur.Name) == 1: + return 1 + cur = cur.Next + return 0 + + +def _str_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt, + target: t.CChar | t.CPtr) -> t.CInt: + """检查 text[start:start+length] 是否等于 target 字符串。 + 返回 1=匹配, 0=不匹配 + """ + if text is None or target is None: return 0 + # 检查 target 长度 + target_len: t.CInt = string.strlen(target) + if target_len != length: return 0 + i: t.CInt = 0 + while i < length: + if text[start + i] != target[i]: return 0 + i += 1 + return 1 + + +# ============================================================ +# 主验证函数 +# ============================================================ +def verify_function(pool: memhub.MemBuddy | t.CPtr, + func: Function | t.CPtr, + result: VerifyResult | t.CPtr) -> t.CInt: + """验证函数的 SSA 正确性。 + + 参数: + pool: 内存池 + func: 要验证的函数 + result: 验证结果(调用前需用 _new_verify_result 创建) + + 返回: 错误数量(0 = 验证通过) + """ + if func is None or result is None: return 1 + + # 创建名表 + name_table: GSList[NameEntry] | t.CPtr = _new_name_table(pool) + if name_table is None: return 1 + + # 1. 将函数参数加入名表(参数是已定义的) + param: Param | t.CPtr = None + if func.Params is not None: + param = func.Params.Head + while param is not None: + if param.Name is not None: + _name_table_add(name_table, pool, param.Name) + param = param.Next + + # 1b. 将基本块名加入名表(块标签如 %then 是 br/phi 的合法引用目标) + blk_iter: BasicBlock | t.CPtr = None + if func.Blocks is not None: + blk_iter = func.Blocks.Head + while blk_iter is not None: + if blk_iter.Name is not None: + blk_name_len: t.CSizeT = string.strlen(blk_iter.Name) + blk_ref: t.CChar | t.CPtr = pool.alloc(blk_name_len + 2) + if blk_ref is not None: + # 构造 "%" 字符串 + blk_ref[0] = '%' + k: t.CSizeT = 0 + while k < blk_name_len: + blk_ref[k + 1] = blk_iter.Name[k] + k += 1 + blk_ref[blk_name_len + 1] = '\0' + _name_table_add(name_table, pool, blk_ref) + blk_iter = blk_iter.Next + + # 2. 遍历所有块 + blk: BasicBlock | t.CPtr = None + if func.Blocks is not None: + blk = func.Blocks.Head + while blk is not None: + # 检查终止指令 + if blk.IsTerminated == 0: + # 进一步检查最后一行是否为终止指令 + has_term: t.CInt = 0 + line_check: Line | t.CPtr = None + if blk.Lines is not None: + line_check = blk.Lines.Head + while line_check is not None: + if line_check.Buf is not None: + if _is_terminator(line_check.Buf) == 1: + has_term = 1 + line_check = line_check.Next + if has_term == 0: + blk_name: t.CChar | t.CPtr = "" + if blk.Name is not None: + blk_name = blk.Name + err_buf: t.CChar | t.CPtr = pool.alloc(128) + if err_buf is not None: + viperlib.snprintf(err_buf, 128, "ERROR: block '%s' missing terminator", blk_name) + _report_error(result, VERIFY_ERR_NO_TERMINATOR, err_buf) + + # 遍历块内指令行 + seen_non_phi: t.CInt = 0 + line: Line | t.CPtr = None + if blk.Lines is not None: + line = blk.Lines.Head + while line is not None: + if line.Buf is not None: + text: t.CChar | t.CPtr = line.Buf + + # 检查 phi 位置 + if _is_phi(text) == 1: + if seen_non_phi == 1: + phi_err: t.CChar | t.CPtr = pool.alloc(128) + if phi_err is not None: + viperlib.snprintf(phi_err, 128, "ERROR: phi not at block start") + _report_error(result, VERIFY_ERR_PHI_NOT_FIRST, phi_err) + else: + # 非空行且非 phi 标记为已见非 phi + if string.strlen(text) > 0: + seen_non_phi = 1 + + # 提取定义名 + def_name: t.CChar | t.CPtr = _extract_def_name(pool, text) + if def_name is not None: + # 检查重复定义 + dup: t.CInt = _name_table_add(name_table, pool, def_name) + if dup == 1: + dup_err: t.CChar | t.CPtr = pool.alloc(128) + if dup_err is not None: + viperlib.snprintf(dup_err, 128, "ERROR: duplicate definition '%s'", def_name) + _report_error(result, VERIFY_ERR_DUPLICATE_DEF, dup_err) + + # 检查未定义使用 + undef: t.CInt = _check_uses_in_line(name_table, text, def_name) + if undef > 0: + use_err: t.CChar | t.CPtr = pool.alloc(128) + if use_err is not None: + viperlib.snprintf(use_err, 128, "ERROR: %d undefined use(s) in: %s", undef, text) + _report_error(result, VERIFY_ERR_UNDEFINED_USE, use_err) + + line = line.Next + + blk = blk.Next + + return result.ErrorCount + + +def verify_module(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, result: VerifyResult | t.CPtr) -> t.CInt: + """验证模块中所有函数的 SSA 正确性。 + + 返回: 错误总数 + """ + if mod is None or result is None: return 1 + func: Function | t.CPtr = mod.FuncHead + while func is not None: + if func.IsDeclared == 0: + # 只验证有函数体的定义,跳过声明 + verify_function(pool, func, result) + func = func.Next + return result.ErrorCount diff --git a/lock.vp b/lock.vp new file mode 100644 index 0000000..5d0c114 --- /dev/null +++ b/lock.vp @@ -0,0 +1,38 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import CRITICAL_SECTION, InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, TryEnterCriticalSection + + +class Lock: + """Mutex built on CRITICAL_SECTION, supports recursive locking. + + Usage: + lock: Lock = Lock() + with lock: + # Critical section + pass + """ + cs: CRITICAL_SECTION + + def __init__(self): + InitializeCriticalSection(c.Addr(self.cs)) + + def acquire(self): + EnterCriticalSection(c.Addr(self.cs)) + + def release(self): + LeaveCriticalSection(c.Addr(self.cs)) + + def try_acquire(self) -> BOOL: + return TryEnterCriticalSection(c.Addr(self.cs)) + + def __enter__(self) -> 'Lock' | t.CPtr: + self.acquire() + return self + + def __exit__(self): + self.release() + + def delete(self): + DeleteCriticalSection(c.Addr(self.cs)) diff --git a/memhub.vp b/memhub.vp new file mode 100644 index 0000000..ff540d4 --- /dev/null +++ b/memhub.vp @@ -0,0 +1,823 @@ +import t, c +from stdint import * +import string +import atom +import viperio +import stdio +import stdlib + +# ============================================================ +# memhub - Unified memory management library +# MemManager (polymorphic base class, vtable) +# ├─ MemPool (arena bump allocator, no support for individual free) +# ├─ MemSlab (fixed-size block pool, alloc/free tracked via bitmap) +# └─ MemBuddy (buddy system, supports alloc/free/realloc with coalescing) +# All subclasses override alloc/free/reset via vtable, invokable polymorphically through MemManager pointer +# ============================================================ + +MEMHUB_ALIGN: t.CDefine = 8 + +# MemSlab bitmap constants +MEMSLAB_MIN_BLOCK: t.CDefine = 16 +MEMSLAB_BITMAP_BYTES: t.CDefine = 256 + +# MemBuddy buddy constants +MEMBUDDY_MIN_BLOCK: t.CDefine = 32 +MEMBUDDY_MAX_ORDERS: t.CDefine = 32 +MEMBUDDY_HEADER_SIZE: t.CDefine = 8 +# 块尾 canary:alloc 时在块尾(用户数据区之外)写 8 字节哨兵, +# check_alive_blocks 校验——越界写穿数据区会破坏 canary,把 +# "崩溃点漂移/事发地遥远"变成"确定性定位到越界写发生的文件" +MEMBUDDY_CANARY: t.CDefine = 8 + + +def _canary_pattern() -> t.CUInt64T: + """块尾 canary 值(0xA5A5A5A5A5A5A5A5,64 位)""" + lo: t.CUInt64T = t.CUInt64T(0xA5A5A5A5) + return (lo << 32) | lo + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: + if align == 0: return val + return (val + align - 1) & ~(align - 1) + + +def _largest_pow2_le(val: t.CSizeT) -> t.CSizeT: + if val == 0: return 0 + p: t.CSizeT = 1 + while p * 2 <= val: + p = p * 2 + return p + + +def _block_size_at_order(order: t.CInt) -> t.CSizeT: + bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + i: t.CInt + for i in range(order): + bs = bs << 1 + return bs + + +# ============================================================ +# MemManager - Polymorphic base class +# @t.CVTable explicit annotation to ensure recognition as vtable class during cross-module imports +# (HandlesImports only detects IsCVTable via decorator; automatic inference is unavailable across modules) +# ============================================================ +@t.CVTable +class MemManager: + __provides__: list[str] = ['__memmgr__'] + base: t.CVoid | t.CPtr # Starting address of memory region + size: t.CSizeT # Total size of memory region + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + self.base = base + self.size = size + + # === Virtual functions (overridden by subclasses) === + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + # Default: allocation not supported + return None + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + # Default: no operation + return 0 + + def reset(self) -> t.CInt: + # Default: no operation + return 0 + + # === Concrete methods (invoke virtual functions for automatic polymorphic dispatch) === + + def calloc(self, count: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr: + total: t.CSizeT = count * size + ptr: t.CVoid | t.CPtr = self.alloc(total) + if ptr is not None: + string.memset(ptr, 0, total) + return ptr + + def realloc(self, ptr: t.CVoid | t.CPtr, new_size: t.CSizeT) -> t.CVoid | t.CPtr: + if ptr is None: + return self.alloc(new_size) + if new_size == 0: + self.free(ptr) + return None + new_ptr: t.CVoid | t.CPtr = self.alloc(new_size) + if new_ptr is None: + return ptr + # Base class cannot track original allocation size; data will not be copied. Subclasses may override to preserve data + self.free(ptr) + return new_ptr + + def __enter__(self) -> 'MemManager' | t.CPtr: + return self + + def __exit__(self): + self.reset() + + def alloc_buf(self, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: + buf: viperio.Buf | t.CPtr = self.alloc(viperio.Buf.__sizeof__()) + if buf is None: + return None + data_ptr: t.CVoid | t.CPtr = self.alloc(capacity) + if data_ptr is None: + return None + buf.__before_init__() + buf.__init__(t.CChar(t.CUInt64T(data_ptr), t.CPtr), capacity) + return buf + + +# ============================================================ +# MemPool - Arena bump allocator +# Individual free operations are unsupported; reset reclaims all memory at once +# ============================================================ +class MemPool(MemManager): + offset: t.CSizeT # Bump pointer offset + high_water: t.CSizeT # High-water mark + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + self.base = base + self.size = size + self.offset = 0 + self.high_water = 0 + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + if size == 0: return None + aligned: t.CSizeT = _align_up(size, MEMHUB_ALIGN) + if self.offset + aligned > self.size: + stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") + stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size) + stdio.printf("[OOM] MemPool: total=%zu used=%zu (bump allocator, 无释放)\n", + self.size, self.offset) + stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n") + stdlib.exit(1) + ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.base) + self.offset, t.CPtr) + self.offset += aligned + if self.offset > self.high_water: + self.high_water = self.offset + return ptr + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + # Bump allocator does not support individual free operations + return 1 + + def reset(self) -> t.CInt: + self.offset = 0 + self.high_water = 0 + return 1 + + +# ============================================================ +# MemSlab - Fixed-size block pool +# Bitmap stored at the start of arena; subsequent area split into block_size units managed by free list +# ============================================================ +class MemSlab(MemManager): + block_size: t.CSizeT # Block size (aligned) + block_count: t.CSizeT # Total block count + used_count: t.CSizeT # Used block count + free_list: t.CVoid | t.CPtr # Free list head + alloc_map: t.CUInt8T | t.CPtr # Allocation bitmap (at start of arena) + alloc_map_size: t.CSizeT # Bitmap byte count + usable: t.CVoid | t.CPtr # Usable block area start (after bitmap) + usable_size: t.CSizeT # Usable block area size + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT, block_size: t.CSizeT): + self.base = base + self.size = size + self.block_size = 0 + self.block_count = 0 + self.used_count = 0 + self.free_list = None + self.alloc_map = None + self.alloc_map_size = 0 + self.usable = None + self.usable_size = 0 + + if base is None: return + + bs: t.CSizeT = _align_up(block_size, MEMHUB_ALIGN) + if bs < MEMSLAB_MIN_BLOCK: bs = MEMSLAB_MIN_BLOCK + + map_bytes: t.CSizeT = _align_up(MEMSLAB_BITMAP_BYTES, MEMHUB_ALIGN) + if size < map_bytes + bs: return + + self.alloc_map = base + self.alloc_map_size = map_bytes + self.usable = t.CVoid(t.CUInt64T(base) + map_bytes, t.CPtr) + self.usable_size = size - map_bytes + self.block_size = bs + + # Clear bitmap + idx: t.CSizeT = 0 + while idx < map_bytes: + self.alloc_map[idx] = 0 + idx += 1 + + self.block_count = self.usable_size / bs + if self.block_count == 0: return + + # Construct free list: the first 8 bytes of each block store pointer to next block + self.free_list = None + i: t.CSizeT = 0 + while i < self.block_count: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.usable) + i * bs, t.CPtr) + c.DerefAs(block, self.free_list) + self.free_list = block + i += 1 + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + # Slab mode: allocate one block only if requested size <= block_size + if self.free_list is None: + stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") + stdio.printf("[OOM] 尝试分配: %zu 字节,失败(free_list 已空)\n", size) + stdio.printf("[OOM] MemSlab: block_size=%zu block_count=%zu used=%zu\n", + self.block_size, self.block_count, self.used_count) + stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n") + stdlib.exit(1) + if size > self.block_size: + # 超块大小请求 = 调用方错误:优雅失败返回 NULL(类 malloc 语义,调用方自行判断)。 + # 与 free_list 耗尽(真正的 OOM,打印后 exit(1))区分开。 + stdio.printf("[WARN] MemSlab: 请求 %zu 字节超过 block_size=%zu,分配失败返回 NULL;应改用 MemBuddy/MemPool。\n", + size, self.block_size) + return None + block: t.CVoid | t.CPtr = self.free_list + self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + self.used_count += 1 + idx: t.CSizeT = (t.CUInt64T(block) - t.CUInt64T(self.usable)) / self.block_size + self.alloc_map[idx / 8] = self.alloc_map[idx / 8] | t.CUInt8T(1 << (idx % 8)) + return block + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + if ptr is None: return 0 + p: t.CUInt64T = t.CUInt64T(ptr) + if p < t.CUInt64T(self.usable): return 0 + if p >= t.CUInt64T(self.usable) + self.block_count * self.block_size: return 0 + if (p - t.CUInt64T(self.usable)) % self.block_size != 0: return 0 + idx: t.CSizeT = (p - t.CUInt64T(self.usable)) / self.block_size + byte_idx: t.CSizeT = idx / 8 + bit_idx: t.CInt = t.CInt(idx % 8) + if (self.alloc_map[byte_idx] >> bit_idx) & 1 == 0: return 0 + self.alloc_map[byte_idx] = self.alloc_map[byte_idx] & t.CUInt8T(~(1 << bit_idx)) + c.DerefAs(ptr, self.free_list) + self.free_list = ptr + self.used_count -= 1 + return 1 + + def reset(self) -> t.CInt: + self.used_count = 0 + self.free_list = None + i: t.CSizeT = 0 + while i < self.block_count: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.usable) + i * self.block_size, t.CPtr) + c.DerefAs(block, self.free_list) + self.free_list = block + if i / 8 < self.alloc_map_size: + self.alloc_map[i / 8] = 0 + i += 1 + return 1 + + +# ============================================================ +# MemBuddy - Buddy system allocator +# Free list head array stored at arena start; subsequent memory managed in power-of-two sized blocks +# Thread-safe (spinlock enabled), supports block coalescing +# +# Checkpoint 支持(供编译器等长任务回收阶段性分配): +# mark() → 返回当前分配水位(不分配内存) +# reset_to(m) → 释放水位 m 之后分配的所有块(回收到 free list) +# 记录栈从 usable 顶部预留 _CHK_RESERVE 字节,不参与 buddy 分配。 +# ============================================================ +class MemBuddy(MemManager): + # Override parent __provides__: MemBuddy provides both __mbuddy__ and __memmgr__. + # Within `with MemBuddy(...)` context, classes (e.g. _str) with __requires__=['__mbuddy__'] + # can be automatically injected via _find_provider + __provides__: list[str] = ['__mbuddy__', '__memmgr__'] + max_order: t.CInt # Maximum order + free_lists: t.CUInt64T | t.CPtr # Free list head array (located at arena start) + lock_val: t.CVolatile | t.CInt # Spinlock + usable: t.CVoid | t.CPtr # Start of usable memory region (skips free_lists) + usable_size: t.CSizeT # Size of usable memory (power of two) + chk_stack: t.CUInt64T | t.CPtr # Checkpoint 分配记录栈(存 block 地址) + chk_cap: t.CSizeT # 记录栈容量(条目数) + chk_depth: t.CSizeT # 当前记录深度 + chk_base: t.CVoid | t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区) + big_alloc_count: t.CSizeT # ≥8KB 大分配计数(OOM 诊断:定位大缓冲反复分配) + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + self.base = base + self.size = size + self.max_order = 0 + self.free_lists = None + self.lock_val = 0 + self.usable = None + self.usable_size = 0 + self.chk_stack = None + self.chk_cap = 0 + self.chk_depth = 0 + self.chk_base = None + self.big_alloc_count = 0 + + self.lock_val = 0 + fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8 + self.free_lists = base + + # Initialize all free list heads to be 0 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + self.free_lists[i] = 0 + + if size <= fl_bytes: + self.usable = None + self.usable_size = 0 + self.max_order = 0 + return + + remaining: t.CSizeT = size - fl_bytes + + # 注意:不能在 __init__ 里预留 checkpoint 记录栈! + # 记录栈改为 mark() 时从 buddy 池懒分配(见 mark())。 + # + # 非 2 的幂 arena 支持:主池 1.2GB(非 2 幂)不再被 + # _largest_pow2_le 砍成 1GB 浪费 0.2GB。整个区域按二进制 + # 分解拆成若干个 2 的幂空闲块压入对应 free list;buddy 合并 + # 按 offset^bs 匹配,跨分解边界的块因 order 不匹配自然停止 + # 合并,不会破坏 buddy 一致性。remaining 恰为 2 的幂时分解 + # 结果与原实现(单个 max_order 块)完全等价。 + max_blk: t.CSizeT = _largest_pow2_le(remaining) + if max_blk < MEMBUDDY_MIN_BLOCK: + self.usable = None + self.usable_size = 0 + self.max_order = 0 + return + + self.usable = t.CVoid(t.CUInt64T(base) + fl_bytes, t.CPtr) + + # 计算 max_order: log2(max_blk / MIN_BLOCK) + self.max_order = 0 + bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + while bs < max_blk: + bs = bs << 1 + self.max_order += 1 + + # 二进制分解:把 [usable, usable+remaining) 拆成 2 的幂空闲块。 + # 尾部碎片(< MIN_BLOCK)不入 free list;usable_size 记实际 + # 可分配字节(used/free 统计不含碎片)。 + pos: t.CSizeT = 0 + rem: t.CSizeT = remaining + used_area: t.CSizeT = 0 + while rem >= MEMBUDDY_MIN_BLOCK: + blk: t.CSizeT = _largest_pow2_le(rem) + o: t.CInt = 0 + ob: t.CSizeT = MEMBUDDY_MIN_BLOCK + while ob < blk: + ob = ob << 1 + o += 1 + self._fl_push(o, t.CVoid(t.CUInt64T(self.usable) + pos, t.CPtr)) + pos += blk + used_area += blk + rem -= blk + self.usable_size = used_area + + # === Checkpoint support === + + def mark(self) -> t.CSizeT: + """返回当前分配水位(checkpoint) + + 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、 + 避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。 + 初始容量 2M 条目(16MB):单文件翻译(parse AST + 生成 IR)可产生 + 几十万次 alloc,64K 初始容量会在首个大文件就触发 realloc 扩容, + 扩容失败时块不再记录 → reset_to 永久 no-op → 所有分配泄漏 → + 1GB 主池 OOM(NewAstTest Phase2 根因)。 + """ + if self.chk_stack is None: + cap: t.CSizeT = 2 * 1024 * 1024 + base: t.CVoid | t.CPtr = t.CVoid(stdlib.malloc(cap * 8), t.CPtr) + if base is None: + return 0 + self.chk_base = base + self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(base, t.CPtr)) + self.chk_cap = cap + self.chk_depth = 0 + return self.chk_depth + + def reset_to(self, mark: t.CSizeT): + """释放水位 mark 之后分配的所有块,回收到 free list + + 栈中每个 block:若 header 仍标记为已分配(奇数),_coalesce 归还; + 若已被单独 free(header==0),跳过避免重复归还。 + """ + if self.chk_stack is None: + return + if mark > self.chk_depth: + # mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例), + # reset 将 no-op → 之后分配全泄漏 → 1GB 主池 OOM。fail-fast 暴露。 + stdio.printf( + "[MEM] reset_to mark=%zu > chk_depth=%zu(mark 异常,reset 失效,终止)\n", + mark, self.chk_depth) + return + if mark >= self.chk_depth: + return + self._lock() + while self.chk_depth > mark: + self.chk_depth -= 1 + block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[self.chk_depth], t.CPtr) + if block is None: + continue + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + if (stored_val & 1) == 0: + continue # 已被单独 free,跳过 + order: t.CInt = t.CInt(stored_val >> 1) + if order < 0 or order > self.max_order: + continue + self._coalesce(block, order) + self._unlock() + + def reset_all(self): + """回收全部已分配块(等价 reset_to(0))""" + if self.chk_stack is None: + return + self.reset_to(0) + + # === Free list operations === + + def _fl_push(self, order: t.CInt, block: t.CVoid | t.CPtr): + old_head: t.CUInt64T = self.free_lists[order] + c.DerefAs(block, t.CVoid(old_head, t.CPtr)) + self.free_lists[order] = t.CUInt64T(block) + + def _fl_pop(self, order: t.CInt) -> t.CVoid | t.CPtr: + head_val: t.CUInt64T = self.free_lists[order] + if head_val == 0: + return None + block: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + self.free_lists[order] = t.CUInt64T(next_ptr) + return block + + def _fl_find_and_remove(self, order: t.CInt, target: t.CVoid | t.CPtr) -> t.CInt: + head_val: t.CUInt64T = self.free_lists[order] + if head_val == 0: + return 0 + head: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + if t.CUInt64T(head) == t.CUInt64T(target): + next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(head, t.CPtr)), t.CPtr) + self.free_lists[order] = t.CUInt64T(next_ptr) + return 1 + prev: t.CVoid | t.CPtr = head + cur: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(head, t.CPtr)), t.CPtr) + while t.CUInt64T(cur) != 0: + if t.CUInt64T(cur) == t.CUInt64T(target): + next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + c.DerefAs(prev, next_ptr) + return 1 + prev = cur + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return 0 + + # === Buddy system core === + + def _buddy_of(self, block: t.CVoid | t.CPtr, order: t.CInt) -> t.CVoid | t.CPtr: + offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + bs: t.CSizeT = _block_size_at_order(order) + buddy_offset: t.CSizeT = offset ^ bs + return t.CVoid(t.CUInt64T(self.usable) + buddy_offset, t.CPtr) + + def _order_for_size(self, size: t.CSizeT) -> t.CInt: + order: t.CInt = 0 + bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + while bs < size: + bs = bs << 1 + order += 1 + return order + + def _split_to_order(self, to_order: t.CInt) -> t.CVoid | t.CPtr: + found_order: t.CInt = to_order + while found_order <= self.max_order: + if self.free_lists[found_order] != 0: + break + found_order += 1 + if found_order > self.max_order: + return None + block: t.CVoid | t.CPtr = self._fl_pop(found_order) + while found_order > to_order: + found_order -= 1 + bs: t.CSizeT = _block_size_at_order(found_order) + buddy: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(block) + bs, t.CPtr) + self._fl_push(found_order, buddy) + return block + + def _coalesce(self, block: t.CVoid | t.CPtr, order: t.CInt): + while order < self.max_order: + buddy: t.CVoid | t.CPtr = self._buddy_of(block, order) + found: t.CInt = self._fl_find_and_remove(order, buddy) + if found == 0: + break + if t.CUInt64T(buddy) < t.CUInt64T(block): + block = buddy + order += 1 + self._fl_push(order, block) + + def _is_valid_ptr(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + if ptr is None: return 0 + if self.usable is None: return 0 + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + if t.CUInt64T(block) < t.CUInt64T(self.usable): return 0 + if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size: return 0 + offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + if offset % MEMBUDDY_MIN_BLOCK != 0: return 0 + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + if (stored_val & 1) == 0: return 0 + order: t.CInt = t.CInt(stored_val >> 1) + if order < 0: return 0 + if order > self.max_order: return 0 + # 记录栈一致性校验:分配时(alloc)每个 block 地址都会压入 chk_stack。 + # reset_to(mark) 会把 [mark, chk_depth) 的块弹栈并归还 free list, + # 之后这些地址会被重新分配。若一个 header 恰好是合法奇数(假阳性), + # 但地址不在当前 chk_stack[0..chk_depth) 存活区间内,说明已被回收, + # 不能当作有效指针(否则 _format_func_type_str/TypePrint 会沿垃圾链 + # 无限分配导致 OOM)。 + # 注意:chk_stack 容量满(64K)后 alloc 不再记录新块(chk_depth==chk_cap), + # 此时无法区分,跳过校验(退化到仅 header 校验,避免误判正常 free)。 + if self.chk_stack is not None and self.chk_depth < self.chk_cap: + alive: t.CInt = 0 + ci: t.CSizeT = 0 + while ci < self.chk_depth: + if self.chk_stack[ci] == t.CUInt64T(block): + alive = 1 + break + ci += 1 + if alive == 0: + return 0 + return 1 + + # === Spinlock === + + def _lock(self): # can use the spinlock library for decoupling + while atom.__atomic_test_and_set(c.Addr(self.lock_val), atom.ATOMIC_ACQUIRE): + pass + + def _unlock(self): + atom.__atomic_clear(c.Addr(self.lock_val), atom.ATOMIC_RELEASE) + + # === Virtual function overrides === + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + self._lock() + result: t.CVoid | t.CPtr = None + if size != 0 and self.usable is not None: + # +MEMBUDDY_CANARY:预留块尾 8 字节哨兵(用户数据区之外),越界写定位用 + needed: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + order: t.CInt = self._order_for_size(needed) + if order <= self.max_order: + block: t.CVoid | t.CPtr = self._split_to_order(order) + if block is not None: + c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr)) + result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr) + # 写块尾 canary(block + block_size - CANARY) + bs: t.CSizeT = _block_size_at_order(order) + c.DerefAs(t.CVoid(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), + t.CVoid(_canary_pattern(), t.CPtr)) + # 记录到 checkpoint 栈(供 reset_to 回收) + # 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失 + # → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题) + if self.chk_stack is not None: + if self.chk_depth >= self.chk_cap: + new_cap: t.CSizeT = self.chk_cap * 2 + new_stack: t.CVoid | t.CPtr = t.CVoid( + stdlib.realloc(self.chk_base, new_cap * 8), t.CPtr) + if new_stack is not None: + self.chk_base = new_stack + self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(new_stack, t.CPtr)) + self.chk_cap = new_cap + else: + # realloc 失败:块不再记录 → reset_to 无法回收该块 → + # 渐进泄漏最终 1GB 主池 OOM。fail-fast 暴露而非静默。 + stdio.printf( + "[MEM] 记录栈 realloc 失败 cap=%zu depth=%zu(reset 将失效,终止)\n", + self.chk_cap, self.chk_depth) + if self.chk_depth < self.chk_cap: + self.chk_stack[self.chk_depth] = t.CUInt64T(block) + self.chk_depth += 1 + if result is None: + # 分配失败诊断(定位"异常 size/池耗尽导致 None → 调用方解引用段错误") + if size != 0 and self.usable is not None: + needed2: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + order2: t.CInt = self._order_for_size(needed2) + stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu\n", + size, needed2, order2, self.max_order, self.used_bytes()) + # 越界写诊断:free list 结构损坏(self_check!=0)说明有越界写穿 + # 破坏块头/free list next 指针 → alloc 找不到块(used 虚高非真实耗尽) + sc: t.CInt = self.self_check() + stdio.printf("[MEM] alloc 失败 self_check=%d free_bytes=%zu free_count=%zu chk_depth=%zu big=%zu\n", + sc, self.free_bytes(), self.free_count(), self.chk_depth, self.big_alloc_count) + # chk_depth 巨大(数百万)→ 分配次数爆炸(每语句/每调用反复分配); + # chk_depth 不大但 used 巨大 → 单次大分配(缓冲/表扩容)反复发生 + if order2 > self.max_order: + stdio.printf("[MEM] 原因:请求 size 超 pool 最大块(order %d > max %d)\n", + order2, self.max_order) + else: + stdio.printf("[MEM] 原因:pool 耗尽(空闲 %zu 字节不足)\n", self.free_bytes()) + # 分配失败(alloc(0) 或池耗尽):解锁并返回 None,由调用者决定后续处理。 + # 不能 exit——测试依赖 alloc 失败返回 None 后继续 free+重试 + # (如 OOM section: 耗尽后 free 一块再 alloc 应成功)。 + self._unlock() + return None + self._unlock() + return result + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + self._lock() + if ptr is not None: + if self._is_valid_ptr(ptr) != 0: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + order: t.CInt = t.CInt(stored_val >> 1) + c.DerefAs(block, t.CVoid(0, t.CPtr)) + self._coalesce(block, order) + self._unlock() + return 1 + + def _rebuild_free_lists(self): + """按二进制分解重建空闲链表(reset 恢复初始分配格局) + + 与 __init__ 的初始化分解一致:非 2 的幂 arena 会拆成多个 + 2 的幂空闲块(buddy 合并跨分解边界时因 order 不匹配自然 + 停止,安全);2 的幂 arena 等价于单个 max_order 块。 + """ + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + self.free_lists[i] = 0 + pos: t.CSizeT = 0 + rem: t.CSizeT = self.usable_size + while rem >= MEMBUDDY_MIN_BLOCK: + blk: t.CSizeT = _largest_pow2_le(rem) + o: t.CInt = 0 + ob: t.CSizeT = MEMBUDDY_MIN_BLOCK + while ob < blk: + ob = ob << 1 + o += 1 + self._fl_push(o, t.CVoid(t.CUInt64T(self.usable) + pos, t.CPtr)) + pos += blk + rem -= blk + + def reset(self) -> t.CInt: + if self.usable is None: + return 0 + self._rebuild_free_lists() + return 1 + + # realloc override: buddy system reads original order from block header; old_size is not required + def realloc(self, ptr: t.CVoid | t.CPtr, new_size: t.CSizeT) -> t.CVoid | t.CPtr: + if ptr is None: + return self.alloc(new_size) + if new_size == 0: + self.free(ptr) + return None + if self._is_valid_ptr(ptr) == 0: + return None + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + old_order: t.CInt = t.CInt(stored_val >> 1) + needed: t.CSizeT = new_size + MEMBUDDY_HEADER_SIZE + new_order: t.CInt = self._order_for_size(needed) + if new_order <= old_order: + return ptr + new_ptr: t.CVoid | t.CPtr = self.alloc(new_size) + if new_ptr is None: + return ptr + old_block_size: t.CSizeT = _block_size_at_order(old_order) + old_data_size: t.CSizeT = old_block_size - MEMBUDDY_HEADER_SIZE + string.memcpy(new_ptr, ptr, old_data_size) + self.free(ptr) + return new_ptr + + # === Status Queries === + + @property + def mem_size(self) -> t.CSizeT: + # Total usable region size (power of two). Maximum allocatable size = mem_size - MEMBUDDY_HEADER_SIZE + return self.usable_size + + def stats(self) -> t.CSizeT: + # Return total usable region size, for status statistics + return self.usable_size + + def free_count(self) -> t.CSizeT: + # Count total blocks in all order lists for status statistics + count: t.CSizeT = 0 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + head_val: t.CUInt64T = self.free_lists[i] + cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + while t.CUInt64T(cur) != 0: + count += 1 + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return count + + def free_bytes(self) -> t.CSizeT: + # Count total bytes in all free blocks for status statistics + total: t.CSizeT = 0 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + head_val: t.CUInt64T = self.free_lists[i] + cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + while t.CUInt64T(cur) != 0: + total += _block_size_at_order(i) + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return total + + def used_bytes(self) -> t.CSizeT: + # Used bytes = total usable region size - free bytes in all free blocks + return self.usable_size - self.free_bytes() + + def dump_stats(self, label: t.CChar | t.CPtr): + # Print memory usage statistics + fb: t.CSizeT = self.free_bytes() + ub: t.CSizeT = self.usable_size - fb + stdio.printf("[MEM] %s: total=%zu used=%zu (%zu%%) free=%zu free_blocks=%zu\n", + label, self.usable_size, ub, + (ub * 100) / self.usable_size if self.usable_size > 0 else 0, + fb, self.free_count()) + + def self_check(self) -> t.CInt: + # Validate buddy allocator internal consistency, return 0=OK, non-0=damage + if self.usable is None: + return 0 + # 环检测:free list 被越界写破坏 next 指针后可能成环, + # 无步数上限会导致无限循环(崩溃点漂移排查哨兵必须能终止)。 + max_steps: t.CSizeT = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + head_val: t.CUInt64T = self.free_lists[i] + cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + steps: t.CSizeT = 0 + while t.CUInt64T(cur) != 0: + steps += 1 + if steps > max_steps: + return 4 # free list 成环或节点数超上限(next 指针被破坏) + # Check pointer is in usable region range + if t.CUInt64T(cur) < t.CUInt64T(self.usable): + return 1 + if t.CUInt64T(cur) >= t.CUInt64T(self.usable) + self.usable_size: + return 2 + # Check alignment: order i blocks must be aligned to size _block_size_at_order(i) + offset: t.CSizeT = t.CUInt64T(cur) - t.CUInt64T(self.usable) + bs: t.CSizeT = _block_size_at_order(i) + if offset % bs != 0: + return 3 + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return 0 + + def check_alive_blocks(self, from_mark: t.CSizeT) -> t.CInt: + # 检查 [from_mark, chk_depth) 记录的所有已分配块 header 完整性。 + # 越界写(参数错位/下标 GEP 越界)会破坏相邻块 header(奇偶位/order 错乱), + # 返回 0=OK,非 0=损坏(rc 语义见调用方注释)。 + # 用于 reset_to 前哨兵:把"崩溃点漂移"变成"确定性定位到损坏发生的文件"。 + if self.chk_stack is None: + return + if from_mark > self.chk_depth: + # from_mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例), + # 校验将 no-op → 越界写漏检。fail-fast 暴露。 + stdio.printf( + "[MEM] check_alive_blocks from_mark=%zu > chk_depth=%zu(mark 异常)\n", + from_mark, self.chk_depth) + return + if from_mark >= self.chk_depth: + return 0 + if self.usable is None: + return 0 + ci: t.CSizeT = from_mark + while ci < self.chk_depth: + block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[ci], t.CPtr) + if block is not None: + if t.CUInt64T(block) < t.CUInt64T(self.usable): + return 1 + if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size: + return 2 + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + if (stored_val & 1) != 0: + # 活块:header 必须是 (order<<1)|1,order 合法且块对齐到该 order 大小 + order: t.CInt = t.CInt(stored_val >> 1) + if order < 0: + return 3 + if order > self.max_order: + return 4 + offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + bs: t.CSizeT = _block_size_at_order(order) + if offset % bs != 0: + return 5 + # 块尾 canary 校验:越界写穿数据区会破坏块尾哨兵, + # 立即定位到越界写发生的文件(崩溃点漂移的关键哨兵) + can_stored: t.CVoid | t.CPtr = t.CVoid( + c.Deref(t.CUInt64T(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), t.CPtr), + t.CPtr) + if t.CUInt64T(can_stored) != _canary_pattern(): + return 6 + ci += 1 + return 0 + diff --git a/numpy/__init__.vp b/numpy/__init__.vp new file mode 100644 index 0000000..f8e5456 --- /dev/null +++ b/numpy/__init__.vp @@ -0,0 +1,1163 @@ +from stdint import * +import stdlib +import string +import vipermath +import stdio +import t, c +import memhub + + +# ============================================================ +# Constants +# ============================================================ +MAX_NDIM: t.CDefine = 4 + +float64: t.CTypedef = t.CDouble +float32: t.CTypedef = t.CFloat +int64: t.CTypedef = t.CLong +int32: t.CTypedef = t.CInt +uint8: t.CTypedef = t.CUnsignedChar + +pi: t.CDefine = 3.14159265358979323846 +e: t.CDefine = 2.71828182845904523536 + +# ============================================================ +# ndarray - generic n-dimensional array (PEP 695) +# +# Element type T is a numeric type (t.CDouble / t.CFloat / t.CInt / ...). +# T is erased to i8* at the IR level but each ndarray[T] instantiation +# generates specialized code (data access uses T's load/store width). +# +# Default usage: ndarray[t.CDouble] for floating point. +# ============================================================ +@t.Object +class ndarray[T]: + data: T | t.CPtr + shape: t.CArray[t.CSizeT, MAX_NDIM] + strides: t.CArray[t.CSizeT, MAX_NDIM] + ndim: t.CInt + size: t.CSizeT + owns_data: t.CInt + pool: memhub.MemManager | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, n: t.CSizeT): + self.pool = pool + self.data = pool.alloc(n * T.__sizeof__()) + if self.data: + string.memset(self.data, 0, n * T.__sizeof__()) + self.ndim = 1 + self.size = n + self.shape[0] = n + self.strides[0] = 1 + self.owns_data = 1 + + def __add__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = self.data[i] + other.data[i] + i += 1 + return result + + def __sub__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = self.data[i] - other.data[i] + i += 1 + return result + + def __mul__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = self.data[i] * other.data[i] + i += 1 + return result + + def __truediv__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != T(0): + result.data[i] = self.data[i] / other.data[i] + else: + result.data[i] = T(0) + i += 1 + return result + + def __floordiv__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != T(0): + result.data[i] = vipermath.floor(self.data[i] / other.data[i]) + else: + result.data[i] = T(0) + i += 1 + return result + + def __mod__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != T(0): + result.data[i] = vipermath.fmod(self.data[i], other.data[i]) + else: + result.data[i] = T(0) + i += 1 + return result + + def __neg__(self) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = -self.data[i] + i += 1 + return result + + def __len__(self) -> t.CInt: + if self.ndim > 0: return t.CInt(self.shape[0]) + return 0 + + def at2d(self, row: t.CSizeT, col: t.CSizeT) -> T: + return self.data[row * self.shape[1] + col] + + def set2d(self, row: t.CSizeT, col: t.CSizeT, val: T): + self.data[row * self.shape[1] + col] = val + + def delete(self): + if self.owns_data and self.data: + self.pool.free(self.data) + self.data = None + self.pool.free(self) + + def fill(self, val: T): + i: t.CSizeT = 0 + while i < self.size: + self.data[i] = val + i += 1 + + def copy(self) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + string.memcpy(result.data, self.data, self.size * T.__sizeof__()) + return result + + def reshape(self, new_shape: INTPTR, new_ndim: t.CInt) -> ndarray[T] | t.CPtr: + new_size: t.CSizeT = 1 + i: t.CInt = 0 + for i in range(new_ndim): + new_size *= t.CSizeT(new_shape[i]) + if new_size != self.size: return None + result: ndarray[T] | t.CPtr = _alloc_ndarray(self.pool) + if not result: return None + result.data = self.data + result.pool = self.pool + result.ndim = new_ndim + result.size = self.size + result.owns_data = 0 + for i in range(new_ndim): + result.shape[i] = t.CSizeT(new_shape[i]) + _compute_strides(result) + return result + + def sum(self) -> T: + s: T = T(0) + i: t.CSizeT = 0 + while i < self.size: + s += self.data[i] + i += 1 + return s + + def mean(self) -> T: + if self.size == 0: return T(0) + return self.sum() / T(self.size) + + def min(self) -> T: + if self.size == 0: return T(0) + m: T = self.data[0] + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] < m: m = self.data[i] + i += 1 + return m + + def max(self) -> T: + if self.size == 0: return T(0) + m: T = self.data[0] + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] > m: m = self.data[i] + i += 1 + return m + + def argmax(self) -> t.CInt: + if self.size == 0: return -1 + m: T = self.data[0] + idx: t.CInt = 0 + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] > m: + m = self.data[i] + idx = t.CInt(i) + i += 1 + return idx + + def argmin(self) -> t.CInt: + if self.size == 0: return -1 + m: T = self.data[0] + idx: t.CInt = 0 + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] < m: + m = self.data[i] + idx = t.CInt(i) + i += 1 + return idx + + def dot(self, other: ndarray[T] | t.CPtr) -> T: + s: T = T(0) + n: t.CSizeT = self.size if (self.size < other.size) else other.size + i: t.CSizeT = 0 + while i < n: + s += self.data[i] * other.data[i] + i += 1 + return s + + def T(self) -> ndarray[T] | t.CPtr: + if self.ndim != 2: return None + rows: t.CSizeT = self.shape[0] + cols: t.CSizeT = self.shape[1] + result: ndarray[T] | t.CPtr = empty2d(self.pool, rows, cols) + if not result: return None + # Swap shape for transpose + result.shape[0] = cols + result.shape[1] = rows + _compute_strides(result) + i: t.CSizeT = 0 + while i < rows: + j: t.CSizeT = 0 + while j < cols: + result.data[j * rows + i] = self.data[i * cols + j] + j += 1 + i += 1 + return result + + def print_arr(self): + if self.ndim == 1: + stdio.printf("[") + i: t.CSizeT = 0 + while i < self.size: + if i > 0: stdio.printf(", ") + stdio.printf("%.4f", self.data[i]) + i += 1 + stdio.printf("]\n") + elif self.ndim == 2: + rows: t.CSizeT = self.shape[0] + cols: t.CSizeT = self.shape[1] + stdio.printf("[") + i: t.CSizeT = 0 + while i < rows: + if i > 0: stdio.printf(" ") + stdio.printf("[") + j: t.CSizeT = 0 + while j < cols: + if j > 0: stdio.printf(", ") + stdio.printf("%.4f", self.data[i * cols + j]) + j += 1 + if i < rows - 1: + stdio.printf("]\n") + else: + stdio.printf("]]\n") + i += 1 + + +# ============================================================ +# Convenience aliases: typed ndarray instantiations +# (must be after class ndarray[T] definition to avoid forward reference) +# ============================================================ +Float64Array: t.CTypedef = ndarray[t.CDouble] +Float32Array: t.CTypedef = ndarray[t.CFloat] +Int64Array: t.CTypedef = ndarray[t.CLong] +Int32Array: t.CTypedef = ndarray[t.CInt] +Uint8Array: t.CTypedef = ndarray[t.CUnsignedChar] + + +# ============================================================ +# Internal helpers (specialized for float64 by default) +# Use _alloc_ndarray_t[T] / _empty_like_t[T] for other types +# ============================================================ +def _alloc_ndarray(pool: memhub.MemManager | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = pool.alloc(ndarray[t.CDouble].__sizeof__()) + if a: + string.memset(a, 0, ndarray[t.CDouble].__sizeof__()) + return a + +def _compute_strides(a: ndarray[t.CDouble] | t.CPtr): + if a.ndim <= 0: return + a.strides[a.ndim - 1] = 1 + i: t.CInt = a.ndim - 2 + while i >= 0: + a.strides[i] = a.strides[i + 1] * a.shape[i + 1] + i -= 1 + +def _empty_like(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(a.pool) + if not result: return None + result.data = a.pool.alloc(a.size * t.CDouble.__sizeof__()) + if not result.data: + a.pool.free(result) + return None + result.pool = a.pool + result.ndim = a.ndim + result.size = a.size + result.owns_data = 1 + i: t.CInt = 0 + for i in range(a.ndim): + result.shape[i] = a.shape[i] + _compute_strides(result) + return result + + +# ============================================================ +# Array creation functions (float64 default) +# ============================================================ +def array(pool: memhub.MemManager | t.CPtr, data: t.CDouble | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(pool) + if not a: return None + a.data = pool.alloc(n * t.CDouble.__sizeof__()) + if not a.data: + pool.free(a) + return None + string.memcpy(a.data, data, n * t.CDouble.__sizeof__()) + a.pool = pool + a.ndim = 1 + a.size = n + a.shape[0] = n + a.strides[0] = 1 + a.owns_data = 1 + return a + +def zeros(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(pool) + if not a: return None + a.data = pool.alloc(n * t.CDouble.__sizeof__()) + if not a.data: + pool.free(a) + return None + string.memset(a.data, 0, n * t.CDouble.__sizeof__()) + a.pool = pool + a.ndim = 1 + a.size = n + a.shape[0] = n + a.strides[0] = 1 + a.owns_data = 1 + return a + +def ones(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) + if not a: return None + a.fill(t.CDouble(1.0)) + return a + +def full(pool: memhub.MemManager | t.CPtr, n: t.CSizeT, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) + if not a: return None + a.fill(val) + return a + +def arange(pool: memhub.MemManager | t.CPtr, start: t.CDouble, stop: t.CDouble, step: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + if step == t.CDouble(0.0): return None + n: t.CSizeT = 0 + if step > t.CDouble(0.0): + v: t.CDouble = start + while v < stop: + n += 1 + v += step + else: + v: t.CDouble = start + while v > stop: + n += 1 + v += step + if n == 0: return None + a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) + if not a: return None + i: t.CSizeT = 0 + v = start + while i < n: + a.data[i] = v + v += step + i += 1 + return a + +def linspace(pool: memhub.MemManager | t.CPtr, start: t.CDouble, stop: t.CDouble, num: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + if num == 0: return None + a: ndarray[t.CDouble] | t.CPtr = zeros(pool, num) + if not a: return None + if num == 1: + a.data[0] = start + return a + step: t.CDouble = (stop - start) / t.CDouble(num - 1) + i: t.CSizeT = 0 + while i < num: + a.data[i] = start + t.CDouble(i) * step + i += 1 + return a + +def empty2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(pool) + if not a: return None + total: t.CSizeT = rows * cols + a.data = pool.alloc(total * t.CDouble.__sizeof__()) + if not a.data: + pool.free(a) + return None + string.memset(a.data, 0, total * t.CDouble.__sizeof__()) + a.pool = pool + a.ndim = 2 + a.size = total + a.shape[0] = rows + a.shape[1] = cols + a.owns_data = 1 + _compute_strides(a) + return a + +def zeros2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + return empty2d(pool, rows, cols) + +def ones2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, rows, cols) + if not a: return None + a.fill(t.CDouble(1.0)) + return a + +def eye(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, n, n) + if not a: return None + i: t.CSizeT = 0 + while i < n: + a.data[i * n + i] = t.CDouble(1.0) + i += 1 + return a + +def diag(pool: memhub.MemManager | t.CPtr, vals: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + n: t.CSizeT = vals.size + a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, n, n) + if not a: return None + i: t.CSizeT = 0 + while i < n: + a.data[i * n + i] = vals.data[i] + i += 1 + return a + + +# ============================================================ +# Mathematical functions (element-wise, float64 default) +# ============================================================ +def np_abs(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + v: t.CDouble = a.data[i] + result.data[i] = v if v >= t.CDouble(0.0) else -v + i += 1 + return result + +def np_sqrt(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.sqrt(a.data[i]) + i += 1 + return result + +def np_exp(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.exp(a.data[i]) + i += 1 + return result + +def np_log(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.log(a.data[i]) + i += 1 + return result + +def np_sin(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.sin(a.data[i]) + i += 1 + return result + +def np_cos(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.cos(a.data[i]) + i += 1 + return result + +def np_tan(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.tan(a.data[i]) + i += 1 + return result + +def np_pow(a: ndarray[t.CDouble] | t.CPtr, p: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.pow(a.data[i], p) + i += 1 + return result + + +# ============================================================ +# Scalar operations (float64 default) +# ============================================================ +def add_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] + s + i += 1 + return result + +def mul_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] * s + i += 1 + return result + +def sub_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] - s + i += 1 + return result + +def div_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + if s != t.CDouble(0.0): + result.data[i] = a.data[i] / s + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + + +# ============================================================ +# Matrix operations (float64 default) +# ============================================================ +def matmul(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # 2D matrix multiply: a(m,k) x b(k,n) = c(m,n) + if a.ndim != 2 or b.ndim != 2: return None + m: t.CSizeT = a.shape[0] + k: t.CSizeT = a.shape[1] + k2: t.CSizeT = b.shape[0] + n: t.CSizeT = b.shape[1] + if k != k2: return None + c: ndarray[t.CDouble] | t.CPtr = empty2d(a.pool, m, n) + if not c: return None + i: t.CSizeT = 0 + while i < m: + j: t.CSizeT = 0 + while j < n: + s: t.CDouble = t.CDouble(0.0) + p: t.CSizeT = 0 + while p < k: + s += a.data[i * k + p] * b.data[p * n + j] + p += 1 + c.data[i * n + j] = s + j += 1 + i += 1 + return c + +def dot_product(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.dot(b) + + +# ============================================================ +# Reduction operations (float64 default) +# ============================================================ +def np_sum(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.sum() + +def np_mean(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.mean() + +def np_min(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.min() + +def np_max(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.max() + +def np_argmax(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + return a.argmax() + +def np_argmin(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + return a.argmin() + + +# ============================================================ +# Utility (float64 default) +# ============================================================ +def var(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + m: t.CDouble = a.mean() + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < a.size: + d: t.CDouble = a.data[i] - m + s += d * d + i += 1 + return s / t.CDouble(a.size) + +def std(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return vipermath.sqrt(var(a)) + +def norm(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return vipermath.sqrt(a.dot(a)) + +def clip(a: ndarray[t.CDouble] | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + v: t.CDouble = a.data[i] + if v < lo: v = lo + if v > hi: v = hi + result.data[i] = v + i += 1 + return result + +def concatenate(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + if a.ndim != 1 or b.ndim != 1: return None + total: t.CSizeT = a.size + b.size + result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, total) + if not result: return None + string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + string.memcpy(result.data + a.size, b.data, b.size * t.CDouble.__sizeof__()) + return result + +def sort_arr(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = a.copy() + if not result: return None + # Simple insertion sort + i: t.CSizeT = 1 + while i < result.size: + key: t.CDouble = result.data[i] + j: t.CSizeT = i - 1 + while j < result.size and result.data[j] > key: + result.data[j + 1] = result.data[j] + if j == 0: break + j -= 1 + if j > 0 or result.data[0] <= key: + result.data[j + 1] = key + else: + result.data[1] = result.data[0] + result.data[0] = key + i += 1 + return result + +def reverse(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[a.size - 1 - i] + i += 1 + return result + + +# ============================================================ +# Additional math functions (element-wise, float64 default) +# ============================================================ +def np_log10(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.log10(a.data[i]) + i += 1 + return result + +def np_log2(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.log2(a.data[i]) + i += 1 + return result + +def np_floor(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.floor(a.data[i]) + i += 1 + return result + +def np_ceil(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.ceil(a.data[i]) + i += 1 + return result + +def np_round(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.round(a.data[i]) + i += 1 + return result + +def np_sign(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] > t.CDouble(0.0): + result.data[i] = t.CDouble(1.0) + elif a.data[i] < t.CDouble(0.0): + result.data[i] = t.CDouble(-1.0) + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + +def np_tanh(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.tanh(a.data[i]) + i += 1 + return result + +def np_sinh(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.sinh(a.data[i]) + i += 1 + return result + +def np_cosh(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.cosh(a.data[i]) + i += 1 + return result + +def np_arcsin(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.asin(a.data[i]) + i += 1 + return result + +def np_arccos(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.acos(a.data[i]) + i += 1 + return result + +def np_arctan(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.atan(a.data[i]) + i += 1 + return result + +def np_arctan2(y: ndarray[t.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(y) + if not result: return None + i: t.CSizeT = 0 + while i < y.size: + result.data[i] = vipermath.atan2(y.data[i], x.data[i]) + i += 1 + return result + +def np_degrees(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.degrees(a.data[i]) + i += 1 + return result + +def np_radians(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.radians(a.data[i]) + i += 1 + return result + +def np_isnan(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(vipermath.isnan(a.data[i])) + i += 1 + return result + +def np_isinf(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(vipermath.isinf(a.data[i])) + i += 1 + return result + +def np_maximum(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] if a.data[i] > b.data[i] else b.data[i] + i += 1 + return result + +def np_minimum(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] if a.data[i] < b.data[i] else b.data[i] + i += 1 + return result + + +# ============================================================ +# Additional array operations (float64 default) +# ============================================================ +def cumsum(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < a.size: + s += a.data[i] + result.data[i] = s + i += 1 + return result + +def diff(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + if a.size < 2: return None + result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, a.size - 1) + if not result: return None + i: t.CSizeT = 0 + while i < a.size - 1: + result.data[i] = a.data[i + 1] - a.data[i] + i += 1 + return result + +def flatten(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + result.ndim = 1 + result.shape[0] = a.size + result.strides[0] = 1 + string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + return result + +def trace(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + if a.ndim != 2: return t.CDouble(0.0) + n: t.CSizeT = a.shape[0] if a.shape[0] < a.shape[1] else a.shape[1] + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < n: + s += a.data[i * a.shape[1] + i] + i += 1 + return s + +def outer(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = empty2d(a.pool, a.size, b.size) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + j: t.CSizeT = 0 + while j < b.size: + result.data[i * b.size + j] = a.data[i] * b.data[j] + j += 1 + i += 1 + return result + +def np_where(condition: ndarray[t.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.CPtr, y: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(x) + if not result: return None + i: t.CSizeT = 0 + while i < x.size: + if condition.data[i] != t.CDouble(0.0): + result.data[i] = x.data[i] + else: + result.data[i] = y.data[i] + i += 1 + return result + +def np_count_nonzero(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + count: t.CInt = 0 + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] != t.CDouble(0.0): + count += 1 + i += 1 + return count + +def np_all(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] == t.CDouble(0.0): + return 0 + i += 1 + return 1 + +def np_any(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] != t.CDouble(0.0): + return 1 + i += 1 + return 0 + +def np_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] == b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_not_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] != b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_less(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] < b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_greater(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] > b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_less_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] <= b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_greater_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] >= b.data[i] else t.CDouble(0.0) + i += 1 + return result + + +# ============================================================ +# Additional creation functions (float64 default) +# ============================================================ +def empty(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + return zeros(pool, n) + +def full2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, rows, cols) + if not a: return None + a.fill(val) + return a + +def zeros_like(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(a.pool) + if not result: return None + result.data = a.pool.alloc(a.size * t.CDouble.__sizeof__()) + if not result.data: + a.pool.free(result) + return None + string.memset(result.data, 0, a.size * t.CDouble.__sizeof__()) + result.pool = a.pool + result.ndim = a.ndim + result.size = a.size + result.owns_data = 1 + i: t.CInt = 0 + for i in range(a.ndim): + result.shape[i] = a.shape[i] + _compute_strides(result) + return result + +def ones_like(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + result.fill(t.CDouble(1.0)) + return result + +def arange1(pool: memhub.MemManager | t.CPtr, stop: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + return arange(pool, t.CDouble(0.0), stop, t.CDouble(1.0)) + +def linspace2(pool: memhub.MemManager | t.CPtr, start: t.CDouble, stop: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + return linspace(pool, start, stop, 50) + +def meshgrid(x: ndarray[t.CDouble] | t.CPtr, y: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # Returns flattened grid pairs - simplified version + # Returns X grid as 2D array (each row is x) + result: ndarray[t.CDouble] | t.CPtr = empty2d(x.pool, y.size, x.size) + if not result: return None + i: t.CSizeT = 0 + while i < y.size: + j: t.CSizeT = 0 + while j < x.size: + result.data[i * x.size + j] = x.data[j] + j += 1 + i += 1 + return result + + +# ============================================================ +# Linear algebra helpers (float64 default) +# ============================================================ +def det2x2(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + # Determinant of 2x2 matrix + if a.ndim != 2: return t.CDouble(0.0) + if a.shape[0] != 2 or a.shape[1] != 2: return t.CDouble(0.0) + return a.data[0] * a.data[3] - a.data[1] * a.data[2] + +def inv2x2(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # Inverse of 2x2 matrix + d: t.CDouble = det2x2(a) + if d == t.CDouble(0.0): return None + result: ndarray[t.CDouble] | t.CPtr = empty2d(a.pool, 2, 2) + if not result: return None + result.data[0] = a.data[3] / d + result.data[1] = -a.data[1] / d + result.data[2] = -a.data[2] / d + result.data[3] = a.data[0] / d + return result + +def cross3(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # Cross product of 3D vectors + result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, 3) + if not result: return None + result.data[0] = a.data[1] * b.data[2] - a.data[2] * b.data[1] + result.data[1] = a.data[2] * b.data[0] - a.data[0] * b.data[2] + result.data[2] = a.data[0] * b.data[1] - a.data[1] * b.data[0] + return result + +def np_interp(x: t.CDouble, xp: ndarray[t.CDouble] | t.CPtr, fp: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + # 1D linear interpolation + if xp.size == 0: return t.CDouble(0.0) + if x <= xp.data[0]: return fp.data[0] + if x >= xp.data[xp.size - 1]: return fp.data[xp.size - 1] + i: t.CSizeT = 0 + while i < xp.size - 1: + if x >= xp.data[i] and x <= xp.data[i + 1]: + t_val: t.CDouble = (x - xp.data[i]) / (xp.data[i + 1] - xp.data[i]) + return fp.data[i] + t_val * (fp.data[i + 1] - fp.data[i]) + i += 1 + return fp.data[xp.size - 1] + +def prod(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + p: t.CDouble = t.CDouble(1.0) + i: t.CSizeT = 0 + while i < a.size: + p *= a.data[i] + i += 1 + return p + +def median(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + s: ndarray[t.CDouble] | t.CPtr = sort_arr(a) + if not s: return t.CDouble(0.0) + mid: t.CSizeT = a.size / 2 + if a.size % 2 == 1: + result: t.CDouble = s.data[mid] + else: + result = (s.data[mid - 1] + s.data[mid]) / t.CDouble(2.0) + s.delete() + return result + +def percentile(a: ndarray[t.CDouble] | t.CPtr, q: t.CDouble) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + s: ndarray[t.CDouble] | t.CPtr = sort_arr(a) + if not s: return t.CDouble(0.0) + idx: t.CDouble = q / t.CDouble(100.0) * t.CDouble(a.size - 1) + lo: t.CSizeT = t.CSizeT(vipermath.floor(idx)) + hi: t.CSizeT = t.CSizeT(vipermath.ceil(idx)) + frac: t.CDouble = idx - vipermath.floor(idx) + result: t.CDouble = s.data[lo] + frac * (s.data[hi] - s.data[lo]) + s.delete() + return result diff --git a/os/__init__.vp b/os/__init__.vp new file mode 100644 index 0000000..daf8635 --- /dev/null +++ b/os/__init__.vp @@ -0,0 +1,134 @@ +import t, c +from stdint import * +import platmacro +import memhub +import os.path +import os._win32 +import os._posix + + +# os package entry point +# Dispatches to _win32 or _posix backend based on platmacro.IS_WINDOWS +# os.path is for cross-platform pure string operations, can be used directly + +# Module-level global MBuddy pointer (initialized by the user in main) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# File/Directory Attribute Query +# ============================================================================= + +def exists(path: str) -> bool: + """Check if the file/directory exists""" + if platmacro.IS_WINDOWS: + return os._win32.exists(path) + return os._posix.exists(path) + + +def isdir(path: str) -> bool: + """Check if the path is a directory""" + if platmacro.IS_WINDOWS: + return os._win32.isdir(path) + return os._posix.isdir(path) + + +def isfile(path: str) -> bool: + """Check if the path is a regular file""" + if platmacro.IS_WINDOWS: + return os._win32.isfile(path) + return os._posix.isfile(path) + + +def getsize(path: str) -> t.CInt64T: + """Returns the file size (in bytes). Returns -1 on failure.""" + if platmacro.IS_WINDOWS: + return os._win32.getsize(path) + return os._posix.getsize(path) + + +# ============================================================================= +# Working Directory +# ============================================================================= + +def getcwd() -> str: + """Return the current working directory (memory allocated via _mbuddy)""" + if platmacro.IS_WINDOWS: + return os._win32.getcwd() + return os._posix.getcwd_impl() + + +def chdir(path: str) -> int: + """Switch the current working directory. Returns 0 if successful, -1 if it fails.""" + if platmacro.IS_WINDOWS: + return os._win32.chdir(path) + return os._posix.chdir_impl(path) + + +# ============================================================================= +# File/Directory Operations +# ============================================================================= + +def mkdir(path: str) -> int: + """Create a directory. Returns 0 on success, -1 on failure.""" + if platmacro.IS_WINDOWS: + return os._win32.mkdir(path) + return os._posix.mkdir_impl(path) + + +def remove(path: str) -> int: + """Delete the file. Returns 0 if successful, -1 if it fails.""" + if platmacro.IS_WINDOWS: + return os._win32.remove(path) + return os._posix.remove(path) + + +def rmdir(path: str) -> int: + """Delete empty directories. Returns 0 if successful, -1 if it fails.""" + if platmacro.IS_WINDOWS: + return os._win32.rmdir(path) + return os._posix.rmdir_impl(path) + + +def rename(old_path: str, new_path: str) -> int: + """Rename/move a file or directory. Returns 0 on success, -1 on failure.""" + if platmacro.IS_WINDOWS: + return os._win32.rename(old_path, new_path) + return os._posix.rename_impl(old_path, new_path) + + +def chmod(path: str, mode: int) -> int: + """Modify file permissions. Returns 0 on success, -1 on failure. + On Windows, only the read-only bit (S_IWUSR) is handled; + On POSIX, full permission bits are used.""" + if platmacro.IS_WINDOWS: + return os._win32.chmod(path, mode) + return os._posix.chmod_impl(path, mode) + + +# ============================================================================= +# Table of Contents Listing +# ============================================================================= + +def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: + """列举目录下的文件/子目录名。 + out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。 + 文件名通过 _mbuddy 分配内存。 + max_count 为 out_names 数组最大容量。 + 返回实际列举的条目数。失败返回 0。""" + if platmacro.IS_WINDOWS: + return os._win32.listdir(path, out_names, max_count) + return os._posix.listdir(path, out_names, max_count) + + +# ============================================================================= +# 命令执行 +# ============================================================================= + +def system(cmd: str) -> int: + """执行命令行命令(通过 C 运行时 system())。 + 命令输出直接到终端(继承父进程 stdout/stderr)。 + 返回命令的退出码(0 表示成功)。""" + if platmacro.IS_WINDOWS: + return os._win32.system(cmd) + return os._posix.system_impl(cmd) diff --git a/os/_posix.vp b/os/_posix.vp new file mode 100644 index 0000000..f5d9114 --- /dev/null +++ b/os/_posix.vp @@ -0,0 +1,190 @@ +import t, c +from stdint import * +import posix +import memhub +import stdlib + + +# POSIX 路径最大长度 +MAX_PATH_LEN: t.CDefine = 4096 + +# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# 文件/目录属性查询 +# ============================================================================= + +def _stat(path: str) -> posix.Stat | t.CPtr: + """调用 stat 并返回 Stat 结构体指针。失败返回 None。 + 注意:Stat 结构体通过 _mbuddy 分配,调用者负责释放。""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return None + return t.CPtr(c.Addr(st)) + + +def exists(path: str) -> bool: + """检查文件/目录是否存在""" + result: INT = posix.access(path, posix.F_OK) + if result == 0: + return True + return False + + +def isdir(path: str) -> bool: + """检查路径是否为目录""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return False + if posix.S_ISDIR(st.st_mode): + return True + return False + + +def isfile(path: str) -> bool: + """检查路径是否为普通文件""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return False + if posix.S_ISREG(st.st_mode): + return True + return False + + +def getsize(path: str) -> t.CInt64T: + """返回文件大小(字节)。失败返回 -1。""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return -1 + return st.st_size + + +# ============================================================================= +# 工作目录 +# ============================================================================= + +def getcwd_impl() -> str: + """返回当前工作目录(通过 _mbuddy 分配内存)""" + buf: bytes = _mbuddy.alloc(MAX_PATH_LEN) + if buf == None: return None + result: CHARPTR = posix.getcwd(buf, MAX_PATH_LEN) + if result == None: + return None + return str(buf) + + +def chdir_impl(path: str) -> int: + """切换当前工作目录。成功返回 0,失败返回 -1。""" + result: INT = posix.chdir(path) + if result != 0: + return -1 + return 0 + + +# ============================================================================= +# 文件/目录操作 +# ============================================================================= + +def mkdir_impl(path: str) -> int: + """创建目录。成功返回 0,失败返回 -1。 + 默认权限 0o755(rwxr-xr-x)。""" + result: INT = posix.mkdir(path, 0o755) + if result != 0: + return -1 + return 0 + + +def remove(path: str) -> int: + """删除文件。成功返回 0,失败返回 -1。""" + result: INT = posix.unlink(path) + if result != 0: + return -1 + return 0 + + +def rmdir_impl(path: str) -> int: + """删除空目录。成功返回 0,失败返回 -1。""" + result: INT = posix.rmdir(path) + if result != 0: + return -1 + return 0 + + +def rename_impl(old_path: str, new_path: str) -> int: + """重命名/移动文件或目录。成功返回 0,失败返回 -1。""" + result: INT = posix.rename(old_path, new_path) + if result != 0: + return -1 + return 0 + + +def chmod_impl(path: str, mode: int) -> int: + """修改文件权限。成功返回 0,失败返回 -1。 + mode 为 POSIX 权限位(如 0o755)。""" + result: INT = posix.chmod(path, posix.mode_t(mode)) + if result != 0: + return -1 + return 0 + + +# ============================================================================= +# 目录列举(opendir / readdir / closedir) +# ============================================================================= + +def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: + """列举目录下的文件/子目录名。 + out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。 + 文件名通过 _mbuddy 分配内存。 + max_count 为 out_names 数组最大容量。 + 返回实际列举的条目数。失败返回 0。""" + dirp: posix.DIR | t.CPtr = posix.opendir(path) + if dirp == None: + return 0 + + count: ULONG = 0 + while count < max_count: + entry: posix.Dirent | t.CPtr = posix.readdir(dirp) + if entry == None: + break + + # 读取 d_name 字段 + name: str = entry.d_name + if name[0] == '.': + if name[1] == 0: + # "." + continue + if name[1] == '.' and name[2] == 0: + # ".." + continue + + # 复制文件名到新分配的内存 + name_len: t.CSizeT = len(name) + name_buf: bytes = _mbuddy.alloc(name_len + 1) + if name_buf == None: break + i: t.CSizeT = 0 + for ch in name: + name_buf[i] = ch + i += 1 + name_buf[name_len] = 0 + out_names[count] = str(name_buf) + count += 1 + + posix.closedir(dirp) + return count + + +# ============================================================================= +# 命令执行 +# ============================================================================= + +def system_impl(cmd: str) -> int: + """执行命令行命令(通过 C 运行时 system())。 + 命令输出直接到子进程的终端(继承父进程 stdout/stderr)。 + 返回命令的退出码(0 表示成功)。""" + return stdlib.system(cmd) diff --git a/os/_win32.vp b/os/_win32.vp new file mode 100644 index 0000000..6292e53 --- /dev/null +++ b/os/_win32.vp @@ -0,0 +1,234 @@ +import t, c +from stdint import * +import w32.win32base +import w32.win32file +import memhub +import stdlib + + +# Windows 路径最大长度 +MAX_PATH_LEN: t.CDefine = 260 + +# INVALID_FILE_ATTRIBUTES +INVALID_FILE_ATTRIBUTES: t.CDefine = 0xFFFFFFFF + +# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# 文件/目录属性查询 +# ============================================================================= + +def _get_attrs(path: str) -> ULONG: + """获取文件属性。失败返回 INVALID_FILE_ATTRIBUTES。""" + return w32.win32file.GetFileAttributesA(path) + + +def exists(path: str) -> bool: + """检查文件/目录是否存在""" + attrs: ULONG = _get_attrs(path) + if attrs == INVALID_FILE_ATTRIBUTES: + return False + return True + + +def isdir(path: str) -> bool: + """检查路径是否为目录""" + attrs: ULONG = _get_attrs(path) + if attrs == INVALID_FILE_ATTRIBUTES: + return False + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + return True + return False + + +def isfile(path: str) -> bool: + """检查路径是否为普通文件""" + attrs: ULONG = _get_attrs(path) + if attrs == INVALID_FILE_ATTRIBUTES: + return False + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + return False + return True + + +def getsize(path: str) -> t.CInt64T: + """返回文件大小(字节)。失败返回 -1。""" + handle: w32.win32base.HANDLE = w32.win32file.CreateFileA( + path, w32.win32file.GENERIC_READ, w32.win32file.FILE_SHARE_READ, + t.CPtr(0), w32.win32file.OPEN_EXISTING, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0) + ) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return -1 + li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER() + result: BOOL = w32.win32file.GetFileSizeEx(handle, t.CPtr(c.Addr(li))) + w32.win32base.CloseHandle(handle) + if result == 0: + return -1 + return li.QuadPart + + +# ============================================================================= +# 工作目录 +# ============================================================================= + +def getcwd() -> str: + """返回当前工作目录(通过 _mbuddy 分配内存)""" + buf: bytes = _mbuddy.alloc(MAX_PATH_LEN + 1) + if buf == None: return None + length: ULONG = w32.win32file.GetCurrentDirectoryA(MAX_PATH_LEN + 1, buf) + if length == 0: + return None + if length > MAX_PATH_LEN: + # 缓冲区不够,重新分配 + buf2: bytes = _mbuddy.alloc(length + 1) + if buf2 == None: return None + w32.win32file.GetCurrentDirectoryA(length + 1, buf2) + buf2[length] = 0 + return str(buf2) + buf[length] = 0 + return str(buf) + + +def chdir(path: str) -> int: + """切换当前工作目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.SetCurrentDirectoryA(path) + if result == 0: + return -1 + return 0 + + +# ============================================================================= +# 文件/目录操作 +# ============================================================================= + +def mkdir(path: str) -> int: + """创建目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.CreateDirectoryA(path, t.CPtr(0)) + if result == 0: + return -1 + return 0 + + +def remove(path: str) -> int: + """删除文件。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.DeleteFileA(path) + if result == 0: + return -1 + return 0 + + +def rmdir(path: str) -> int: + """删除空目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.RemoveDirectoryA(path) + if result == 0: + return -1 + return 0 + + +def rename(old_path: str, new_path: str) -> int: + """重命名/移动文件或目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.MoveFileExA( + old_path, new_path, + w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED + ) + if result == 0: + return -1 + return 0 + + +def chmod(path: str, mode: int) -> int: + """修改文件属性(Windows 简化版:只处理只读位)。 + mode 的 S_IWUSR 位(0o200)为 0 时设为只读,为 1 时设为可写。 + 成功返回 0,失败返回 -1。""" + if (mode & 0o200) != 0: + # 可写:清除只读属性 + result: BOOL = w32.win32file.SetFileAttributesA( + path, w32.win32file.FILE_ATTRIBUTE_NORMAL + ) + else: + # 只读:设置只读属性 + result: BOOL = w32.win32file.SetFileAttributesA( + path, w32.win32file.FILE_ATTRIBUTE_READONLY + ) + if result == 0: + return -1 + return 0 + + +# ============================================================================= +# 目录列举(FindFirstFile / FindNextFile) +# ============================================================================= + +def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: + """列举目录下的文件/子目录名。 + out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。 + 文件名通过 _mbuddy 分配内存。 + max_count 为 out_names 数组最大容量。 + 返回实际列举的条目数。失败返回 0。""" + # 构造搜索模式:path\* + path_len: t.CSizeT = len(path) + pattern: bytes = _mbuddy.alloc(path_len + 3) + if pattern == None: return 0 + i: t.CSizeT = 0 + for ch in path: + pattern[i] = ch + i += 1 + # 添加 \* 后缀 + if path[path_len - 1] != '\\' and path[path_len - 1] != '/': + pattern[i] = '\\' + i += 1 + pattern[i] = '*' + i += 1 + pattern[i] = 0 + + find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA() + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data))) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return 0 + + count: ULONG = 0 + while count < max_count: + # 跳过 . 和 .. + name: str = find_data.cFileName + if name[0] == '.': + if name[1] == 0: + # "." + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + break + continue + if name[1] == '.' and name[2] == 0: + # ".." + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + break + continue + + # 复制文件名到新分配的内存 + name_len: t.CSizeT = len(name) + name_buf: bytes = _mbuddy.alloc(name_len + 1) + if name_buf == None: break + j: t.CSizeT = 0 + for ch in name: + name_buf[j] = ch + j += 1 + name_buf[name_len] = 0 + out_names[count] = str(name_buf) + count += 1 + + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + break + + w32.win32file.FindClose(handle) + return count + + +# ============================================================================= +# 命令执行 +# ============================================================================= + +def system(cmd: str) -> int: + """执行命令行命令(通过 C 运行时 system())。 + 命令输出直接到子进程的终端(继承父进程 stdout/stderr)。 + 返回命令的退出码(0 表示成功)。""" + return stdlib.system(cmd) diff --git a/os/path.vp b/os/path.vp new file mode 100644 index 0000000..af38b91 --- /dev/null +++ b/os/path.vp @@ -0,0 +1,316 @@ +import t, c +from stdint import * +import string +import memhub +import platmacro + + +# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# 路径分隔符 +# ============================================================================= + +def sep() -> t.CChar: + """返回当前平台的路径分隔符(Windows: \\,POSIX: /)""" + if platmacro.IS_WINDOWS: + return '\\' + return '/' + + +def _is_sep(ch: t.CChar) -> bool: + """判断字符是否为路径分隔符(/ 或 \\,跨平台识别)""" + return ch == '/' or ch == '\\' + + +# ============================================================================= +# 内部辅助函数 +# ============================================================================= + +def _dup_str(s: str) -> str: + """复制字符串(通过全局 MBuddy 分配内存)""" + if s == None: return None + length: t.CSizeT = len(s) + buf: bytes = _mbuddy.alloc(length + 1) + if buf == None: return None + i: t.CSizeT = 0 + for ch in s: + buf[i] = ch + i += 1 + buf[length] = 0 + return str(buf) + + +def _substr(s: str, start: t.CSizeT, end: t.CSizeT) -> str: + """提取子串 s[start:end](通过全局 MBuddy 分配内存)""" + if s == None: return None + if start >= end: return _dup_str("") + result_len: t.CSizeT = end - start + buf: bytes = _mbuddy.alloc(result_len + 1) + if buf == None: return None + i: t.CSizeT = 0 + k: t.CSizeT = start + while k < end: + buf[i] = s[k] + i += 1 + k += 1 + buf[i] = 0 + return str(buf) + + +# ============================================================================= +# 路径判断 +# ============================================================================= + +def isabs(path: str) -> bool: + """判断路径是否为绝对路径。 + POSIX: 以 / 开头。 + Windows: 以 \\ 开头(UNC)或 X:\\ / X:/ 开头(盘符)。""" + if path == None: return False + if path[0] == 0: return False + if path[0] == '/' or path[0] == '\\': return True + if platmacro.IS_WINDOWS: + # 检查 X:\ 或 X:/ 模式 + c0: t.CChar = path[0] + if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'): + if path[1] == ':': + if path[2] == '\\' or path[2] == '/': + return True + return False + + +# ============================================================================= +# 路径拼接与分割 +# ============================================================================= + +def join(path1: str, path2: str) -> str: + """拼接两个路径。如果 path2 是绝对路径,返回 path2 的副本。""" + if path1 == None or path1[0] == 0: + return _dup_str(path2) + if path2 == None or path2[0] == 0: + return _dup_str(path1) + if isabs(path2): + return _dup_str(path2) + + len1: t.CSizeT = len(path1) + len2: t.CSizeT = len(path2) + + # 检查 path1 是否以分隔符结尾 + need_sep: bool = True + if _is_sep(path1[len1 - 1]): + need_sep = False + + total: t.CSizeT = len1 + len2 + 1 + if need_sep: + total += 1 + + buf: bytes = _mbuddy.alloc(total) + if buf == None: return None + + # 复制 path1 + i: t.CSizeT = 0 + for ch in path1: + buf[i] = ch + i += 1 + + # 添加分隔符 + if need_sep: + buf[i] = sep() + i += 1 + + # 复制 path2 + for ch in path2: + buf[i] = ch + i += 1 + + buf[i] = 0 + return str(buf) + + +def basename(path: str) -> str: + """返回路径的文件名部分(最后一个分隔符之后的内容)""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找分隔符 + i: t.CSizeT = length + while i > 0: + i -= 1 + if _is_sep(path[i]): + return _substr(path, i + 1, length) + + # 没有分隔符,返回整个路径的副本 + return _dup_str(path) + + +def dirname(path: str) -> str: + """返回路径的目录部分(最后一个分隔符之前的内容)""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找分隔符 + i: t.CSizeT = length + while i > 0: + i -= 1 + if _is_sep(path[i]): + if i == 0: + # 路径以分隔符开头,返回根目录 + return _dup_str("/") + return _substr(path, 0, i) + + # 没有分隔符,返回空字符串 + return _dup_str("") + + +# ============================================================================= +# 扩展名处理 +# ============================================================================= + +def splitext_name(path: str) -> str: + """返回路径去除扩展名后的主名部分。 + 扩展名从最后一个 '.' 开始(该 '.' 不能是路径最后一个组件的第一个字符)。""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找 '.',遇到分隔符停止 + i: t.CSizeT = length + while i > 0: + i -= 1 + if path[i] == '.': + return _substr(path, 0, i) + if _is_sep(path[i]): + break + + # 没有扩展名,返回整个路径的副本 + return _dup_str(path) + + +def splitext_ext(path: str) -> str: + """返回路径的扩展名部分(包含 '.')。无扩展名时返回空字符串。""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找 '.',遇到分隔符停止 + i: t.CSizeT = length + while i > 0: + i -= 1 + if path[i] == '.': + return _substr(path, i, length) + if _is_sep(path[i]): + break + + # 没有扩展名,返回空字符串 + return _dup_str("") + + +# ============================================================================= +# 路径规范化 +# ============================================================================= + +def normpath(path: str) -> str: + """规范化路径:统一分隔符、消除多余的 . 和 .. 组件、合并连续分隔符。 + 注意:不解析符号链接,不调用系统 API。""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str(".") + + # 分配输出缓冲区(最坏情况:长度不变 + 前缀 /) + buf: bytes = _mbuddy.alloc(length + 2) + if buf == None: return None + + out_pos: t.CSizeT = 0 + i: t.CSizeT = 0 + s: str = sep() + + # 处理绝对路径前缀 + is_absolute: bool = False + if _is_sep(path[0]): + is_absolute = True + buf[out_pos] = s + out_pos += 1 + i = 1 + + # Windows 盘符前缀(X:\ 或 X:/) + drive_prefix_len: t.CSizeT = 0 + if platmacro.IS_WINDOWS: + if length >= 3: + c0: t.CChar = path[0] + if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'): + if path[1] == ':': + if _is_sep(path[2]): + buf[out_pos] = path[0] + out_pos += 1 + buf[out_pos] = ':' + out_pos += 1 + buf[out_pos] = s + out_pos += 1 + drive_prefix_len = 3 + i = 3 + is_absolute = True + + # 逐组件处理 + while i < length: + # 跳过连续分隔符 + while i < length and _is_sep(path[i]): + i += 1 + if i >= length: + break + + # 提取组件 + comp_start: t.CSizeT = i + while i < length and not _is_sep(path[i]): + i += 1 + comp_len: t.CSizeT = i - comp_start + + # 处理 "." 组件:跳过 + if comp_len == 1 and path[comp_start] == '.': + continue + + # 处理 ".." 组件:回退一级 + if comp_len == 2 and path[comp_start] == '.' and path[comp_start + 1] == '.': + if out_pos > drive_prefix_len: + # 回退到上一个分隔符前 + out_pos -= 1 + while out_pos > drive_prefix_len and not _is_sep(buf[out_pos - 1]): + out_pos -= 1 + # 如果回退到了根目录前缀,不删除前缀 + if out_pos == drive_prefix_len and is_absolute: + out_pos = drive_prefix_len + if drive_prefix_len == 0: + # POSIX 根:保留 / + buf[out_pos] = s + out_pos += 1 + continue + + # 普通组件:复制到输出 + if out_pos > drive_prefix_len and not (drive_prefix_len == 0 and out_pos == 1 and is_absolute): + buf[out_pos] = s + out_pos += 1 + elif out_pos == 0 and not is_absolute: + pass # 第一个组件,不需要前导分隔符 + elif is_absolute and out_pos == drive_prefix_len: + # 已经有前导分隔符,不重复添加 + pass + else: + buf[out_pos] = s + out_pos += 1 + + j: t.CSizeT = comp_start + while j < comp_start + comp_len: + buf[out_pos] = path[j] + out_pos += 1 + j += 1 + + # 处理空结果 + if out_pos == 0: + buf[out_pos] = '.' + out_pos += 1 + + buf[out_pos] = 0 + return str(buf) diff --git a/platmacro.vp b/platmacro.vp new file mode 100644 index 0000000..695f918 --- /dev/null +++ b/platmacro.vp @@ -0,0 +1,57 @@ +import t, c + + +IS_WINDOWS: t.CDefine = 1 +IS_WIN64: t.CDefine = 1 +IS_X86_64: t.CDefine = 1 +IS_LP64: t.CDefine = 1 +IS_LITTLE_ENDIAN: t.CDefine = 1 + +IS_LINUX: t.CDefine = 0 +IS_MACOS: t.CDefine = 0 +IS_ARM64: t.CDefine = 0 +IS_BIG_ENDIAN: t.CDefine = 0 +IS_ILP32: t.CDefine = 0 + +PTR_SIZE: t.CDefine = 8 +INT_SIZE: t.CDefine = 4 +LONG_SIZE: t.CDefine = 4 +WORD_SIZE: t.CDefine = 8 + +CACHE_LINE_SIZE: t.CDefine = 64 +PAGE_SIZE: t.CDefine = 4096 +STACK_ALIGN: t.CDefine = 16 +MAX_PATH_LEN: t.CDefine = 260 + +PLATFORM_NAME: t.CDefine = 1 +ARCH_NAME: t.CDefine = 1 + +WINVER: t.CDefine = 0x0A00 +_WIN32_WINNT: t.CDefine = 0x0A00 +NTDDI_VERSION: t.CDefine = 0x0A000006 + +HAS_SSE2: t.CDefine = 1 +HAS_AVX: t.CDefine = 1 +HAS_AVX2: t.CDefine = 1 +HAS_FMA: t.CDefine = 1 +HAS_NEON: t.CDefine = 0 + +ALIGNOF_INT: t.CDefine = 4 +ALIGNOF_LONG: t.CDefine = 4 +ALIGNOF_PTR: t.CDefine = 8 +ALIGNOF_DOUBLE: t.CDefine = 8 +ALIGNOF_LONG_DOUBLE: t.CDefine = 16 + +SIZEOF_SHORT: t.CDefine = 2 +SIZEOF_INT: t.CDefine = 4 +SIZEOF_LONG: t.CDefine = 4 +SIZEOF_LONG_LONG: t.CDefine = 8 +SIZEOF_FLOAT: t.CDefine = 4 +SIZEOF_DOUBLE: t.CDefine = 8 +SIZEOF_LONG_DOUBLE: t.CDefine = 16 +SIZEOF_POINTER: t.CDefine = 8 +SIZEOF_SIZE_T: t.CDefine = 8 +SIZEOF_PTRDIFF_T: t.CDefine = 8 + +BYTE_ORDER_LE: t.CDefine = 1 +BYTE_ORDER_BE: t.CDefine = 0 diff --git a/posix.vp b/posix.vp new file mode 100644 index 0000000..d98e7ac --- /dev/null +++ b/posix.vp @@ -0,0 +1,265 @@ +import t, c +from stdint import * + + +# ============================================================================= +# POSIX Type Alias +# Note: ssize_t has already been defined as t.CPtrDiffT in stdint.py, so we won’t repeat it here. +# ============================================================================= +DIR: t.CTypedef = t.CVoid | t.CPtr # Opaque directory stream handle +mode_t: t.CTypedef = t.CUInt32T # File mode/permission bits +pid_t: t.CTypedef = t.CInt32T # Process ID +off_t: t.CTypedef = t.CInt64T # File offset (Linux x86_64) +dev_t: t.CTypedef = t.CUInt64T # Device number +ino_t: t.CTypedef = t.CUInt64T # inode number +nlink_t: t.CTypedef = t.CUInt64T # Hard link count +uid_t: t.CTypedef = t.CUInt32T # User ID +gid_t: t.CTypedef = t.CUInt32T # Group ID +blksize_t: t.CTypedef = t.CInt64T # File I/O block size +blkcnt_t: t.CTypedef = t.CInt64T # Allocated block count +time_t: t.CTypedef = t.CInt64T # Calendar time seconds + + +# ============================================================================= +# open() Flags +# ============================================================================= +O_RDONLY: t.CDefine = 0 +O_WRONLY: t.CDefine = 1 +O_RDWR: t.CDefine = 2 +O_CREAT: t.CDefine = 0o100 +O_EXCL: t.CDefine = 0o200 +O_TRUNC: t.CDefine = 0o1000 +O_APPEND: t.CDefine = 0o2000 +O_NONBLOCK: t.CDefine = 0o4000 +O_CLOEXEC: t.CDefine = 0o2000000 + + +# ============================================================================= +# access() Test Flags +# ============================================================================= +F_OK: t.CDefine = 0 # File exists +R_OK: t.CDefine = 4 # Read permission +W_OK: t.CDefine = 2 # Write permission +X_OK: t.CDefine = 1 # Execute permission + + +# ============================================================================= +# stat struct st_mode Mask and Type Bits +# ============================================================================= +S_IFMT: t.CDefine = 0o170000 # Type mask bits +S_IFSOCK: t.CDefine = 0o140000 # Socket +S_IFLNK: t.CDefine = 0o120000 # Symbolic link +S_IFREG: t.CDefine = 0o100000 # Regular file +S_IFBLK: t.CDefine = 0o060000 # Block device +S_IFDIR: t.CDefine = 0o040000 # Directory +S_IFCHR: t.CDefine = 0o020000 # Character device +S_IFIFO: t.CDefine = 0o010000 # FIFO/pipe + +# Permission Bits +S_ISUID: t.CDefine = 0o4000 # Set-user-ID +S_ISGID: t.CDefine = 0o2000 # Set-group-ID +S_ISVTX: t.CDefine = 0o1000 # Sticky bit +S_IRWXU: t.CDefine = 0o700 # Read/write/execute permission +S_IRUSR: t.CDefine = 0o400 # User read permission +S_IWUSR: t.CDefine = 0o200 # User write permission +S_IXUSR: t.CDefine = 0o100 # User execute permission +S_IRWXG: t.CDefine = 0o070 # Read/write/execute permission +S_IRGRP: t.CDefine = 0o040 # Read permission +S_IWGRP: t.CDefine = 0o020 # Write +S_IXGRP: t.CDefine = 0o010 # Execute +S_IRWXO: t.CDefine = 0o007 # Read/write/execute permission +S_IROTH: t.CDefine = 0o004 # Other read permission +S_IWOTH: t.CDefine = 0o002 # Other write permission +S_IXOTH: t.CDefine = 0o001 # Other execute permission + + +# ============================================================================= +# lseek() whence values +# ============================================================================= +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 + + +# ============================================================================= +# Path/name length limits +# ============================================================================= +PATH_MAX: t.CDefine = 4096 +NAME_MAX: t.CDefine = 255 + + +# ============================================================================= +# sysconf() parameters +# ============================================================================= +_SC_NPROCESSORS_ONLN: t.CDefine = 84 +_SC_PAGESIZE: t.CDefine = 30 +_SC_CLK_TCK: t.CDefine = 2 + + +# ============================================================================= +# dirent struct d_type values +# ============================================================================= +DT_UNKNOWN: t.CDefine = 0 +DT_FIFO: t.CDefine = 1 +DT_CHR: t.CDefine = 2 +DT_DIR: t.CDefine = 4 +DT_BLK: t.CDefine = 6 +DT_REG: t.CDefine = 8 +DT_LNK: t.CDefine = 10 +DT_SOCK: t.CDefine = 12 +DT_WHT: t.CDefine = 14 + + +# ============================================================================= +# waitpid() options +# ============================================================================= +WNOHANG: t.CDefine = 1 +WUNTRACED: t.CDefine = 2 +WCONTINUED: t.CDefine = 8 + + +# ============================================================================= +# Struct: Linux x86_64 Layout +# ============================================================================= + +# struct stat (144 bytes, Linux x86_64 glibc layout) +# Note: st_atim/st_mtim/st_ctim in C are struct timespec { tv_sec; tv_nsec; } +# Here split into _sec/_nsec two LONGLONG fields to maintain binary compatibility +class Stat(): + st_dev: dev_t # @ 0 + st_ino: ino_t # @ 8 + st_nlink: nlink_t # @ 16 + st_mode: mode_t # @ 24 + st_uid: uid_t # @ 28 + st_gid: gid_t # @ 32 + __pad0: INT # @ 36 + st_rdev: dev_t # @ 40 + st_size: off_t # @ 48 + st_blksize: blksize_t # @ 56 + st_blocks: blkcnt_t # @ 64 + st_atim_sec: time_t # @ 72 + st_atim_nsec: LONGLONG # @ 80 + st_mtim_sec: time_t # @ 88 + st_mtim_nsec: LONGLONG # @ 96 + st_ctim_sec: time_t # @ 104 + st_ctim_nsec: LONGLONG # @ 112 + __unused0: LONGLONG # @ 120 + __unused1: LONGLONG # @ 128 + __unused2: LONGLONG # @ 136 + + +# struct dirent (Linux x86_64, d_name is char[256]) +# Note: d_name is actually a fixed-length char[256], TransPyC uses CHARPTR as a placeholder (8 bytes). +# Users usually access it via the read-only pointer returned by readdir, not by directly allocating a Dirent structure. +class Dirent(): + d_ino: ino_t # @ 0 + d_off: off_t # @ 8 + d_reclen: USHORT # @ 16 + d_type: BYTE # @ 18 + d_name: CHARPTR # @ 19 (actually char[256], this is a placeholder) + + +# ============================================================================= +# File operations (10) +# ============================================================================= +def open(path: t.CConst | str, oflag: INT, *args) -> INT | t.State: pass +def close(fd: INT) -> INT | t.State: pass +def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t | t.State: pass +def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t | t.State: pass +def lseek(fd: INT, offset: off_t, whence: INT) -> off_t | t.State: pass +def unlink(path: t.CConst | str) -> INT | t.State: pass +def access(path: t.CConst | str, amode: INT) -> INT | t.State: pass +def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR | t.State: pass +def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT | t.State: pass +def chmod(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass + + +# ============================================================================= +# stat series (2) +# ============================================================================= +def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT | t.State: pass +def fstat(fd: INT, buf: Stat | t.CPtr) -> INT | t.State: pass + + +# ============================================================================= +# Directory operations (6) +# ============================================================================= +def opendir(name: t.CConst | str) -> DIR | t.CPtr | t.State: pass +def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr | t.State: pass +def closedir(dirp: DIR | t.CPtr) -> INT | t.State: pass +def mkdir(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass +def rmdir(path: t.CConst | str) -> INT | t.State: pass +def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR | t.State: pass +def chdir(path: t.CConst | str) -> INT | t.State: pass + + +# ============================================================================= +# Process operations (8) +# ============================================================================= +def fork() -> pid_t | t.State: pass +def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass +def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass +def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t | t.State: pass +def pipe(fds: INT | t.CPtr) -> INT | t.State: pass +def dup2(oldfd: INT, newfd: INT) -> INT | t.State: pass +def _exit(status: INT) -> t.CVoid | t.State: pass +def getpid() -> pid_t | t.State: pass + + +# ============================================================================= +# Environment operations (4) +# ============================================================================= +def getenv(name: t.CConst | str) -> CHARPTR | t.State: pass +def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT | t.State: pass +def sysconf(name: INT) -> LONG | t.State: pass +def isatty(fd: INT) -> INT | t.State: pass + + +# ============================================================================= +# Inline macros (C macros, implemented as normal functions, not marked as t.CExtern) +# ============================================================================= + +# st_mode type determination +def S_ISREG(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFREG + + +def S_ISDIR(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFDIR + + +def S_ISLNK(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFLNK + + +def S_ISCHR(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFCHR + + +def S_ISBLK(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFBLK + + +def S_ISFIFO(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFIFO + + +def S_ISSOCK(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFSOCK + + +# waitpid status parsing +def WIFEXITED(status: INT) -> bool: + return (status & 0x7F) == 0 + + +def WEXITSTATUS(status: INT) -> INT: + return (status >> 8) & 0xFF + + +def WIFSIGNALED(status: INT) -> bool: + return ((status & 0x7F) != 0) and ((status & 0x7F) != 0x7F) + + +def WTERMSIG(status: INT) -> INT: + return status & 0x7F diff --git a/requests.vp b/requests.vp new file mode 100644 index 0000000..ba9f72e --- /dev/null +++ b/requests.vp @@ -0,0 +1,360 @@ +import t, c +from stdint import * +import string +import socket +import memhub +import stdio + + +# ============================================================ +# requests.py — HTTP client library (Python original style) +# +# Usage: +# requests._mbuddy = my_mbuddy +# resp = requests.get("http://example.com/path") +# if resp is not None: +# print(resp.status_code) +# print(resp.text) +# requests.release(resp) +# ============================================================ + +# Module-level global MBuddy pointer (assigned by the user in main) +_mbuddy: memhub.MemBuddy | t.CPtr + +# Socket initialization flag +_socket_ready: bool = False + +HTTP_PORT: t.CDefine = 80 +HTTP_BUFSIZ: t.CDefine = 4096 + + +# ============================================================ +# Response — HTTP response object +# ============================================================ + +class Response: + """HTTP response object, similar to how Python's requests.Response works. + + Allocated from _mbuddy, call release(resp) to free it after use. + """ + status_code: INT # HTTP status code (e.g., 200, 404) + text: str # Response body text (points into _raw_buf) + body_len: INT # Response body length + _raw_buf: str # Raw buffer pointer + + +# ============================================================ +# Internal auxiliary functions +# ============================================================ + +def _EnsureSocketInit() -> INT: + """Ensure Socket library is initialized (idempotent).""" + global _socket_ready + if _socket_ready: return 0 + result: INT = socket.SocketInit() + if result == 0: + _socket_ready = True + return result + + +def _AllocResponse() -> Response | t.CPtr: + """Allocate Response struct from _mbuddy and initialize it in-place.""" + if _mbuddy is None: return None + resp: Response | t.CPtr = _mbuddy.alloc(Response.__sizeof__()) + if resp is None: return None + resp.status_code = 0 + resp.text = None + resp.body_len = 0 + resp._raw_buf = None + return resp + + +def _ParseUrl(url: str, host_buf: str, host_size: INT, path_buf: str, path_size: INT, port: INT | t.CPtr) -> INT: + """Parse URL and extract host, port, and path.""" + if url is None: return -1 + if host_buf is None or path_buf is None or port is None: return -1 + + p: str = url + + # Skip "http://" + if string.strncmp(p, "http://", 7) == 0: + p += 7 + + # Parse host + host_start: str = p + host_len: INT = 0 + while p[0] != '\0' and p[0] != ':' and p[0] != '/': + host_len += 1 + p += 1 + + if host_len == 0 or host_len >= host_size: return -1 + string.strncpy(host_buf, host_start, host_len) + host_buf[host_len] = 0 + + # Parse port + if p[0] == ':': + p += 1 + port_val: INT = 0 + while p[0] >= '0' and p[0] <= '9': + port_val = port_val * 10 + INT(p[0] - '0') + p += 1 + c.DerefAs(port, port_val) + else: + c.DerefAs(port, HTTP_PORT) + + # Parse path + if p[0] == '/': + path_start: str = p + path_len: INT = 0 + while p[0] != '\0': + path_len += 1 + p += 1 + if path_len >= path_size: return -1 + string.strncpy(path_buf, path_start, path_len) + path_buf[path_len] = 0 + else: + if path_size < 2: return -1 + path_buf[0] = '/' + path_buf[1] = 0 + + return 0 + + +def _ParseStatusLine(resp_text: str, out_code: INT | t.CPtr) -> INT: + """Parse HTTP status line and extract status code.""" + if resp_text is None or out_code is None: return -1 + + p: str = resp_text + + # Skip "HTTP/x.x " + while p[0] != '\0' and p[0] != ' ': + p += 1 + if p[0] == ' ': p += 1 + + # Parse status code + code: INT = 0 + while p[0] >= '0' and p[0] <= '9': + code = code * 10 + INT(p[0] - '0') + p += 1 + + c.DerefAs(out_code, code) + + # Find \n + while p[0] != '\0' and p[0] != '\n': + p += 1 + if p[0] == '\n': p += 1 + + return INT(t.CUInt64T(p) - t.CUInt64T(resp_text)) + + +def _FindBodyStart(resp_text: str, resp_len: INT) -> INT: + """Find the start of the HTTP response body (after rnrn).""" + if resp_text is None: return -1 + + end_of_headers: str = string.strstr(resp_text, "\r\n\r\n") + if end_of_headers is None: + end_of_headers = string.strstr(resp_text, "\n\n") + if end_of_headers is None: + return -1 + return INT(t.CUInt64T(end_of_headers) - t.CUInt64T(resp_text)) + 2 + + return INT(t.CUInt64T(end_of_headers) - t.CUInt64T(resp_text)) + 4 + + +# ============================================================ +# 公共 API +# ============================================================ + +def get(url: str) -> Response | t.CPtr: + """HTTP GET request. + + Args: + url: Full URL (e.g., "http://example.com/path") + Returns: + Pointer to a Response object (allocated from _mbuddy), returns None on failure. + """ + if _mbuddy is None: return None + + resp: Response | t.CPtr = _AllocResponse() + if resp is None: return None + + if _EnsureSocketInit() != 0: + release(resp) + return None + + # Parse URL + host_buf: t.CArray[t.CChar, 256] + path_buf: t.CArray[t.CChar, 1024] + port: INT = 0 + + if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: + release(resp) + return None + + # Create Socket + sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) + if sock.fd == socket.INVALID_SOCKET: + release(resp) + return None + + if sock.connect(host_buf, port) != 0: + sock.close() + release(resp) + return None + + # Build HTTP request + req_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if req_buf is None: + sock.close() + release(resp) + return None + + stdio.snprintf(req_buf, HTTP_BUFSIZ, + "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", + path_buf, host_buf) + + req_len: INT = INT(string.strlen(req_buf)) + sent: INT = sock.send(req_buf, req_len) + _mbuddy.free(req_buf) + + if sent <= 0: + sock.close() + release(resp) + return None + + # Receive response body + resp_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if resp_buf is None: + sock.close() + release(resp) + return None + + total: INT = 0 + while total < HTTP_BUFSIZ - 1: + n: INT = sock.recv(resp_buf + total, HTTP_BUFSIZ - 1 - total) + if n <= 0: break + total += n + + resp_buf[total] = 0 + sock.close() + + resp._raw_buf = resp_buf + + # Parse status line + _ParseStatusLine(resp_buf, c.Addr(resp.status_code)) + + # Find body start + body_offset: INT = _FindBodyStart(resp_buf, total) + if body_offset < 0 or body_offset >= total: + resp.text = None + resp.body_len = 0 + else: + resp.text = resp_buf + body_offset + resp.body_len = total - body_offset + + return resp + + +def post(url: str, data: str = None, content_type: str = "application/x-www-form-urlencoded") -> Response | t.CPtr: + """HTTP POST request. + + Args: + url: Full URL + data: Request body data + content_type: Content-Type header (default is "application/x-www-form-urlencoded") + Returns: + Pointer to Response object (allocated from _mbuddy), returns None on failure. + """ + if _mbuddy is None: return None + + resp: Response | t.CPtr = _AllocResponse() + if resp is None: return None + + if _EnsureSocketInit() != 0: + release(resp) + return None + + # Parse URL + host_buf: t.CArray[t.CChar, 256] + path_buf: t.CArray[t.CChar, 1024] + port: INT = 0 + + if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: + release(resp) + return None + + body_len: INT = INT(string.strlen(data)) if data is not None else 0 + ct: str = content_type if content_type is not None else "application/x-www-form-urlencoded" + + # Create Socket + sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) + if sock.fd == socket.INVALID_SOCKET: + release(resp) + return None + + if sock.connect(host_buf, port) != 0: + sock.close() + release(resp) + return None + + # Build HTTP request + req_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if req_buf is None: + sock.close() + release(resp) + return None + + stdio.snprintf(req_buf, HTTP_BUFSIZ, + "POST %s HTTP/1.1\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\nConnection: close\r\n\r\n", + path_buf, host_buf, ct, body_len) + + hdr_len: INT = INT(string.strlen(req_buf)) + + # Send headers + body + sent: INT = sock.send(req_buf, hdr_len) + if sent > 0 and body_len > 0 and data is not None: + sock.send(data, body_len) + + _mbuddy.free(req_buf) + + # Receive response body + resp_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if resp_buf is None: + sock.close() + release(resp) + return None + + total: INT = 0 + while total < HTTP_BUFSIZ - 1: + n: INT = sock.recv(resp_buf + total, HTTP_BUFSIZ - 1 - total) + if n <= 0: break + total += n + + resp_buf[total] = 0 + sock.close() + + resp._raw_buf = resp_buf + + _ParseStatusLine(resp_buf, c.Addr(resp.status_code)) + body_offset: INT = _FindBodyStart(resp_buf, total) + if body_offset < 0 or body_offset >= total: + resp.text = None + resp.body_len = 0 + else: + resp.text = resp_buf + body_offset + resp.body_len = total - body_offset + + return resp + + +def release(resp: Response | t.CPtr): + """Release Response object and its internal buffers. + + Args: + resp: The Response object to release + """ + if resp is None: return + if _mbuddy is None: return + if resp._raw_buf is not None: + _mbuddy.free(resp._raw_buf) + _mbuddy.free(t.CVoid(t.CUInt64T(resp), t.CPtr)) diff --git a/rwlock.vp b/rwlock.vp new file mode 100644 index 0000000..3d0ae58 --- /dev/null +++ b/rwlock.vp @@ -0,0 +1,46 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import ( + InitializeSRWLock, + AcquireSRWLockExclusive, ReleaseSRWLockExclusive, + AcquireSRWLockShared, ReleaseSRWLockShared +) + + +@t.Object +class RWLock: + """SRWLock-based read-write lock that supports multiple readers and single writer, but does not support recursion. + + Usage: + rwlock: RWLock = RWLock() + rwlock.acquire_read() + # ... read shared data + rwlock.release_read() + rwlock.acquire_write() + # ... modify shared data + rwlock.release_write() + """ + lock: VOIDPTR + + def __init__(self): + InitializeSRWLock(c.Addr(self.lock)) + + def acquire_read(self): + AcquireSRWLockShared(c.Addr(self.lock)) + + def release_read(self): + ReleaseSRWLockShared(c.Addr(self.lock)) + + def acquire_write(self): + AcquireSRWLockExclusive(c.Addr(self.lock)) + + def release_write(self): + ReleaseSRWLockExclusive(c.Addr(self.lock)) + + def __enter__(self) -> 'RWLock' | t.CPtr: + self.acquire_write() + return self + + def __exit__(self): + self.release_write() diff --git a/shutil.vp b/shutil.vp new file mode 100644 index 0000000..ed7e578 --- /dev/null +++ b/shutil.vp @@ -0,0 +1,283 @@ +import t, c +from stdint import * +import platmacro +import memhub +import string + +# Windows backend dependencies +import w32.win32base +import w32.win32file + +# POSIX backend dependencies +import posix + + +# File copy buffer size +COPY_BUF_SIZE: t.CDefine = 65536 # 2^16 + +# Module-level global MBuddy pointer (initialized by the user in main) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# copyfile: Copy file content (without preserving permissions/metadata) +# ============================================================================= + +def copyfile(src: str, dst: str) -> int: + """Copy file content. Returns 0, otherwise -1.""" + if platmacro.IS_WINDOWS: + return _copyfile_win32(src, dst) + return _copyfile_posix(src, dst) + + +def _copyfile_win32(src: str, dst: str) -> int: + """Windows: Use CopyFileA kernel implementation (efficient).""" + result: BOOL = w32.win32file.CopyFileA(src, dst, 0) + if result == 0: + return -1 + return 0 + + +def _copyfile_posix(src: str, dst: str) -> int: + """POSIX: Manual file read/write loop copy""" + fd_in: INT = posix.open(src, posix.O_RDONLY, 0) + if fd_in < 0: + return -1 + fd_out: INT = posix.open(dst, posix.O_WRONLY | posix.O_CREAT | posix.O_TRUNC, 0o644) + if fd_out < 0: + posix.close(fd_in) + return -1 + buf: bytes = _mbuddy.alloc(COPY_BUF_SIZE) + if buf == None: + posix.close(fd_in) + posix.close(fd_out) + return -1 + n: ssize_t = 0 + result: int = 0 + n = posix.read(fd_in, buf, COPY_BUF_SIZE) + while n > 0: + written: ssize_t = posix.write(fd_out, buf, t.CSizeT(n)) + if written < 0: + result = -1 + break + n = posix.read(fd_in, buf, COPY_BUF_SIZE) + if n < 0: + result = -1 + _mbuddy.free(buf) + posix.close(fd_in) + posix.close(fd_out) + return result + + +# ============================================================================= +# copy: Copy file and preserve permissions/metadata (POSIX only) +# ============================================================================= + +def copy(src: str, dst: str) -> int: + """Copy file and preserve permissions/metadata (POSIX only). Returns 0, otherwise -1.""" + if platmacro.IS_WINDOWS: + return _copy_win32(src, dst) + return _copy_posix(src, dst) + + +def _copy_win32(src: str, dst: str) -> int: + """Windows: Copy file (using CopyFileA kernel implementation (simple, delegate to copyfile).""" + return _copyfile_win32(src, dst) + + +def _copy_posix(src: str, dst: str) -> int: + """POSIX: Copy file and preserve permissions (stat+chmod). Returns 0, otherwise -1.""" + result: int = _copyfile_posix(src, dst) + if result != 0: + return -1 + st: posix.Stat = posix.Stat() + if posix.stat(src, t.CPtr(c.Addr(st))) == 0: + posix.chmod(dst, st.st_mode) + return 0 + + +# ============================================================================= +# rmtree: Recursively remove directory tree (POSIX only) +# ============================================================================= + +def rmtree(path: str) -> int: + """Recursively delete a directory tree. Returns 0 on success and -1 on failure.""" + if platmacro.IS_WINDOWS: + return _rmtree_win32(path) + return _rmtree_posix(path) + + +def _rmtree_win32(path: str) -> int: + """Windows: Recursively delete a directory tree using FindFirstFileA/FindNextFileA.""" + path_len: t.CSizeT = len(path) + # Construct search pattern path\* + pattern: bytes = _mbuddy.alloc(path_len + 3) + if pattern == None: + return -1 + i: t.CSizeT = 0 + for ch in path: + pattern[i] = ch + i += 1 + if path_len > 0: + if path[path_len - 1] != '\\' and path[path_len - 1] != '/': + pattern[i] = '\\' + i += 1 + pattern[i] = '*' + i += 1 + pattern[i] = 0 + + find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA() + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data))) + _mbuddy.free(pattern) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return -1 + + result: int = 0 + has_more: int = 1 + while has_more == 1: + name: str = find_data.cFileName + # Skip . and .. + skip: bool = False + if name[0] == '.': + if name[1] == 0: + skip = True + elif name[1] == '.' and name[2] == 0: + skip = True + if not skip: + # Construct full path path\name + name_len: t.CSizeT = len(name) + full_path: bytes = _mbuddy.alloc(path_len + name_len + 2) + if full_path == None: + result = -1 + else: + j: t.CSizeT = 0 + for ch in path: + full_path[j] = ch + j += 1 + if path_len > 0: + if path[path_len - 1] != '\\' and path[path_len - 1] != '/': + full_path[j] = '\\' + j += 1 + for ch in name: + full_path[j] = ch + j += 1 + full_path[j] = 0 + # Check if it's a directory or a file + if (find_data.dwFileAttributes & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + # Recursively delete subdirectory + sub_result: int = _rmtree_win32(str(full_path)) + if sub_result != 0: + result = -1 + else: + # Delete file + if w32.win32file.DeleteFileA(str(full_path)) == 0: + result = -1 + _mbuddy.free(full_path) + # Continue searching next entry + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + has_more = 0 + + w32.win32file.FindClose(handle) + # Delete empty directory itself + if result == 0: + if w32.win32file.RemoveDirectoryA(path) == 0: + result = -1 + return result + + +def _rmtree_posix(path: str) -> int: + """POSIX: Recursively delete a directory tree using opendir/readdir.""" + dirp: posix.DIR = posix.opendir(path) + if dirp == None: + return -1 + + path_len: t.CSizeT = len(path) + result: int = 0 + entry: posix.Dirent | t.CPtr = posix.readdir(dirp) + while entry != None: + name: str = entry.d_name + # Skip . and .. + skip: bool = False + if name[0] == '.': + if name[1] == 0: + skip = True + elif name[1] == '.' and name[2] == 0: + skip = True + if not skip: + # Construct full path path/name + name_len: t.CSizeT = len(name) + full_path: bytes = _mbuddy.alloc(path_len + name_len + 2) + if full_path == None: + result = -1 + else: + j: t.CSizeT = 0 + for ch in path: + full_path[j] = ch + j += 1 + if path_len > 0: + if path[path_len - 1] != '/': + full_path[j] = '/' + j += 1 + for ch in name: + full_path[j] = ch + j += 1 + full_path[j] = 0 + # Check entry type + if entry.d_type == posix.DT_DIR: + # Recursively delete subdirectory + sub_result: int = _rmtree_posix(str(full_path)) + if sub_result != 0: + result = -1 + else: + # Delete file or symbolic link etc. + if posix.unlink(str(full_path)) != 0: + result = -1 + _mbuddy.free(full_path) + entry = posix.readdir(dirp) + + posix.closedir(dirp) + # Delete empty directory itself + if result == 0: + if posix.rmdir(path) != 0: + result = -1 + return result + + +# ============================================================================= +# move:Move file/directory +# ============================================================================= + +def move(src: str, dst: str) -> int: + """Move/rename files or directories. If it's the same partition, just rename; + if it's across partitions, copy then delete. Returns 0 on success, -1 on failure.""" + if platmacro.IS_WINDOWS: + return _move_win32(src, dst) + return _move_posix(src, dst) + + +def _move_win32(src: str, dst: str) -> int: + """Windows: MoveFileExA (rename within the same partition, copy and delete across partitions)""" + rename_result: BOOL = w32.win32file.MoveFileExA( + src, dst, + w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED + ) + if rename_result != 0: + return 0 + # rename failed, try copy or remove + if copyfile(src, dst) != 0: + return -1 + if w32.win32file.DeleteFileA(src) == 0: + return -1 + return 0 + + +def _move_posix(src: str, dst: str) -> int: + """POSIX: rename (within the same partition), copy and unlink across partitions""" + if posix.rename(src, dst) == 0: + return 0 + # rename failed (possibly across partitions), try copy or remove + if copyfile(src, dst) != 0: + return -1 + if posix.unlink(src) != 0: + return -1 + return 0 diff --git a/socket.vp b/socket.vp new file mode 100644 index 0000000..163873e --- /dev/null +++ b/socket.vp @@ -0,0 +1,454 @@ +import t, c +from stdint import * +import string +import platmacro +import stdio +import w32.winsock2 + + +# ============================================================ +# socket.py — Cross-platform wrapper for Socket +# Python-style OOP API + Compatibility with legacy procedural functions +# +# Example: +# sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) +# sock.connect("example.com", 80) +# sock.send(data, length) +# n = sock.recv(buf, bufsize) +# sock.close() +# +# Only 3 platform differences (via platmacro.IS_WINDOWS branch): +# 1. WSAStartup() / WSACleanup() +# 2. closesocket() vs close() +# 3. WSAGetLastError() vs errno +# ============================================================ + + +# ============================================================ +# Constants +# ============================================================ +AF_INET: t.CDefine = 2 +AF_INET6: t.CDefine = 10 + +SOCK_STREAM: t.CDefine = 1 +SOCK_DGRAM: t.CDefine = 2 +SOCK_RAW: t.CDefine = 3 + +IPPROTO_TCP: t.CDefine = 6 +IPPROTO_UDP: t.CDefine = 17 + +SOL_SOCKET: t.CDefine = 1 +SO_RCVTIMEO: t.CDefine = 20 +SO_SNDTIMEO: t.CDefine = 21 +SO_REUSEADDR: t.CDefine = 2 + +INADDR_ANY: t.CDefine = 0 + +SOCKET_ERROR: t.CDefine = -1 +INVALID_SOCKET: t.CDefine = -1 + +SOCKET_DEFAULT_TIMEOUT: t.CDefine = 0 + + +# ============================================================ +# Structures +# ============================================================ + +class SocketAddr: + """sockaddr_in — IPv4 address (16 bytes layout)""" + family: u16 + port: u16 + addr: u32 + zero: u64 + + +class HostEnt: + """struct hostent — DNS resolution result""" + h_name: CHARPTR + h_aliases: CHARPTR + h_addrtype: INT + h_length: INT + h_addr_list: CHARPTR + + +class timeval: + """struct timeval — Timeout setting""" + tv_sec: INT + tv_usec: INT + + +# ============================================================ +# External C Functions — Using u64 Handle, Cross-platform Compatibility +# (Windows SOCKET=u64, POSIX fd=int → u64 Zero-Extension Compatible) +# ============================================================ + +def socket(family: INT, type: INT, protocol: INT) -> u64 | t.CExtern | t.CExport: pass +def connect(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT) -> INT | t.CExtern | t.CExport: pass +def send(fd: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.CExtern | t.CExport: pass +def recv(fd: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.CExtern | t.CExport: pass +def bind(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT) -> INT | t.CExtern | t.CExport: pass +def listen(fd: u64, backlog: INT) -> INT | t.CExtern | t.CExport: pass +def accept(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT | t.CPtr) -> u64 | t.CExtern | t.CExport: pass +def setsockopt(fd: u64, level: INT, optname: INT, optval: t.CVoid | t.CPtr, optlen: INT) -> INT | t.CExtern | t.CExport: pass +def gethostbyname(name: t.CChar | t.CConst | t.CPtr) -> HostEnt | t.CPtr | t.CExtern | t.CExport: pass +def ntohs(netshort: u16) -> u16 | t.CExtern | t.CExport: pass +def htons(hostshort: u16) -> u16 | t.CExtern | t.CExport: pass +def close(fd: u64) -> INT | t.CExtern | t.CExport: pass + + +# ============================================================ +# Internal Auxiliary Functions +# ============================================================ + +def _CloseFd(fd: INT) -> INT: + """Platform differences: Windows uses closesocket, POSIX uses close。""" + if platmacro.IS_WINDOWS: + return w32.winsock2.closesocket(u64(fd)) + return close(fd) + + +def _MakeAddr(host: str, port: INT) -> SocketAddr: + """Build SocketAddr. First try decimal IP, then DNS resolution. + If decimal IP fails, try DNS resolution. + If DNS resolution fails, return INADDR_ANY.""" + addr: SocketAddr + string.memset(c.Addr(addr), 0, 16) + addr.family = u16(AF_INET) + addr.port = htons(u16(port)) + + ip: u32 = 0 + if _ParseIPv4(host, c.Addr(ip)): + addr.addr = ip + return addr + + # DNS resolution — gethostbyname returns struct hostent* + # h_addr_list is char** → h_addr_list[0] is char* → *(uint32_t*)h_addr_list[0] is IP + if platmacro.IS_WINDOWS: + he_raw: w32.winsock2.WSAHostEnt | t.CPtr = w32.winsock2.gethostbyname(host) + if he_raw is not None: + # he_raw.h_addr_list → he_raw->h_addr_list (char**) + # c.Deref(t.CUInt64T(he_raw.h_addr_list, t.CPtr)) → *(uint64_t*)(he_raw->h_addr_list) → h_addr_list[0] + ip_ptr: u64 = u64(c.Deref(t.CUInt64T(he_raw.h_addr_list, t.CPtr))) + if ip_ptr != 0: + addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr))) + else: + he: HostEnt | t.CPtr = gethostbyname(host) + if he is not None: + ip_ptr: u64 = u64(c.Deref(t.CUInt64T(he.h_addr_list, t.CPtr))) + if ip_ptr != 0: + addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr))) + + return addr + + +def _ParseIPv4(ip_str: str, out_addr: u32 | t.CPtr) -> bool: + """Parse IPv4 address.""" + if ip_str is None or out_addr is None: return False + + parts: t.CArray[INT, 4] + part_count: INT = 0 + current: INT = 0 + started: bool = False + + for ch in ip_str: + if ch >= '0' and ch <= '9': + if not started: started = True + current = current * 10 + INT(ch - '0') + if current > 255: return False + elif ch == '.': + if not started: return False + if part_count >= 4: return False + parts[part_count] = current + part_count += 1 + current = 0 + started = False + else: + break + + if started and part_count < 4: + parts[part_count] = current + part_count += 1 + + if part_count != 4: return False + + result: u32 = 0 + result = result | (u32(parts[0]) << 24) + result = result | (u32(parts[1]) << 16) + result = result | (u32(parts[2]) << 8) + result = result | u32(parts[3]) + c.DerefAs(out_addr, result) + return True + + +# ============================================================ +# Socket class — Python OOP API +# ============================================================ + +class Socket: + """Cross-platform Socket class, similar to Python socket.socket. + + Usage: + sock = Socket(AF_INET, SOCK_STREAM) + sock.connect("example.com", 80) + sock.send(data, length) + n = sock.recv(buf, bufsize) + sock.close() + """ + fd: INT + family: INT + type: INT + protocol: INT + + def __init__(self, family: INT, type: INT, protocol: INT = 0): + """Create Socket. + + Args: + family: Address family (AF_INET) + type: Socket type (SOCK_STREAM) + protocol: Protocol (default 0, auto-match) + """ + self.family = family + self.type = type + self.protocol = protocol + + if platmacro.IS_WINDOWS: + self.fd = INT(w32.winsock2.socket(family, type, protocol)) + else: + self.fd = socket(family, type, protocol) + + def connect(self, host: str, port: INT) -> INT: + """Connect to remote host. + + Args: + host: Hostname or IP + port: Port number + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + addr: SocketAddr = _MakeAddr(host, port) + + result: INT = 0 + if platmacro.IS_WINDOWS: + result = w32.winsock2.connect(u64(self.fd), c.Addr(addr), 16) + if result != 0: + err: INT = w32.winsock2.WSAGetLastError() + else: + result = connect(self.fd, c.Addr(addr), 16) + return result + + def send(self, data: t.CVoid | t.CPtr, length: INT) -> INT: + """Send data. + + Returns: + Sent bytes, SOCKET_ERROR on error + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if data is None or length <= 0: return 0 + + if platmacro.IS_WINDOWS: + return w32.winsock2.send(u64(self.fd), data, length, 0) + return send(self.fd, data, length, 0) + + def recv(self, buf: t.CVoid | t.CPtr, bufsize: INT) -> INT: + """Receive data. + + Returns: + Received bytes, SOCKET_ERROR on error, 0 on connection close + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if buf is None or bufsize <= 0: return 0 + + if platmacro.IS_WINDOWS: + return w32.winsock2.recv(u64(self.fd), buf, bufsize, 0) + return recv(self.fd, buf, bufsize, 0) + + def sendall(self, data: t.CVoid | t.CPtr, length: INT) -> INT: + """Send all data. + + Returns: + 0 success, SOCKET_ERROR on error + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if data is None or length <= 0: return 0 + + total: INT = 0 + while total < length: + n: INT = self.send(t.CVoid(t.CUInt64T(data) + total, t.CPtr), length - total) + if n <= 0: return SOCKET_ERROR + total += n + return 0 + + def close(self) -> INT: + """Close Socket.""" + if self.fd == INVALID_SOCKET: return 0 + result: INT = _CloseFd(self.fd) + self.fd = INVALID_SOCKET + return result + + def bind(self, host: str, port: INT) -> INT: + """Bind address and port (server-side). + + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + addr: SocketAddr = _MakeAddr(host, port) + + if platmacro.IS_WINDOWS: + return w32.winsock2.bind(u64(self.fd), c.Addr(addr), 16) + return bind(self.fd, c.Addr(addr), 16) + + def listen(self, backlog: INT) -> INT: + """Start for incoming connections (server-side). + + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + + if platmacro.IS_WINDOWS: + return w32.winsock2.listen(u64(self.fd), backlog) + return listen(self.fd, backlog) + + def accept(self, out_client: 'Socket' | t.CPtr) -> INT: + """Accept a client connection. + + Args: + out_client: Output parameter, receives client Socket + Returns: + Client fd (>= 0 on success), SOCKET_ERROR on error + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if out_client is None: return SOCKET_ERROR + + addr: SocketAddr + string.memset(c.Addr(addr), 0, 16) + addrlen: INT = 16 + + if platmacro.IS_WINDOWS: + client_fd: u64 = w32.winsock2.accept(u64(self.fd), c.Addr(addr), c.Addr(addrlen)) + if client_fd == w32.winsock2.INVALID_SOCKET: + return SOCKET_ERROR + out_client.fd = INT(client_fd) + out_client.family = self.family + out_client.type = self.type + out_client.protocol = self.protocol + return INT(client_fd) + + client_fd: INT = accept(self.fd, c.Addr(addr), c.Addr(addrlen)) + if client_fd == SOCKET_ERROR: + return SOCKET_ERROR + out_client.fd = client_fd + out_client.family = self.family + out_client.type = self.type + out_client.protocol = self.protocol + return client_fd + + def settimeout(self, timeout_ms: INT) -> INT: + """Set timeout for receive and send operations (milliseconds). + + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + + tv: timeval + tv.tv_sec = timeout_ms / 1000 + tv.tv_usec = (timeout_ms % 1000) * 1000 + optlen: INT = 8 + + if platmacro.IS_WINDOWS: + r1: INT = w32.winsock2.setsockopt(u64(self.fd), SOL_SOCKET, SO_RCVTIMEO, c.Addr(tv), optlen) + r2: INT = w32.winsock2.setsockopt(u64(self.fd), SOL_SOCKET, SO_SNDTIMEO, c.Addr(tv), optlen) + else: + r1 = setsockopt(self.fd, SOL_SOCKET, SO_RCVTIMEO, c.Addr(tv), optlen) + r2 = setsockopt(self.fd, SOL_SOCKET, SO_SNDTIMEO, c.Addr(tv), optlen) + + if r1 != 0: return r1 + return r2 + + def fileno(self) -> INT: + """Return underlying file descriptor / SOCKET handle.""" + return self.fd + + +# ============================================================ +# Platform initialization +# ============================================================ + +def SocketInit() -> INT: + """Initialize the Socket library. On Windows, call WSAStartup; on POSIX, do nothing.""" + if platmacro.IS_WINDOWS: + wsa_data: t.CArray[BYTE, 400] + string.memset(c.Addr(wsa_data), 0, 400) + return w32.winsock2.WSAStartup(w32.winsock2.WINSOCK_VERSION, c.Addr(wsa_data)) + return 0 + + +def SocketCleanup() -> INT: + """Cleanup the Socket library.""" + if platmacro.IS_WINDOWS: + return w32.winsock2.WSACleanup() + return 0 + + +# ============================================================ +# Compatibility with old procedural API (delegates to Socket methods) +# ============================================================ + +def SocketCreate(family: INT, type: INT, protocol: INT, out_sock: Socket | t.CPtr) -> INT: + """Create a Socket handle (compatible with old API). It is recommended to use Socket(...) constructor.""" + if out_sock is None: return -1 + out_sock.family = family + out_sock.type = type + out_sock.protocol = protocol + + if platmacro.IS_WINDOWS: + fd: u64 = w32.winsock2.socket(family, type, protocol) + out_sock.fd = INT(fd) + if fd == w32.winsock2.INVALID_SOCKET: return -1 + else: + fd: INT = socket(family, type, protocol) + out_sock.fd = fd + if fd == INVALID_SOCKET: return -1 + return 0 + +# But maybe using OOP would be better, though that can be wrapped up later. + +def SocketConnect(sock: Socket | t.CPtr, host: str, port: INT) -> INT: + return sock.connect(host, port) + + +def SocketSend(sock: Socket | t.CPtr, data: t.CVoid | t.CPtr, length: INT) -> INT: + return sock.send(data, length) + + +def SocketRecv(sock: Socket | t.CPtr, buf: t.CVoid | t.CPtr, bufsize: INT) -> INT: + return sock.recv(buf, bufsize) + + +def SocketClose(sock: Socket | t.CPtr) -> INT: + return sock.close() + + +def SocketBind(sock: Socket | t.CPtr, host: str, port: INT) -> INT: + return sock.bind(host, port) + + +def SocketListen(sock: Socket | t.CPtr, backlog: INT) -> INT: + return sock.listen(backlog) + + +def SocketAccept(sock: Socket | t.CPtr, out_client: Socket | t.CPtr) -> INT: + return sock.accept(out_client) + + +def SocketSetTimeout(sock: Socket | t.CPtr, timeout_ms: INT) -> INT: + return sock.settimeout(timeout_ms) + + +def SocketIsValid(sock: Socket | t.CPtr) -> bool: + """Check if a Socket is valid.""" + if sock is None: return False + return sock.fd != INVALID_SOCKET \ No newline at end of file diff --git a/spinlock.vp b/spinlock.vp new file mode 100644 index 0000000..b16ecb3 --- /dev/null +++ b/spinlock.vp @@ -0,0 +1,16 @@ +import t, c +import atom + + +class _spinlock: + locked: t.CVolatile | t.CInt + name: t.CArray[t.CChar, 32] + + def __init__(self): + self.locked = 0 + + def lock(self): + while atom.__atomic_test_and_set(c.Addr(self.locked), atom.ATOMIC_ACQUIRE): pass + + def unlock(self): + atom.__atomic_clear(c.Addr(self.locked), atom.ATOMIC_RELEASE) diff --git a/stdarg.vp b/stdarg.vp new file mode 100644 index 0000000..1d0192f --- /dev/null +++ b/stdarg.vp @@ -0,0 +1,9 @@ +import t + +def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State: pass +def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr | t.State: pass +def va_end(args: t.CPtr) -> t.State | t.State: pass + +va_list: t.CTypedef = t.CUnsignedChar | t.CPtr + +def arg(type: t.CType) -> t.State: pass \ No newline at end of file diff --git a/stdint.vp b/stdint.vp new file mode 100644 index 0000000..727b759 --- /dev/null +++ b/stdint.vp @@ -0,0 +1,133 @@ +import t + + +# ============================================================================= +# 大写别名(Win32/TransPyC 风格) +# 注意:INTPTR/UINTPTR 在此模块中是 int*/unsigned int* 指针类型(历史命名)。 +# 它们与 C 标准的 intptr_t/uintptr_t 整数类型不同,后者见下方小写 _t 区域。 +# ============================================================================= +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr + +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid + +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr + +LONGLONG: t.CTypedef = t.CLongLong +ULONGLONG: t.CTypedef = t.CUnsignedLongLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong + +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD + +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble + +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T + + +# ============================================================================= +# 定长整数大写别名 +# ============================================================================= +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T + +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T + +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr + +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr + +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr + +i8: t.CTypedef = t.CInt8T +i16: t.CTypedef = t.CInt16T +i32: t.CTypedef = t.CInt32T +i64: t.CTypedef = t.CInt64T + +u8: t.CTypedef = t.CUInt8T +u16: t.CTypedef = t.CUInt16T +u32: t.CTypedef = t.CUInt32T +u64: t.CTypedef = t.CUInt64T + +SIZE_T: t.CTypedef = t.CSizeT +SSIZE_T: t.CTypedef = t.CPtrDiffT +PTRDIFF_T: t.CTypedef = t.CPtrDiffT + + +# ============================================================================= +# C 标准库 类型名(小写 _t 后缀) +# 这些是 C 语言标准类型名,从 _CNAME_ALIAS 挪到此处作为 typedef 提供。 +# 用户 `from stdint import *` 后即可直接使用 int8_t / size_t 等。 +# ============================================================================= +int8_t: t.CTypedef = t.CInt8T +int16_t: t.CTypedef = t.CInt16T +int32_t: t.CTypedef = t.CInt32T +int64_t: t.CTypedef = t.CInt64T + +uint8_t: t.CTypedef = t.CUInt8T +uint16_t: t.CTypedef = t.CUInt16T +uint32_t: t.CTypedef = t.CUInt32T +uint64_t: t.CTypedef = t.CUInt64T + +size_t: t.CTypedef = t.CSizeT +ssize_t: t.CTypedef = t.CPtrDiffT +ptrdiff_t: t.CTypedef = t.CPtrDiffT + +# intptr_t/uintptr_t 是足以容纳指针的整数类型(不是指针!) +# 与上方的 INTPTR/UINTPTR(int 指针)语义不同。 +intptr_t: t.CTypedef = t.CIntPtrT +uintptr_t: t.CTypedef = t.CUIntPtrT + +# 宽字符 / 字符类型 +wchar_t: t.CTypedef = t.CWCharT +char8_t: t.CTypedef = t.CChar8T +char16_t: t.CTypedef = t.CChar16T +char32_t: t.CTypedef = t.CChar32T + +# 浮点特化类型 +float8_t: t.CTypedef = t.CFloat8T +float16_t: t.CTypedef = t.CFloat16T +float32_t: t.CTypedef = t.CFloat32T +float64_t: t.CTypedef = t.CFloat64T +float128_t: t.CTypedef = t.CFloat128T + +_Bool: t.CTypedef = t.CBool diff --git a/stdio.vp b/stdio.vp new file mode 100644 index 0000000..5dd3213 --- /dev/null +++ b/stdio.vp @@ -0,0 +1,11 @@ +import t, c + + +def printf(fmt: t.CConst | str, *args) -> int | t.State: pass +def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass +def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass +def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> int | t.State: pass +def puts(s: t.CConst | str) -> int | t.State: pass +def fputs(s: t.CConst | str, stream: bytes) -> int | t.State: pass +def fgets(buf: bytes, size: int, stream: bytes) -> bytes | t.State: pass +def fflush(stream: bytes) -> int | t.State: pass diff --git a/stdlib.vp b/stdlib.vp new file mode 100644 index 0000000..a580043 --- /dev/null +++ b/stdlib.vp @@ -0,0 +1,10 @@ +from stdint import * +import t + + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass +def free(p: t.CVoid | t.CPtr) -> t.State: pass +def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass +def exit(status: int) -> t.State: pass \ No newline at end of file diff --git a/string.vp b/string.vp new file mode 100644 index 0000000..89981f1 --- /dev/null +++ b/string.vp @@ -0,0 +1,417 @@ +from stdint import * +import t, c +import stdio + + +# String copy function +def strcpy(dest: str, src: str) -> str: + if dest == None or src == None: return None + original_dest: str = dest + for s in src: + dest[0] = s + dest += 1 + dest[0] = 0 + return original_dest + + +# String concatenate function +def strcat(dest: str, src: str) -> str: + if dest == None or src == None: return dest + original_dest: str = dest + # Find end of dest + while dest[0] != '\0': + dest += 1 + # Copy src + for s in src: + dest[0] = s + dest += 1 + dest[0] = 0 + return original_dest + + +# String copy function with limited length +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: + if dest == None or src == None or n == 0: return dest + original_dest: str = dest + i: t.CSizeT = 0 + for s in src: + if i >= n: break + dest[0] = s + dest += 1 + i += 1 + # Fill remaining space with '\0' + while i < n: + dest[0] = 0 + dest += 1 + i += 1 + return original_dest + + +# String concatenate function with limited length +def strncat(dest: str, src: str, n: t.CSizeT) -> str: + if dest == None or src == None or n == 0: return dest + original_dest: str = dest + # Find end of dest + while dest[0] != '\0': + dest += 1 + # Copy up to n chars from src + i: t.CSizeT = 0 + for s in src: + if i >= n: break + dest[0] = s + dest += 1 + i += 1 + dest[0] = 0 + return original_dest + + +# String length function +def strlen(src: str) -> t.CSizeT | t.CExport: + length: t.CSizeT = 0 + for _ in src: + length += 1 + return length + +# String comparison function +def strcmp(str1: str, str2: str) -> t.CInt: + while str1[0] != '\0' and str2[0] != '\0': + if str1[0] != str2[0]: + return str1[0] - str2[0] + str1 += 1 + str2 += 1 + return str1[0] - str2[0] + +def samestr(str1: str, str2: str) -> bool: + return strcmp(str1, str2) == 0 + + +# String compare function with limited length +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: + i: t.CSizeT = 0 + while str1[0] != '\0' and str2[0] != '\0' and i < n: + if str1[0] != str2[0]: + return str1[0] - str2[0] + str1 += 1 + str2 += 1 + i += 1 + if i < n: + return str1[0] - str2[0] + return 0 + + +# Memory compare function +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: + p1: BYTEPTR = BYTEPTR(ptr1) + p2: BYTEPTR = BYTEPTR(ptr2) + i: t.CSizeT = 0 + while i < n: + if p1[i] != p2[i]: + return t.CInt(p1[i]) - t.CInt(p2[i]) + i += 1 + return 0 + + +# String find function +def strchr(s: str, cr: t.CInt) -> str: + while s[0] != '\0': + if s[0] == t.CChar(cr): + return str(s) + s += 1 + if cr == '\0': + return str(s) + return None + +# String reverse find function (find last occurrence of character) +def strrchr(s: str, cr: t.CInt) -> str: + last: str = None + while s[0] != '\0': + if s[0] == t.CChar(cr): + last = s + s += 1 + if cr == '\0': return s + return last + + +# Substring search function (find first occurrence of needle in s, return pointer to that position, or None if not found) +def strstr(s: str, needle: str) -> str: + if needle[0] == 0: + return s + needle_len: t.CSizeT = strlen(needle) + if needle_len == 0: + return s + i: t.CSizeT = 0 + s_len: t.CSizeT = strlen(s) + while i + needle_len <= s_len: + if strncmp(s + i, needle, needle_len) == 0: + return s + i + i += 1 + return None + +# String skip function +def strspn(s: str, skip: str = " ") -> int: + si: int = 0 + while s[si] != 0: + found: int = 0 + sj: int = 0 + while skip[sj] != 0: + if s[si] == skip[sj]: + found = 1 + break + sj += 1 + if found == 0: + break + si += 1 + return si + +# Memory set function +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: + # Original implementation: + # p: BYTEPTR = BYTEPTR(ptr) + # i: t.CSizeT + # for i in range(num): + # p[i] = t.CUnsignedChar(value) + if num == 0: return ptr + c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)} + rep stosb""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, + t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI]) + return ptr + + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: + # Original implementation: + # p: UINT32PTR = UINT32PTR(ptr) + # i: t.CSizeT + # for i in range(count): + # p[i] = value + if count == 0: return ptr + c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(count, t.ASM_DESCR.REG_ANY)} + rep stosd""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, + t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI]) + return ptr + + +# Memory copy function +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: + # Original implementation: + # d: BYTEPTR = BYTEPTR(dest) + # s: BYTEPTR = BYTEPTR(src) + # i: t.CSizeT + # for i in range(num): + # d[i] = s[i] + if num == 0: return dest + c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)} + mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)} + rep movsb""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX, + t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI]) + return dest + + +# 内存移动函数 +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: + # 原始实现: + # d: BYTEPTR = BYTEPTR(dest) + # s: BYTEPTR = BYTEPTR(src) + # i: t.CSizeT + # if d < s: + # for i in range(num): + # d[i] = s[i] + # elif d > s: + # for i in range(num, 0, -1): + # d[i - 1] = s[i - 1] + if num == 0: return dest + c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)} + mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)} + cmp rdi, rsi + jb 2f + std + add rdi, rcx + dec rdi + add rsi, rcx + dec rsi + rep movsb + cld + jmp 3f + 2: + rep movsb + 3:""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX, + t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI]) + return dest + + +def atoi(src: str) -> t.CInt: + num: t.CInt = 0 + sign: t.CInt = 1 + s: str = src + if s == None: return 0 + # 跳过空白 + while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r': + s += 1 + # 符号 + if s[0] == '-': + sign = -1 + s += 1 + elif s[0] == '+': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + digit: t.CInt = ch - '0' + num = num * 10 + digit + return num * sign + + +def atoll(src: str) -> t.CInt64T: + num: t.CInt64T = 0 + sign: t.CInt64T = 1 + s: str = src + if s == None: return 0 + while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r': + s += 1 + if s[0] == '-': + sign = -1 + s += 1 + elif s[0] == '+': + s += 1 + # 十六进制前缀 0x / 0X + is_hex: t.CInt = 0 + if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'): + is_hex = 1 + s += 2 + if is_hex: + for ch in s: + d: t.CInt = 0 + if ch >= '0' and ch <= '9': + d = ch - '0' + elif ch >= 'a' and ch <= 'f': + d = ch - 'a' + 10 + elif ch >= 'A' and ch <= 'F': + d = ch - 'A' + 10 + else: + break + digit: t.CInt64T = t.CInt64T(d) + num = num * 16 + digit + else: + for ch in s: + if ch < '0' or ch > '9': break + d: t.CInt = ch - '0' + digit: t.CInt64T = t.CInt64T(d) + num = num * 10 + digit + return num * sign + + +def atof(src: str) -> t.CDouble: + s: str = src + if s == None: return 0.0 + # 跳过空白 + while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r': + s += 1 + # 符号 + sign: t.CDouble = 1.0 + if s[0] == '-': + sign = -1.0 + s += 1 + elif s[0] == '+': + s += 1 + # 整数部分 + int_part: t.CDouble = 0.0 + for ch in s: + if ch < '0' or ch > '9': break + d1: t.CInt = ch - '0' + int_part = int_part * 10.0 + t.CDouble(d1) + s += 1 + # 小数部分 + frac_part: t.CDouble = 0.0 + frac_div: t.CDouble = 1.0 + if s[0] == '.': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + d2: t.CInt = ch - '0' + frac_div = frac_div * 10.0 + frac_part = frac_part * 10.0 + t.CDouble(d2) + s += 1 + # 指数部分 + exp: t.CInt = 0 + exp_sign: t.CInt = 1 + if s[0] == 'e' or s[0] == 'E': + s += 1 + if s[0] == '-': + exp_sign = -1 + s += 1 + elif s[0] == '+': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + d3: t.CInt = ch - '0' + exp = exp * 10 + d3 + s += 1 + exp = exp * exp_sign + result: t.CDouble = sign * (int_part + frac_part / frac_div) + # 应用指数 + if exp > 0: + while exp > 0: + result = result * 10.0 + exp -= 1 + elif exp < 0: + while exp < 0: + result = result / 10.0 + exp += 1 + return result + + +def atof_out(src: str, out: t.CDouble | t.CPtr) -> t.CInt: + """atof 结果写入 out[0](输出参数方式,避免跨模块 double 返回值传递 bug) + + 返回值仅表示成功与否(1=成功,0=失败),结果值通过 out 指针传递, + 不依赖 double 返回值的跨模块传递。 + """ + if out is None: + return 0 + v: t.CDouble = atof(src) + out[0] = v + return 1 + +def split(s: str, delim: str, result: t.CArray[str]) -> int: + count: int = 0 + start: str = s + if not s or not delim or not result: + return 0 + d: t.CChar = delim[0] # 单分隔符 + + while start[0]: + # 跳过分隔符 + while start[0] == d: start += 1 + if not start[0]: break + + # 记录token起始 + result[count] = start + count += 1 + + # 找到下一个分隔符,截断 + while start[0] and start[0] != d: start += 1 + if start[0]: + start[0] = '\0' + start += 1 + result[count] = None # 结尾标记 + return count + + +ascii_lowercase: str = "abcdefghijklmnopqrstuvwxyz" +ascii_uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +ascii_letters: str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +digits: str = "0123456789" +hexdigits: str = "0123456789abcdefABCDEF" +octdigits: str = "01234567" +punctuation: str = "!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~" +whitespace: str = " \t\n\r\f\v" +printable: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\f\v" diff --git a/subprocess.vp b/subprocess.vp new file mode 100644 index 0000000..3496993 --- /dev/null +++ b/subprocess.vp @@ -0,0 +1,196 @@ +import t, c +from stdint import * +import platmacro +import memhub +import string + +# Windows backend dependencies +import w32.win32base +import w32.win32file +import w32.win32process +import w32.win32sync + +# POSIX backend dependencies +import posix + + +# Subprocess output buffer size +OUTPUT_BUF_SIZE: t.CDefine = 65536 + +# Module global MBuddy pointer (initialized in main) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# CompletedProcess result class +# ============================================================================= + +class CompletedProcess: + """Result class for subprocess.run.""" + args: str # Original command line + returncode: int # Process exit code (0 means success) + stdout: str # Standard output (when capture_output=True) + stderr: str # Standard error (when capture_output=True) + + def __new__(self, args: str, returncode: int, stdout: str, stderr: str) -> t.CPtr: + # Heap allocation (avoiding use-after-return) + return t.CPtr(_mbuddy.alloc(CompletedProcess.__sizeof__())) + + def __init__(self, args: str, returncode: int, stdout: str, stderr: str): + self.args = args + self.returncode = returncode + self.stdout = stdout + self.stderr = stderr + + +# ============================================================================= +# Entry function +# ============================================================================= + +def run(args: str, capture_output: bool = True, text: bool = True) -> CompletedProcess | t.CPtr: + """Run a subprocess synchronously and wait for it to finish. + The args are the full command line string. + If capture_output=True, stdout/stderr will be captured. If text=True, the output will be a string (currently it always returns a string). + Returns a CompletedProcess object.""" + if platmacro.IS_WINDOWS: + return _run_win32(args, capture_output, text) + return _run_posix(args, capture_output, text) + + +# ============================================================================= +# Windows backend implementation +# ============================================================================= + +def _run_win32(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: + """Windows platform subprocess execution (CreateProcessA pipe)""" + # Copy command line (CreateProcessA requires a modifiable lpCommandLine) + args_len: t.CSizeT = len(args) + cmd_line: bytes = _mbuddy.alloc(args_len + 1) + if cmd_line == None: + return CompletedProcess(args, -1, None, None) + i: t.CSizeT = 0 + for ch in args: + cmd_line[i] = ch + i += 1 + cmd_line[args_len] = 0 + + # Security attributes (allow handle inheritance) + sa: w32.win32base.SECURITY_ATTRIBUTES = w32.win32base.SECURITY_ATTRIBUTES() + sa.nLength = w32.win32base.SECURITY_ATTRIBUTES.__sizeof__() + sa.lpSecurityDescriptor = t.CPtr(0) + sa.bInheritHandle = 1 # TRUE + + # Create stdout pipe + stdout_read: w32.win32base.HANDLE = t.CPtr(0) + stdout_write: w32.win32base.HANDLE = t.CPtr(0) + if capture_output: + pipe_result: BOOL = w32.win32file.CreatePipe( + t.CPtr(c.Addr(stdout_read)), + t.CPtr(c.Addr(stdout_write)), + t.CPtr(c.Addr(sa)), + 0 + ) + if pipe_result == 0: + return CompletedProcess(args, -1, None, None) + # Prevent read end from being inherited by child process + w32.win32file.SetHandleInformation(stdout_read, w32.win32file.HANDLE_FLAG_INHERIT, 0) + + # Set startup information + si: w32.win32process.STARTUPINFOA = w32.win32process.STARTUPINFOA() + si.cb = w32.win32process.STARTUPINFOA.__sizeof__() + if capture_output: + si.dwFlags = w32.win32process.STARTF_USESTDHANDLES + si.hStdOutput = stdout_write + si.hStdError = stdout_write # stderr merged to stdout + + pi: w32.win32process.PROCESS_INFORMATION = w32.win32process.PROCESS_INFORMATION() + + # Create process + # use CREATE_NO_WINDOW when capture_output=True (output to pipe, no console) + # use 0 when capture_output=False (inherit parent process console, let stdout directly display) + create_flags: ULONG = w32.win32process.CREATE_NO_WINDOW if capture_output else 0 + create_result: BOOL = w32.win32process.CreateProcessA( + t.CPtr(0), # lpApplicationName (NULL, parse from command line) + cmd_line, # lpCommandLine (modifiable) + t.CPtr(0), # lpProcessAttributes + t.CPtr(0), # lpThreadAttributes + 1, # bInheritHandles = TRUE + create_flags, # dwCreationFlags + t.CPtr(0), # lpEnvironment (inherit from parent process) + t.CPtr(0), # lpCurrentDirectory (inherit from parent process) + t.CPtr(c.Addr(si)), + t.CPtr(c.Addr(pi)) + ) + + if create_result == 0: + # Create process failed + if capture_output: + w32.win32base.CloseHandle(stdout_read) + w32.win32base.CloseHandle(stdout_write) + return CompletedProcess(args, -1, None, None) + + # Close parent process's write end (child process already has a copy of it) + if capture_output: + w32.win32base.CloseHandle(stdout_write) + + # Read stdout + wait for process to exit + # Note: must read and wait at the same time, or else deadlock will occur when child process outputs more than pipe buffer size + # (child process blocks on writing stdout, parent process blocks on WaitForSingleObject) + stdout_str: str = None + if capture_output: + buf_size: ULONG = OUTPUT_BUF_SIZE + buf: bytes = _mbuddy.alloc(buf_size) + if buf != None: + total: ULONG = 0 + while 1: + bytes_read: ULONG = 0 + read_result: BOOL = w32.win32file.ReadFile( + stdout_read, + buf + total, + buf_size - 1 - total, + t.CPtr(c.Addr(bytes_read)), + t.CPtr(0) + ) + if read_result == 0 or bytes_read == 0: + break + total += bytes_read + # Buffer will be full, double it + if total >= buf_size - 1 - 4096: + new_size: ULONG = buf_size * 2 + new_buf: bytes = _mbuddy.alloc(new_size) + if new_buf != None: + string.memcpy(new_buf, buf, total) + buf = new_buf + buf_size = new_size + else: + # Expand failed, stop reading + break + buf[total] = 0 + stdout_str = str(buf) + + # Wait for process to exit + w32.win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE) + + # Get exit code + exit_code: ULONG = 0 + w32.win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(c.Addr(exit_code))) + + # Close handles + w32.win32base.CloseHandle(pi.hProcess) + w32.win32base.CloseHandle(pi.hThread) + if capture_output: + w32.win32base.CloseHandle(stdout_read) + + return CompletedProcess(args, exit_code, stdout_str, None) + + +# ============================================================================= +# POSIX backend implementation +# ============================================================================= + +def _run_posix(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: + """POSIX platform subprocess execution (fork, execvp, pipe, waitpid) + Note: Currently this is a stub function. + POSIX implementation requires pipe/fork/waitpid, which are not available on Windows MinGW. + It will be completed when testing on a POSIX platform.""" + return CompletedProcess(args, -1, None, None) diff --git a/sys.vp b/sys.vp new file mode 100644 index 0000000..251a776 --- /dev/null +++ b/sys.vp @@ -0,0 +1,200 @@ +import t, c +from stdint import * +import platmacro +import memhub +import string +import stdio + +# Windows backend dependencies +import w32.win32base +import w32.win32process + +# POSIX backend dependencies +import posix + +# Module global MBuddy pointer (initialized in user main), Plans to ban +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# C Standard Library IO Declarations +# ============================================================================= + +def fgets(buf: bytes, size: int, stream: t.CVoid | t.CPtr) -> str | t.State: pass + +def fflush(stream: t.CVoid | t.CPtr) -> int | t.State: pass + +# C standard library exit (terminates the process after flushing the buffer, cross-platform) +def exit(status: int) -> t.State: pass + + +# ============================================================================= +# Platform Information +# ============================================================================= + +# Maximum integer value (64-bit platform ssize_t upper limit) +maxsize: t.CDefine = 9223372036854775807 # 2^63 - 1 + + +def platform() -> str: + """Returns the platform identifier string ('win32' or 'linux').""" + if platmacro.IS_WINDOWS: + return "win32" + return "linux" + + +# ============================================================================= +# Process Information +# ============================================================================= + +def get_pid() -> int: + """返回当前进程 ID""" + if platmacro.IS_WINDOWS: + return w32.win32process.GetCurrentProcessId() + return posix.getpid() + + +# ============================================================================= +# Command Line Arguments (argv) +# ============================================================================= + +# global argv status (initialized on first access) +_argc: int = 0 +# _argv is a pointer array (char**), must use str | t.CPtr to index with sizeof(char*) +# str | t.CPtr is a pointer to char** +# bytes | t.CPtr is a pointer to char** +_argv: str | t.CPtr + + +def _init_argv(): + """Initialize global argv once on first access""" + global _argc, _argv + if _argc != 0: + return + if platmacro.IS_WINDOWS: + _init_argv_win32() + else: + _init_argv_posix() + + +def _init_argv_win32(): + """Windows: GetCommandLineA + manual parsing (handle spaces/double quotes/backslashes)""" + global _argc, _argv + cmdline: CHARPTR = w32.win32base.GetCommandLineA() + if cmdline == None: + return + cmdlen: t.CSizeT = string.strlen(cmdline) + if cmdlen == 0: + return + + # Allocate buffer for parameter strings (worst case: entire command line + argc \0s) + buf: bytes = _mbuddy.alloc(cmdlen + 1) + if buf == None: + return + + # Allocate pointer array for argv (worst case: each character is a parameter) + max_args: t.CSizeT = cmdlen + 1 + argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(max_args * platmacro.SIZEOF_POINTER)) + if argv_arr == None: + return + + argc: INT = 0 + i: t.CSizeT = 0 + j: t.CSizeT = 0 + in_quote: bool = False + in_arg: bool = False + + while i < cmdlen: + ch: t.CInt = cmdline[i] + if ch == 34: # Double quote + in_quote = not in_quote + if not in_arg: + argv_arr[argc] = str(buf + j) + argc += 1 + in_arg = True + elif (ch == 32 or ch == 9) and not in_quote: + # Space or Tab (outside quotes): parameter delimiter + if in_arg: + buf[j] = 0 + j += 1 + in_arg = False + else: + if not in_arg: + argv_arr[argc] = str(buf + j) + argc += 1 + in_arg = True + buf[j] = ch + j += 1 + i += 1 + + if in_arg: + buf[j] = 0 + + _argc = argc + _argv = argv_arr + + +def _init_argv_posix(): + """POSIX: Read cmdline from /proc/self/cmdline (\0) separated parameters""" + global _argc, _argv + fd: INT = posix.open("/proc/self/cmdline", posix.O_RDONLY, 0) + if fd < 0: + return + + # Read cmdline (4KB) + buf: bytes = _mbuddy.alloc(4096) # Need to verify size of buffer + if buf == None: + posix.close(fd) + return + + total: ssize_t = posix.read(fd, buf, 4096) + posix.close(fd) + if total <= 0: + return + + # Calculate argument count (\0 delimited) + argc: INT = 0 + i: t.CSizeT = 0 + total_size: t.CSizeT = t.CSizeT(total) + while i < total_size: + if buf[i] == 0: + argc += 1 + i += 1 + + if argc == 0: + return + + # Allocate pointer array for argv (argc pointers) + argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(argc * platmacro.SIZEOF_POINTER)) + if argv_arr == None: + return + + # Populate pointer array (start address of each parameter) + argv_arr[0] = str(buf) + idx: INT = 1 + i = 0 + while i < total_size and idx < argc: + if buf[i] == 0: + argv_arr[idx] = str(buf + i + 1) + idx += 1 + i += 1 + + _argc = argc + _argv = argv_arr + + +def argc() -> int: + """Returns the number of command line arguments. Automatically initializes on the first call.""" + if _argc == 0: + _init_argv() + return _argc + + +def argv(index: int) -> str: + """Returns the command line argument at index `index` (starting from 0). + Automatically initializes on first call. Returns None if the index is out of range.""" + if _argc == 0: + _init_argv() + if index < 0 or index >= _argc: + return None + return _argv[index] diff --git a/testcheck.vp b/testcheck.vp new file mode 100644 index 0000000..29e1989 --- /dev/null +++ b/testcheck.vp @@ -0,0 +1,71 @@ +# testcheck - Regression test formatted output library +# Provide PASS/FAIL counts, section headers, summary reports +import t, c +import stdio +from w32.win32console import SetConsoleOutputCP, SetConsoleCP + +CP_UTF8: t.CDefine = 65001 + +_pass_count: t.CInt = 0 +_fail_count: t.CInt = 0 +_total_pass: t.CInt = 0 +_total_fail: t.CInt = 0 + + +def begin(name: str): + """Start the test suite, print the header, and reset the current suite counter (total count remains the same)""" + global _pass_count, _fail_count + _pass_count = 0 + _fail_count = 0 + SetConsoleOutputCP(CP_UTF8) + SetConsoleCP(CP_UTF8) + stdio.printf("=== %s ===\n\n", name) + + +def section(name: str): + """Print the section header""" + stdio.printf("--- %s ---\n", name) + + +def ok(msg: str): + """Print PASS and count""" + global _pass_count + _pass_count += 1 + stdio.printf("PASS: %s\n", msg) + + +def fail(msg: str): + """Print FAIL and count""" + global _fail_count + _fail_count += 1 + stdio.printf("FAIL: %s\n", msg) + + +def check(cond: t.CInt, ok_msg: str, fail_msg: str): + """Conditional check, automatically select PASS/FAIL""" + if cond: + ok(ok_msg) + else: + fail(fail_msg) + + +def info(msg: str): + """Print information message (not counted in the PASS/FAIL messages)""" + stdio.printf("%s\n", msg) + + +def end() -> t.CInt: + """Print the current suite summary, accumulate to total, return the current suite fail count""" + global _total_pass, _total_fail + _total_pass += _pass_count + _total_fail += _fail_count + stdio.printf("\n--- Summary ---\n") + stdio.printf("PASS: %d, FAIL: %d\n", _pass_count, _fail_count) + return _fail_count + + +def summary() -> t.CInt: + """Print the total summary of all suites, return the total fail count""" + stdio.printf("\n=== Total Summary ===\n") + stdio.printf("Total PASS: %d, Total FAIL: %d\n", _total_pass, _total_fail) + return _total_fail diff --git a/this.vp b/this.vp new file mode 100644 index 0000000..8c93b93 --- /dev/null +++ b/this.vp @@ -0,0 +1,39 @@ +import stdio, t, c + + +def this(): + s: str = """Ivcre Cevapvcyrf, ol GrezvArkhf + +Ornhgl orngf htyvarff. +Rkcyvpvg orngf vzcyvpvg. +Fvzcyr orngf pbzcyrk. +Pbapvfr orngf ireobfr. +Syng orngf qrrc arfgvat. +Fcnpvbhf orngf pyhggrerq. +Ernqnovyvgl vf pehpvny. +Fcrpvny pnfrf qba’g whfgvsl oernxvat gur ehyrf. +Ohg cenpgvpnyvgl orngf cher vqrnyf. +Reebef fubhyq arire or fvyragyl vtaberq. +Hayrff rkcyvpvgyl fgngrq gb or vtaberq. +Jura snprq jvgu nzovthbhf frznagvpf, erfvfg znxvat nffhzcgvbaf. +Hayrff pyrneyl nyybjrq. +Gurer fubhyq or bar — cersrenoyl bayl bar — boivbhf jnl gb qb vg. +Rira vs vg’f uneq gb tenfc ng svefg, hayrff lbh qrrcyl haqrefgnaq gur haqreylvat flfgrz. +Fgnegvat vzzrqvngryl orngf vaqrsvavgr qrynl. +Ohg unfgl npgvba vf bsgra jbefr guna pnershy jnvgvat. +Vs na vzcyrzragngvba vf bofpher naq uneq gb qrfpevor, vg’f n onq fbyhgvba. +Vs na vzcyrzragngvba vf pyrne naq rnfl gb haqrefgnaq, punaprf ner vg’f n tbbq fbyhgvba. +Anzrfcnprf ner vaperqvoyl inyhnoyr — hfr gurz trarebhfyl!""" + + # ASCII + m: t.CArray[t.CChar, 256] = [0] + l: t.CArray[int, 2] = [65, 97] + + for k in [65, 97]: + for i in range(26): + m[k + i] = (k + ((i + 13) % 26)) # Implicit type conversion + + for ch in s: + _: t.CUInt8T = ch + stdio.printf("%c", m[_] if m[_] else ch) + stdio.printf("\n") diff --git a/vector.vp b/vector.vp new file mode 100644 index 0000000..e32a74b --- /dev/null +++ b/vector.vp @@ -0,0 +1,65 @@ +import t, c +from stdint import * +import memhub + + +class Vector[T](): + data: t.CVoid | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + elem_size: t.CSizeT + pool: memhub.MemManager | t.CPtr + + def __init__(self, pool: memhub.MemManager | t.CPtr, capacity: t.CSizeT, _hint: T): + self.elem_size = T.__sizeof__() + self.capacity = capacity + self.length = 0 + self.pool = pool + self.data = pool.alloc(capacity * self.elem_size) + + def push(self, value: T): + if self.data == None: return + if self.length >= self.capacity: + self._grow() + if self.length >= self.capacity: return + offset: t.CUInt64T = t.CUInt64T(self.data) + self.length * self.elem_size + dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr) + c.DerefAs(dst, value) + self.length += 1 + + def _grow(self): + if self.pool == None: return + new_capacity: t.CSizeT = self.capacity * 2 + if new_capacity == 0: new_capacity = 4 + new_size: t.CSizeT = new_capacity * self.elem_size + new_data: t.CVoid | t.CPtr = self.pool.realloc(self.data, new_size) + if new_data == None: return + self.data = new_data + self.capacity = new_capacity + + def get(self, index: t.CSizeT) -> T: + if self.data == None: return T(0) + offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size + typed_ptr = T(offset, t.CPtr) + return c.Deref(typed_ptr) + + def set(self, index: t.CSizeT, value: T): + if index >= self.length: return + if self.data == None: return + offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size + dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr) + c.DerefAs(dst, value) + + def len(self) -> t.CSizeT: + return self.length + + def clear(self): + self.length = 0 + + def free(self): + if self.data != None: + if self.pool != None: + self.pool.free(self.data) + self.data = None + self.length = 0 + self.capacity = 0 diff --git a/viperio.vp b/viperio.vp new file mode 100644 index 0000000..48157bc --- /dev/null +++ b/viperio.vp @@ -0,0 +1,59 @@ +import t, c +from stdint import * + + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + + def __init__(self, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT = 0, owned: bool = False): + self.data = data + self.capacity = capacity + self.length = length + self.owned = owned + + def clear(self): + self.length = 0 + if self.data != None and self.capacity > 0: + self.data[0] = 0 + + def write(self, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: + if self.data == None: return 0 + if src == None: return 0 + if count == 0: return 0 + avail: t.CSizeT = self.capacity - self.length + if avail <= 0: return 0 + n: t.CSizeT = count if count < avail else avail + i: t.CSizeT = 0 + while i < n: + self.data[self.length + i] = src[i] + i += 1 + self.length += n + # 恰好写满(n==avail)时 data[capacity] 越界 1 字节,加保护 + if self.length < self.capacity: + self.data[self.length] = 0 + return n + + def cstr(self) -> t.CChar | t.CPtr: + return self.data + + def reset(self): + self.length = 0 + if self.data != None and self.capacity > 0: + self.data[0] = 0 + + def __enter__(self) -> 'Buf' | t.CPtr: + return self + + def __exit__(self): + self.reset() + + def free(self): + if self.owned and self.data != None: + self.data[0] = 0 + self.owned = False + self.data = None + self.length = 0 + self.capacity = 0 diff --git a/viperlib.vp b/viperlib.vp new file mode 100644 index 0000000..f0cecb6 --- /dev/null +++ b/viperlib.vp @@ -0,0 +1,1375 @@ +import t, c +import viperio +from stdarg import arg, va_arg + +TEMP_BUF_SIZE: t.CDefine = 68 + +def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt: + count: t.CInt = 0 + if num == 0: return 1 + while num > 0: + count += 1 + num //= base + return count + +def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.CExport: + if buf is None or rule is None: return + vsnprintf(buf, 0x7FFFFFFF, rule, args) + +def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt: + if buf is None or rule is None: return 0 + return vsnprintf(buf, 0x7FFFFFFF, rule, args) + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.CExport: + if fmt is None: return 0 + if buf is None or size == 0: + return vsnprintf(None, 0, fmt, args) + ret: t.CInt = vsnprintf(buf, size, fmt, args) + return ret + +# Check floating-point special values (IEEE 754) +# Return: 0=normal, 1=+inf, 2=-inf, 3=nan +def _check_special_float(fv: t.CDouble) -> t.CInt: + fbits: t.CUInt64T = 0 + c.Load(c.Addr(fbits), c.Addr(fv)) + if ((fbits >> 52) & 0x7FF) != 0x7FF: + return 0 + is_neg: t.CInt = 1 if (fbits >> 63) != 0 else 0 + if (fbits & 0x000FFFFFFFFFFFFF) == 0: + if is_neg: + return 2 + return 1 + return 3 + +def vsnprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) -> t.CInt | t.CExport: + if fmt is None: return 0 + # 长度探测模式:buf is None 时只计算格式化后长度,不实际写入 + # _step=0 使 ptr 不前进,反复写入同一个 dummy 字节(无害),write_count 正确累加 + count_mode: t.CInt = 0 + _step: t.CInt = 1 + _dummy: t.CChar = '\0' + if buf is None or size == 0: + count_mode = 1 + _step = 0 + buf = c.Addr(_dummy) + size = 0x7FFFFFFF + ptr: t.CChar | t.CPtr = buf + write_count: t.CInt = 0 + temp: t.CArray[t.CChar, 68] + temp[0] = '\t' + while c.Deref(fmt) != 0 and write_count < size - 1: + if c.Deref(fmt) != 37: + ptr[0] = c.Deref(fmt) + write_count += 1 + ptr += _step + fmt += 1 + else: + fmt += 1 + if c.Deref(fmt) == 0: break + width: t.CInt = 0 + pad_zero: t.CInt = 0 + left_align: t.CInt = 0 + show_sign: t.CInt = 0 + space_sign: t.CInt = 0 + alt_form: t.CInt = 0 + precision: t.CInt = -1 + is_long: t.CInt = 0 + is_long_long: t.CInt = 0 + is_size: t.CInt = 0 + is_short: t.CInt = 0 + is_char: t.CInt = 0 + while True: + if c.Deref(fmt) == 45: + left_align = 1 + fmt += 1 + elif c.Deref(fmt) == 48: + pad_zero = 1 + fmt += 1 + elif c.Deref(fmt) == 43: + show_sign = 1 + fmt += 1 + elif c.Deref(fmt) == 32: + space_sign = 1 + fmt += 1 + elif c.Deref(fmt) == 35: + alt_form = 1 + fmt += 1 + else: break + if show_sign: space_sign = 0 + while c.Deref(fmt) >= 48 and c.Deref(fmt) <= 57: + width = width * 10 + (c.Deref(fmt) - 48) + fmt += 1 + if c.Deref(fmt) == 46: + fmt += 1 + precision = 0 + while c.Deref(fmt) >= 48 and c.Deref(fmt) <= 57: + precision = precision * 10 + (c.Deref(fmt) - 48) + fmt += 1 + if left_align: pad_zero = 0 + if c.Deref(fmt) == 108: + is_long = 1 + fmt += 1 + if c.Deref(fmt) == 108: + is_long_long = 1 + is_long = 0 + fmt += 1 + elif c.Deref(fmt) == 104: + is_short = 1 + fmt += 1 + if c.Deref(fmt) == 104: + is_char = 1 + is_short = 0 + fmt += 1 + elif c.Deref(fmt) == 122: + is_size = 1 + fmt += 1 + elif c.Deref(fmt) == 106: + is_long_long = 1 + fmt += 1 + elif c.Deref(fmt) == 116: + is_long = 1 + fmt += 1 + if c.Deref(fmt) == 99: + if write_count < size - 1: + ptr_i: t.CInt = va_arg(ap) + ptr[0] = t.CChar(ptr_i) + write_count += 1 + ptr += _step + else: + ptr_i: t.CInt = va_arg(ap) + elif c.Deref(fmt) == 115: + s: str = va_arg(ap, t.CPtr) + if s is None: s = "(None)" + slen: t.CInt = 0 + sc: str = s + while c.Deref(sc) != 0: + slen += 1 + sc += 1 + if not left_align and width > slen: + pad_count: t.CInt = width - slen + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + while c.Deref(s) != 0 and write_count < size - 1: + ptr[0] = c.Deref(s) + write_count += 1 + ptr += _step + s += 1 + if left_align and width > slen: + pad_count = width - slen + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 100 or c.Deref(fmt) == 105: + if is_long_long or is_size or is_long: + num_l: t.CInt64T = va_arg(ap, t.CInt64T) + else: + num_l: t.CInt64T = t.CInt64T(va_arg(ap, t.CInt)) + if is_char: + num_l = t.CInt64T(t.CChar(num_l)) + elif is_short: + num_l = t.CInt64T(t.CShort(num_l)) + sign: t.CInt = 0 + if num_l < 0: + sign = 1 + if num_l == (-9223372036854775807 - 1): + u_num: t.CUInt64T = t.CUInt64T(0x8000000000000000) + else: + u_num: t.CUInt64T = t.CUInt64T(-num_l) + else: + u_num: t.CUInt64T = t.CUInt64T(num_l) + if show_sign: sign = 2 + elif space_sign: sign = 3 + i: t.CInt = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num % 10 + 48) + i += 1 + u_num //= 10 + if u_num <= 0: break + if sign == 1 and i < TEMP_BUF_SIZE - 1: + temp[i] = 45 + i += 1 + elif sign == 2 and i < TEMP_BUF_SIZE - 1: + temp[i] = 43 + i += 1 + elif sign == 3 and i < TEMP_BUF_SIZE - 1: + temp[i] = 32 + i += 1 + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 117: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num_l % 10 + 48) + i += 1 + u_num_l //= 10 + if u_num_l <= 0: break + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 120: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + is_nonzero: t.CInt = 0 + if u_num_l != 0: + is_nonzero = 1 + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + digit: t.CInt = t.CInt(u_num_l % 16) + if digit < 10: + temp[i] = t.CChar(digit + 48) + else: + temp[i] = t.CChar(digit - 10 + 97) + u_num_l //= 16 + i += 1 + if u_num_l <= 0: break + digit_count: t.CInt = i + prefix_len: t.CInt = 0 + if alt_form and is_nonzero: + prefix_len = 2 + effective_len: t.CInt = digit_count + prefix_len + if not left_align and not pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if prefix_len > 0: + if write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 120 + write_count += 1 + ptr += _step + if pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 88: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + is_nonzero = 0 + if u_num_l != 0: + is_nonzero = 1 + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + digit = t.CInt(u_num_l % 16) + if digit < 10: + temp[i] = t.CChar(digit + 48) + else: + temp[i] = t.CChar(digit - 10 + 65) + u_num_l //= 16 + i += 1 + if u_num_l <= 0: break + digit_count = i + prefix_len = 0 + if alt_form and is_nonzero: + prefix_len = 2 + effective_len = digit_count + prefix_len + if not left_align and not pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if prefix_len > 0: + if write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 88 + write_count += 1 + ptr += _step + if pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 111: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + if is_char: + u_num_l = t.CUInt64T(t.CChar(u_num_l)) + elif is_short: + u_num_l = t.CUInt64T(t.CShort(u_num_l)) + i = 0 + if u_num_l == 0 and not alt_form: + temp[0] = 48 + i = 1 + else: + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num_l % 8 + 48) + i += 1 + u_num_l //= 8 + if u_num_l <= 0: break + if alt_form and i < TEMP_BUF_SIZE - 1: + temp[i] = 48 + i += 1 + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 98: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + if is_char: + u_num_l = t.CUInt64T(t.CChar(u_num_l)) + elif is_short: + u_num_l = t.CUInt64T(t.CShort(u_num_l)) + i = 0 + if u_num_l == 0: + temp[0] = 48 + i = 1 + else: + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num_l % 2 + 48) + i += 1 + u_num_l //= 2 + if u_num_l <= 0: break + if alt_form and i < TEMP_BUF_SIZE - 1: + temp[i] = 98 + i += 1 + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 112: + ptr_val: t.CUInt64T = t.CUInt64T(va_arg(ap, t.CPtr)) + if ptr_val == 0: + temp[0] = 40 + temp[1] = 110 + temp[2] = 105 + temp[3] = 108 + temp[4] = 41 + i = 5 + else: + u_num_l = ptr_val + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + digit = t.CInt(u_num_l % 16) + if digit < 10: + temp[i] = t.CChar(digit + 48) + else: + temp[i] = t.CChar(digit - 10 + 97) + u_num_l //= 16 + i += 1 + if u_num_l <= 0: break + if i < TEMP_BUF_SIZE - 1: + temp[i] = 120 + i += 1 + if i < TEMP_BUF_SIZE - 1: + temp[i] = 48 + i += 1 + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 102 or c.Deref(fmt) == 70: + f_upper: t.CInt = 1 if c.Deref(fmt) == 70 else 0 + if precision < 0: precision = 6 + fv: t.CDouble = va_arg(ap, t.CDouble) + f_sp: t.CInt = _check_special_float(fv) + if f_sp != 0: + f_sgn_len: t.CInt = 0 + if f_sp == 2: + f_sgn_len = 1 + elif f_sp == 1 and show_sign: + f_sgn_len = 1 + elif f_sp == 1 and space_sign: + f_sgn_len = 1 + f_total_len: t.CInt = f_sgn_len + 3 + if not left_align and width > f_total_len: + f_pad: t.CInt = width - f_total_len + while f_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + f_pad -= 1 + if f_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif f_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif f_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + fi_c: t.CInt = 0 + while fi_c < 3 and write_count < size - 1: + fc: t.CInt = 0 + if f_sp == 3: + # nan + if fi_c == 0: + fc = 110 + elif fi_c == 1: + fc = 97 + else: + fc = 110 + else: + # inf (f_sp==1 +inf 或 f_sp==2 -inf) + if fi_c == 0: + fc = 105 + elif fi_c == 1: + fc = 110 + else: + fc = 102 + if f_upper and fc >= 97 and fc <= 122: + fc -= 32 + ptr[0] = t.CChar(fc) + write_count += 1 + ptr += _step + fi_c += 1 + if left_align and width > f_total_len: + f_pad = width - f_total_len + while f_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + f_pad -= 1 + fmt += 1 + continue + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + di: t.CInt = 0 + work: t.CDouble = fv + if work < 1.0: + temp[0] = 48 + di = 1 + else: + scale: t.CDouble = 1.0 + while work >= scale * 10.0: + scale *= 10.0 + while scale >= 1.0 and di < TEMP_BUF_SIZE - 1: + d: t.CInt = t.CInt(work / scale) + if d > 9: d = 9 + temp[di] = t.CChar(d + 48) + di += 1 + work = work - t.CDouble(d) * scale + scale /= 10.0 + frac_val: t.CDouble = work + p: t.CInt = 0 + while p < precision: + frac_val *= 10.0 + p += 1 + frac_part: t.CUInt64T = t.CUInt64T(frac_val + 0.5) + f_total: t.CInt = di + (precision + 1 if precision > 0 else 0) + if not left_align and not pad_zero and width > f_total: + pad_count = width - f_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > f_total: + pad_count = width - f_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while di > 0 and write_count < size - 1: + di -= 1 + ptr[0] = temp[di] + write_count += 1 + ptr += _step + if precision > 0: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + fi: t.CInt = 0 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = t.CChar(frac_part % 10 + 48) + fi += 1 + frac_part //= 10 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = 48 + fi += 1 + while fi > 0 and write_count < size - 1: + fi -= 1 + ptr[0] = temp[fi] + write_count += 1 + ptr += _step + elif alt_form: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + if left_align and width > f_total: + pad_count = width - f_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 101 or c.Deref(fmt) == 69: + if precision < 0: precision = 6 + fv: t.CDouble = va_arg(ap, t.CDouble) + e_upper: t.CInt = 1 if c.Deref(fmt) == 69 else 0 + e_sp: t.CInt = _check_special_float(fv) + if e_sp != 0: + e_sgn_len: t.CInt = 0 + if e_sp == 2: + e_sgn_len = 1 + elif e_sp == 1 and show_sign: + e_sgn_len = 1 + elif e_sp == 1 and space_sign: + e_sgn_len = 1 + e_total_len: t.CInt = e_sgn_len + 3 + if not left_align and width > e_total_len: + e_pad: t.CInt = width - e_total_len + while e_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + e_pad -= 1 + if e_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif e_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif e_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + ei_c: t.CInt = 0 + while ei_c < 3 and write_count < size - 1: + ec: t.CInt = 0 + if e_sp == 3: + # nan + if ei_c == 0: + ec = 110 + elif ei_c == 1: + ec = 97 + else: + ec = 110 + else: + # inf (e_sp==1 +inf 或 e_sp==2 -inf) + if ei_c == 0: + ec = 105 + elif ei_c == 1: + ec = 110 + else: + ec = 102 + if e_upper and ec >= 97 and ec <= 122: + ec -= 32 + ptr[0] = t.CChar(ec) + write_count += 1 + ptr += _step + ei_c += 1 + if left_align and width > e_total_len: + e_pad = width - e_total_len + while e_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + e_pad -= 1 + fmt += 1 + continue + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + exp10: t.CInt = 0 + if fv != 0.0: + while fv >= 10.0: + fv /= 10.0 + exp10 += 1 + while fv < 1.0: + fv *= 10.0 + exp10 -= 1 + int_digit: t.CInt = t.CInt(fv) + if int_digit > 9: int_digit = 9 + if int_digit < 0: int_digit = 0 + frac_v: t.CDouble = fv - t.CDouble(int_digit) + p: t.CInt = 0 + while p < precision: + frac_v *= 10.0 + p += 1 + frac_p: t.CUInt64T = t.CUInt64T(frac_v + 0.5) + carry: t.CUInt64T = 1 + p = 0 + while p < precision: + carry *= 10 + p += 1 + if frac_p >= carry and carry > 0: + frac_p = 0 + int_digit += 1 + if int_digit > 9: + int_digit = 1 + exp10 += 1 + e_total: t.CInt = 1 + (precision + 1 if precision > 0 else 0) + 4 + if not left_align and not pad_zero and width > e_total: + pad_count = width - e_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > e_total: + pad_count = width - e_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + if write_count < size - 1: + ptr[0] = t.CChar(int_digit + 48) + write_count += 1 + ptr += _step + if precision > 0: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + fi: t.CInt = 0 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = t.CChar(frac_p % 10 + 48) + fi += 1 + frac_p //= 10 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = 48 + fi += 1 + while fi > 0 and write_count < size - 1: + fi -= 1 + ptr[0] = temp[fi] + write_count += 1 + ptr += _step + elif alt_form: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 101 if e_upper == 0 else 69 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 45 if exp10 < 0 else 43 + write_count += 1 + ptr += _step + exp_abs: t.CUInt64T = t.CUInt64T(exp10) if exp10 >= 0 else t.CUInt64T(0 - exp10) + ei: t.CInt = 0 + if exp_abs == 0: + temp[0] = 48 + temp[1] = 48 + ei = 2 + else: + while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: + temp[ei] = t.CChar(exp_abs % 10 + 48) + ei += 1 + exp_abs //= 10 + while ei < 2: + temp[ei] = 48 + ei += 1 + while ei > 0 and write_count < size - 1: + ei -= 1 + ptr[0] = temp[ei] + write_count += 1 + ptr += _step + if left_align and width > e_total: + pad_count = width - e_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 103 or c.Deref(fmt) == 71: + if precision < 0: precision = 6 + if precision == 0: precision = 1 + fv: t.CDouble = va_arg(ap, t.CDouble) + g_upper: t.CInt = 1 if c.Deref(fmt) == 71 else 0 + g_sp: t.CInt = _check_special_float(fv) + if g_sp != 0: + g_sgn_len: t.CInt = 0 + if g_sp == 2: + g_sgn_len = 1 + elif g_sp == 1 and show_sign: + g_sgn_len = 1 + elif g_sp == 1 and space_sign: + g_sgn_len = 1 + g_total_len: t.CInt = g_sgn_len + 3 + if not left_align and width > g_total_len: + g_pad: t.CInt = width - g_total_len + while g_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + g_pad -= 1 + if g_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif g_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif g_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + gi_c: t.CInt = 0 + while gi_c < 3 and write_count < size - 1: + gc: t.CInt = 0 + if g_sp == 3: + # nan + if gi_c == 0: + gc = 110 + elif gi_c == 1: + gc = 97 + else: + gc = 110 + else: + # inf (g_sp==1 +inf 或 g_sp==2 -inf) + if gi_c == 0: + gc = 105 + elif gi_c == 1: + gc = 110 + else: + gc = 102 + if g_upper and gc >= 97 and gc <= 122: + gc -= 32 + ptr[0] = t.CChar(gc) + write_count += 1 + ptr += _step + gi_c += 1 + if left_align and width > g_total_len: + g_pad = width - g_total_len + while g_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + g_pad -= 1 + fmt += 1 + continue + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + fv_orig: t.CDouble = fv + exp10: t.CInt = 0 + if fv != 0.0: + while fv >= 10.0: + fv /= 10.0 + exp10 += 1 + while fv < 1.0: + fv *= 10.0 + exp10 -= 1 + g_use_e: t.CInt = 0 + if exp10 < -4 or exp10 >= precision: + g_use_e = 1 + g_len: t.CInt = 0 + if g_use_e: + int_digit: t.CInt = t.CInt(fv) + if int_digit > 9: int_digit = 9 + if int_digit < 0: int_digit = 0 + frac_v: t.CDouble = fv - t.CDouble(int_digit) + prec_e: t.CInt = precision - 1 + p: t.CInt = 0 + while p < prec_e: + frac_v *= 10.0 + p += 1 + frac_p: t.CUInt64T = t.CUInt64T(frac_v + 0.5) + carry: t.CUInt64T = 1 + p = 0 + while p < prec_e: + carry *= 10 + p += 1 + if frac_p >= carry and carry > 0: + frac_p = 0 + int_digit += 1 + if int_digit > 9: + int_digit = 1 + exp10 += 1 + temp[0] = t.CChar(int_digit + 48) + g_len = 1 + if prec_e > 0: + temp[1] = 46 + g_len = 2 + # 小数位逆序存入(个位放 g_len+prec_e-1),temp 直接为正序。 + # 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654), + # 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。 + fi: t.CInt = 0 + fp_inv: t.CUInt64T = frac_p + fp_idx: t.CInt = g_len + prec_e - 1 + while fi < prec_e and fp_idx < TEMP_BUF_SIZE - 1: + temp[fp_idx] = t.CChar(fp_inv % 10 + 48) + fp_idx -= 1 + fp_inv //= 10 + fi += 1 + g_len += prec_e + else: + prec_f: t.CInt = precision - 1 - exp10 + if prec_f < 0: prec_f = 0 + work: t.CDouble = fv_orig + if work < 1.0: + temp[0] = 48 + g_len = 1 + else: + scale: t.CDouble = 1.0 + while work >= scale * 10.0: + scale *= 10.0 + while scale >= 1.0 and g_len < TEMP_BUF_SIZE - 1: + d: t.CInt = t.CInt(work / scale) + if d > 9: d = 9 + temp[g_len] = t.CChar(d + 48) + g_len += 1 + work = work - t.CDouble(d) * scale + scale /= 10.0 + if prec_f > 0 and g_len < TEMP_BUF_SIZE - 1: + temp[g_len] = 46 + g_len += 1 + frac_val: t.CDouble = work + p = 0 + while p < prec_f: + frac_val *= 10.0 + p += 1 + frac_part: t.CUInt64T = t.CUInt64T(frac_val + 0.5) + # 小数位逆序存入(个位放 g_len+prec_f-1),temp 直接为正序。 + # 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654), + # 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。 + fi = 0 + fp_inv: t.CUInt64T = frac_part + fp_idx: t.CInt = g_len + prec_f - 1 + while fi < prec_f and fp_idx < TEMP_BUF_SIZE - 1: + temp[fp_idx] = t.CChar(fp_inv % 10 + 48) + fp_idx -= 1 + fp_inv //= 10 + fi += 1 + g_len += prec_f + if not alt_form and g_len > 0: + while g_len > 0: + if temp[g_len - 1] == 48: + g_len -= 1 + else: + break + if g_len > 0 and temp[g_len - 1] == 46: + g_len -= 1 + g_total: t.CInt = g_len + if g_use_e: g_total = g_len + 4 + if not left_align and not pad_zero and width > g_total: + pad_count = width - g_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > g_total: + pad_count = width - g_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + gi: t.CInt = 0 + while gi < g_len and write_count < size - 1: + ptr[0] = temp[gi] + write_count += 1 + ptr += _step + gi += 1 + if g_use_e: + if write_count < size - 1: + ptr[0] = 101 if g_upper == 0 else 69 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 45 if exp10 < 0 else 43 + write_count += 1 + ptr += _step + exp_abs: t.CUInt64T = t.CUInt64T(exp10) if exp10 >= 0 else t.CUInt64T(0 - exp10) + ei: t.CInt = 0 + if exp_abs == 0: + temp[0] = 48 + temp[1] = 48 + ei = 2 + else: + while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: + temp[ei] = t.CChar(exp_abs % 10 + 48) + ei += 1 + exp_abs //= 10 + while ei < 2: + temp[ei] = 48 + ei += 1 + while ei > 0 and write_count < size - 1: + ei -= 1 + ptr[0] = temp[ei] + write_count += 1 + ptr += _step + if left_align and width > g_total: + pad_count = width - g_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 97 or c.Deref(fmt) == 65: + a_upper: t.CInt = 1 if c.Deref(fmt) == 65 else 0 + fv: t.CDouble = va_arg(ap, t.CDouble) + a_sp: t.CInt = _check_special_float(fv) + if a_sp != 0: + a_sgn_len: t.CInt = 0 + if a_sp == 2: + a_sgn_len = 1 + elif a_sp == 1 and show_sign: + a_sgn_len = 1 + elif a_sp == 1 and space_sign: + a_sgn_len = 1 + a_total_len: t.CInt = a_sgn_len + 3 + if not left_align and width > a_total_len: + a_pad: t.CInt = width - a_total_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + if a_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif a_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif a_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + ai_c: t.CInt = 0 + while ai_c < 3 and write_count < size - 1: + ac: t.CInt = 0 + if a_sp == 3: + # nan + if ai_c == 0: + ac = 110 + elif ai_c == 1: + ac = 97 + else: + ac = 110 + else: + # inf (a_sp==1 +inf 或 a_sp==2 -inf) + if ai_c == 0: + ac = 105 + elif ai_c == 1: + ac = 110 + else: + ac = 102 + if a_upper and ac >= 97 and ac <= 122: + ac -= 32 + ptr[0] = t.CChar(ac) + write_count += 1 + ptr += _step + ai_c += 1 + if left_align and width > a_total_len: + a_pad = width - a_total_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + fmt += 1 + continue + fbits: t.CUInt64T = 0 + c.Load(c.Addr(fbits), c.Addr(fv)) + a_neg: t.CInt = 1 if (fbits >> 63) != 0 else 0 + a_exp: t.CInt = t.CInt((fbits >> 52) & 0x7FF) + a_frac: t.CUInt64T = fbits & 0x000FFFFFFFFFFFFF + a_leading: t.CInt = 0 + a_binexp: t.CInt = 0 + if a_exp == 0: + a_leading = 0 + if a_frac == 0: + a_binexp = 0 + else: + a_binexp = -1022 + else: + a_leading = 1 + a_binexp = a_exp - 1023 + a_prec: t.CInt = precision + if a_prec < 0: + a_prec = 13 + if a_prec > 50: + a_prec = 50 + a_hi: t.CInt = 0 + while a_hi < 13 and a_hi < a_prec: + a_digit: t.CInt = t.CInt((a_frac >> (48 - 4 * a_hi)) & 0xF) + if a_digit < 10: + temp[a_hi] = t.CChar(a_digit + 48) + else: + if a_upper: + temp[a_hi] = t.CChar(a_digit - 10 + 65) + else: + temp[a_hi] = t.CChar(a_digit - 10 + 97) + a_hi += 1 + while a_hi < a_prec: + temp[a_hi] = 48 + a_hi += 1 + a_hd_count: t.CInt = a_prec + if precision < 0: + while a_hd_count > 0 and temp[a_hd_count - 1] == 48: + a_hd_count -= 1 + a_has_dot: t.CInt = 0 + if a_hd_count > 0: + a_has_dot = 1 + elif alt_form: + a_has_dot = 1 + a_eb: t.CInt = a_binexp + a_esign: t.CInt = 0 + if a_binexp < 0: + a_esign = 1 + a_eb = -a_binexp + a_ei: t.CInt = 0 + if a_eb == 0: + temp[60] = 48 + a_ei = 1 + else: + while a_eb > 0 and a_ei < 7: + temp[60 + a_ei] = t.CChar(a_eb % 10 + 48) + a_ei += 1 + a_eb //= 10 + a_ecount: t.CInt = a_ei + a_sign_len: t.CInt = 0 + if a_neg: + a_sign_len = 1 + elif show_sign: + a_sign_len = 1 + elif space_sign: + a_sign_len = 1 + a_content_len: t.CInt = a_sign_len + 2 + 1 + a_has_dot + a_hd_count + 1 + 1 + a_ecount + if not left_align and not pad_zero and width > a_content_len: + a_pad = width - a_content_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + if a_neg: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + if pad_zero and width > a_content_len: + a_pad = width - a_content_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + a_pad -= 1 + if write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + if write_count < size - 1: + if a_upper: + ptr[0] = 88 + else: + ptr[0] = 120 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = t.CChar(a_leading + 48) + write_count += 1 + ptr += _step + if a_has_dot: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + a_hj: t.CInt = 0 + while a_hj < a_hd_count and write_count < size - 1: + ptr[0] = temp[a_hj] + write_count += 1 + ptr += _step + a_hj += 1 + if write_count < size - 1: + if a_upper: + ptr[0] = 80 + else: + ptr[0] = 112 + write_count += 1 + ptr += _step + if write_count < size - 1: + if a_esign: + ptr[0] = 45 + else: + ptr[0] = 43 + write_count += 1 + ptr += _step + a_ek: t.CInt = a_ecount + while a_ek > 0 and write_count < size - 1: + a_ek -= 1 + ptr[0] = temp[60 + a_ek] + write_count += 1 + ptr += _step + if left_align and width > a_content_len: + a_pad = width - a_content_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + elif c.Deref(fmt) == 110: + if is_long_long or is_long: + np: t.CInt64T | t.CPtr = va_arg(ap, t.CInt64T | t.CPtr) + if np != None: + np[0] = t.CInt64T(write_count) + elif is_short: + sp: t.CShort | t.CPtr = va_arg(ap, t.CShort | t.CPtr) + if sp != None: + sp[0] = t.CShort(write_count) + elif is_char: + cp: t.CChar | t.CPtr = va_arg(ap, t.CChar | t.CPtr) + if cp != None: + cp[0] = t.CChar(write_count) + else: + ip: t.CInt | t.CPtr = va_arg(ap, t.CInt | t.CPtr) + if ip != None: + ip[0] = write_count + elif c.Deref(fmt) == 37: + if write_count < size - 1: + ptr[0] = 37 + write_count += 1 + ptr += _step + else: + if write_count < size - 1: + ptr[0] = c.Deref(fmt) + write_count += 1 + ptr += _step + fmt += 1 + ptr[0] = 0 + return write_count diff --git a/vipermath.vp b/vipermath.vp new file mode 100644 index 0000000..b121af1 --- /dev/null +++ b/vipermath.vp @@ -0,0 +1,544 @@ +import t, c + + +U_M_PI: t.CDefine = 3.14159265358979323846 +U_M_E: t.CDefine = 2.71828182845904523536 +U_M_PI_2: t.CDefine = 1.57079632679489661923 +U_M_PI_4: t.CDefine = 0.78539816339744830962 +U_M_1_PI: t.CDefine = 0.31830988618379067154 +U_M_2_PI: t.CDefine = 0.63661977236758134308 + +U_M_LN2: t.CDefine = 0.69314718055994530942 +U_M_LN10: t.CDefine = 2.30258509299404568402 + +U_M_2_SQRT_PI: t.CDefine = 1.77245385090551602730 + +def radians(degrees: t.CDouble) -> t.CDouble: + return degrees * (U_M_PI / t.CDouble(180.0)) + +def degrees(radians: t.CDouble) -> t.CDouble: + return radians * (t.CDouble(180.0) / U_M_PI) + +def sin(x: t.CDouble) -> t.CDouble: + while x > U_M_PI: + x -= t.CDouble(2.0) * U_M_PI + while x < -U_M_PI: + x += t.CDouble(2.0) * U_M_PI + x2: t.CDouble = x * x + result: t.CDouble = x + term: t.CDouble = x + term = term * x2 / t.CDouble(6.0) + result = result - term + term = term * x2 / t.CDouble(20.0) + result = result + term + term = term * x2 / t.CDouble(42.0) + result = result - term + term = term * x2 / t.CDouble(72.0) + result = result + term + term = term * x2 / t.CDouble(110.0) + result = result - term + term = term * x2 / t.CDouble(156.0) + result = result + term + term = term * x2 / t.CDouble(210.0) + result = result - term + term = term * x2 / t.CDouble(272.0) + result = result + term + return result + + +def cos(x: t.CDouble) -> t.CDouble: + while x > U_M_PI: + x -= t.CDouble(2.0) * U_M_PI + while x < -U_M_PI: + x += t.CDouble(2.0) * U_M_PI + x2: t.CDouble = x * x + result: t.CDouble = t.CDouble(1.0) + term: t.CDouble = t.CDouble(1.0) + term = term * x2 / t.CDouble(2.0) + result = result - term + term = term * x2 / t.CDouble(12.0) + result = result + term + term = term * x2 / t.CDouble(30.0) + result = result - term + term = term * x2 / t.CDouble(56.0) + result = result + term + term = term * x2 / t.CDouble(90.0) + result = result - term + term = term * x2 / t.CDouble(132.0) + result = result + term + term = term * x2 / t.CDouble(182.0) + result = result - term + term = term * x2 / t.CDouble(240.0) + result = result + term + return result + + +def tan(x: t.CDouble) -> t.CDouble: + return sin(x) / cos(x) + + +def asin(x: t.CDouble) -> t.CDouble: + if x > t.CDouble(1.0): + x = t.CDouble(1.0) + if x < t.CDouble(-1.0): + x = t.CDouble(-1.0) + x2: t.CDouble = x * x + result: t.CDouble = x + result += x * x2 / t.CDouble(6.0) + result += t.CDouble(3.0) * x * x2 * x2 / t.CDouble(40.0) + result += t.CDouble(5.0) * x * x2 * x2 * x2 / t.CDouble(112.0) + result += t.CDouble(35.0) * x * x2 * x2 * x2 * x2 / t.CDouble(1152.0) + result += t.CDouble(63.0) * x * x2 * x2 * x2 * x2 * x2 / t.CDouble(2816.0) + return result + + +def acos(x: t.CDouble) -> t.CDouble: + return U_M_PI / t.CDouble(2.0) - asin(x) + + +def _atan_core(x: t.CDouble) -> t.CDouble: + x2: t.CDouble = x * x + result: t.CDouble = x + term: t.CDouble = x + term = term * x2 / t.CDouble(3.0) + result = result - term + term = term * x2 / t.CDouble(5.0) + result = result + term + term = term * x2 / t.CDouble(7.0) + result = result - term + term = term * x2 / t.CDouble(9.0) + result = result + term + term = term * x2 / t.CDouble(11.0) + result = result - term + term = term * x2 / t.CDouble(13.0) + result = result + term + term = term * x2 / t.CDouble(15.0) + result = result - term + term = term * x2 / t.CDouble(17.0) + result = result + term + term = term * x2 / t.CDouble(19.0) + result = result - term + term = term * x2 / t.CDouble(21.0) + result = result + term + return result + + +def atan(x: t.CDouble) -> t.CDouble: + ax: t.CDouble = x + if ax < t.CDouble(0.0): + ax = -ax + if ax > t.CDouble(1.0): + return t.CDouble(0.0) - _atan_core(t.CDouble(1.0) / ax) + U_M_PI_2 if x > t.CDouble(0.0) else _atan_core(t.CDouble(1.0) / ax) - U_M_PI_2 + return _atan_core(x) if x >= t.CDouble(0.0) else t.CDouble(0.0) - _atan_core(ax) + + +def atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble: + if x > t.CDouble(0.0): + return atan(y / x) + elif x < t.CDouble(0.0): + if y >= t.CDouble(0.0): + return atan(y / x) + U_M_PI + else: + return atan(y / x) - U_M_PI + else: + if y > t.CDouble(0.0): + return U_M_PI_2 + elif y < t.CDouble(0.0): + return t.CDouble(0.0) - U_M_PI_2 + else: + return t.CDouble(0.0) + + +def sinh(x: t.CDouble) -> t.CDouble: + ex: t.CDouble = exp(x) + e_negx: t.CDouble = exp(-x) + return (ex - e_negx) / t.CDouble(2.0) + + +def cosh(x: t.CDouble) -> t.CDouble: + ex: t.CDouble = exp(x) + e_negx: t.CDouble = exp(-x) + return (ex + e_negx) / t.CDouble(2.0) + + +def tanh(x: t.CDouble) -> t.CDouble: + ex: t.CDouble = exp(x) + e_negx: t.CDouble = exp(-x) + return (ex - e_negx) / (ex + e_negx) + + +def exp(x: t.CDouble) -> t.CDouble: + if x > t.CDouble(709.0): + return t.CDouble(1.7976931348623157e308) + if x < t.CDouble(-709.0): + return t.CDouble(0.0) + result: t.CDouble = t.CDouble(1.0) + term: t.CDouble = t.CDouble(1.0) + term = term * x / t.CDouble(1.0) + result = result + term + term = term * x / t.CDouble(2.0) + result = result + term + term = term * x / t.CDouble(3.0) + result = result + term + term = term * x / t.CDouble(4.0) + result = result + term + term = term * x / t.CDouble(5.0) + result = result + term + term = term * x / t.CDouble(6.0) + result = result + term + term = term * x / t.CDouble(7.0) + result = result + term + term = term * x / t.CDouble(8.0) + result = result + term + term = term * x / t.CDouble(9.0) + result = result + term + term = term * x / t.CDouble(10.0) + result = result + term + term = term * x / t.CDouble(11.0) + result = result + term + term = term * x / t.CDouble(12.0) + result = result + term + term = term * x / t.CDouble(13.0) + result = result + term + term = term * x / t.CDouble(14.0) + result = result + term + term = term * x / t.CDouble(15.0) + result = result + term + term = term * x / t.CDouble(16.0) + result = result + term + term = term * x / t.CDouble(17.0) + result = result + term + term = term * x / t.CDouble(18.0) + result = result + term + return result + + +def log(x: t.CDouble) -> t.CDouble: + if x <= t.CDouble(0.0): + return t.CDouble(-1e308) + exponent: t.CInt = 0 + while x >= t.CDouble(2.0): + x /= t.CDouble(2.0) + exponent += 1 + while x < t.CDouble(1.0): + x *= t.CDouble(2.0) + exponent -= 1 + y: t.CDouble = (x - t.CDouble(1.0)) / (x + t.CDouble(1.0)) + y2: t.CDouble = y * y + result: t.CDouble = t.CDouble(2.0) * y + term: t.CDouble = t.CDouble(2.0) * y + term = term * y2 + result = result + term / t.CDouble(3.0) + term = term * y2 + result = result + term / t.CDouble(5.0) + term = term * y2 + result = result + term / t.CDouble(7.0) + term = term * y2 + result = result + term / t.CDouble(9.0) + term = term * y2 + result = result + term / t.CDouble(11.0) + term = term * y2 + result = result + term / t.CDouble(13.0) + term = term * y2 + result = result + term / t.CDouble(15.0) + term = term * y2 + result = result + term / t.CDouble(17.0) + term = term * y2 + result = result + term / t.CDouble(19.0) + term = term * y2 + result = result + term / t.CDouble(21.0) + result += t.CDouble(exponent) * U_M_LN2 + return result + + +def sqrt(x: t.CDouble) -> t.CDouble: + if x < t.CDouble(0.0): + return t.CDouble(0.0) + if x == t.CDouble(0.0): + return t.CDouble(0.0) + guess: t.CDouble = x / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + return guess + + +def abs(x: t.CInt) -> t.CInt: + return x if x >= 0 else -x + +def fabs(x: t.CDouble) -> t.CDouble: + return x if x >= t.CDouble(0.0) else -x + +def labs(x: t.CLong) -> t.CLong: + return x if x >= 0 else -x + +def factorial(n: t.CInt) -> t.CDouble: + if n < 0: return t.CDouble(0.0) + if n == 0 or n == 1: return t.CDouble(1.0) + result: t.CDouble = t.CDouble(1.0) + for i in range(2, n + 1): + result *= i + return result + + +def combination(n: t.CInt, k: t.CInt) -> t.CDouble: + if k < 0 or k > n: return t.CDouble(0.0) + if k == 0 or k == n: return t.CDouble(1.0) + k = k if k < n - k else n - k + result: t.CDouble = t.CDouble(1.0) + for i in range(1, k + 1): + result = result * (n - k + i) / i + return result + + +def permutation(n: t.CInt, k: t.CInt) -> t.CDouble: + if k < 0 or k > n: return t.CDouble(0.0) + result: t.CDouble = t.CDouble(1.0) + for i in range(0, k): + result *= (n - i) + return result + +def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: + if x == t.CDouble(0.0): + if y > t.CDouble(0.0): + return t.CDouble(0.0) + return t.CDouble(1.0) + if x < t.CDouble(0.0): + iy: t.CDouble = y * log(-x) + return exp(iy) + return exp(y * log(x)) + + +def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble: + return pow(x, y) + + +def cbrt(x: t.CDouble) -> t.CDouble: + return pow(x, t.CDouble(1.0) / t.CDouble(3.0)) + +def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble: + return sqrt(x * x + y * y) + + +def floor(x: t.CDouble) -> t.CDouble: + if x >= t.CDouble(0.0): + return t.CDouble(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x < t.CDouble(i): + return t.CDouble(i - 1) + else: + return t.CDouble(i) + + +def ceil(x: t.CDouble) -> t.CDouble: + if x < t.CDouble(0.0): + return t.CDouble(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x > t.CDouble(i): + return t.CDouble(i + 1) + else: + return t.CDouble(i) + + +def round(x: t.CDouble) -> t.CDouble: + return floor(x + t.CDouble(0.5)) + +def trunc(x: t.CDouble) -> t.CDouble: + if x >= t.CDouble(0.0): + return floor(x) + else: + return ceil(x) + + +def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble: + if y == t.CDouble(0.0): + return t.CDouble(0.0) + result: t.CDouble = x - y * floor(x / y) + if result < t.CDouble(0.0): + result += y + return result + + +def fmodf(x: float, y: float) -> float: + if y == float(0.0): + return float(0.0) + result: float = x - y * floorf(x / y) + if result < float(0.0): + result += y + return result + + +def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble: + int_part: t.CDouble = floor(x) + # c.Set(a, b) = a = b:a 为 c.Deref(iptr) 左值表达式 → *iptr = int_part + # TPV 的 c.Deref 立即 load 返回右值,故 c.Set 需识别 Deref 左值形态(translate_c_set 形态 1) + c.Set(c.Deref(iptr), int_part) + return x - int_part + + +def log10(x: t.CDouble) -> t.CDouble: + return log(x) / U_M_LN10 + + +def log2(x: t.CDouble) -> t.CDouble: + return log(x) / U_M_LN2 + + +def exp2(x: t.CDouble) -> t.CDouble: + return pow(t.CDouble(2.0), x) + + +def expm1(x: t.CDouble) -> t.CDouble: + return exp(x) - t.CDouble(1.0) + + +def log1p(x: t.CDouble) -> t.CDouble: + return log(t.CDouble(1.0) + x) + + +def asinh(x: t.CDouble) -> t.CDouble: + return log(x + sqrt(x * x + t.CDouble(1.0))) + +def acosh(x: t.CDouble) -> t.CDouble: + return log(x + sqrt(x * x - t.CDouble(1.0))) + +def atanh(x: t.CDouble) -> t.CDouble: + return (log(t.CDouble(1.0) + x) - log(t.CDouble(1.0) - x)) / t.CDouble(2.0) + + +def gamma(x: t.CDouble) -> t.CDouble: + if x <= t.CDouble(0.0): return t.CDouble(0.0) + if x == t.CDouble(1.0) or x == t.CDouble(2.0): return t.CDouble(1.0) + ln_gamma: t.CDouble = t.CDouble(0.5) * log(t.CDouble(2.0) * U_M_PI / x) + x * log(x / U_M_E) + return exp(ln_gamma) + + +def erf(x: t.CDouble) -> t.CDouble: + sign: t.CDouble = t.CDouble(1.0) if x >= t.CDouble(0.0) else t.CDouble(-1.0) + abs_x: t.CDouble = fabs(x) + t0: t.CDouble = t.CDouble(4.0) * abs_x * abs_x / U_M_PI + exp_term: t.CDouble = exp(-t0) + return sign * sqrt(t.CDouble(1.0) - exp_term) + + +def erfc(x: t.CDouble) -> t.CDouble: + return t.CDouble(1.0) - erf(x) + +def sqrtf(x: t.CFloat) -> t.CFloat: + if x < t.CFloat(0.0): + return t.CFloat(0.0) + if x == t.CFloat(0.0): + return t.CFloat(0.0) + guess: t.CFloat = x / t.CFloat(2.0) + for i in range(10): + guess = (guess + x / guess) / t.CFloat(2.0) + return guess + +def sinf(x: t.CFloat) -> t.CFloat: + while x > t.CFloat(3.14159265): + x -= t.CFloat(6.28318530) + while x < t.CFloat(-3.14159265): + x += t.CFloat(6.28318530) + x2: t.CFloat = x * x + result: t.CFloat = x + term: t.CFloat = x + term = term * x2 / t.CFloat(6.0) + result = result - term + term = term * x2 / t.CFloat(20.0) + result = result + term + term = term * x2 / t.CFloat(42.0) + result = result - term + term = term * x2 / t.CFloat(72.0) + result = result + term + term = term * x2 / t.CFloat(110.0) + result = result - term + term = term * x2 / t.CFloat(156.0) + result = result + term + term = term * x2 / t.CFloat(210.0) + result = result - term + term = term * x2 / t.CFloat(272.0) + result = result + term + return result + +def cosf(x: t.CFloat) -> t.CFloat: + while x > t.CFloat(3.14159265): + x -= t.CFloat(6.28318530) + while x < t.CFloat(-3.14159265): + x += t.CFloat(6.28318530) + x2: t.CFloat = x * x + result: t.CFloat = t.CFloat(1.0) + term: t.CFloat = t.CFloat(1.0) + term = term * x2 / t.CFloat(2.0) + result = result - term + term = term * x2 / t.CFloat(12.0) + result = result + term + term = term * x2 / t.CFloat(30.0) + result = result - term + term = term * x2 / t.CFloat(56.0) + result = result + term + term = term * x2 / t.CFloat(90.0) + result = result - term + term = term * x2 / t.CFloat(132.0) + result = result + term + term = term * x2 / t.CFloat(182.0) + result = result - term + term = term * x2 / t.CFloat(240.0) + result = result + term + return result + +def tanf(x: t.CFloat) -> t.CFloat: + c: t.CFloat = cosf(x) + if c == t.CFloat(0.0): + return t.CFloat(0.0) + return sinf(x) / c + +def fabsf(x: t.CFloat) -> t.CFloat: + return x if x >= t.CFloat(0.0) else -x + +def floorf(x: t.CFloat) -> t.CFloat: + if x >= t.CFloat(0.0): + return t.CFloat(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x < t.CFloat(i): + return t.CFloat(i - 1) + else: + return t.CFloat(i) + +def ceilf(x: t.CFloat) -> t.CFloat: + if x < t.CFloat(0.0): + return t.CFloat(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x > t.CFloat(i): + return t.CFloat(i + 1) + else: + return t.CFloat(i) + + +class _U(t.CUnion): + d: t.CDouble + u: t.CUInt64T + +def isnan(x: t.CDouble) -> t.CStatic | t.CInt: + u: t.CUInt64T = t.CUInt64T(x) + exp_part: t.CUInt64T = (u >> 52) & 0x7FF + mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF + if exp_part == 0x7FF: + if mantissa_part != 0: + return 1 + return 0 + +def isinf(x: t.CDouble) -> t.CStatic | t.CInt: + u: t.CUInt64T = t.CUInt64T(x) + exp_part: t.CUInt64T = (u >> 52) & 0x7FF + mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF + if exp_part == 0x7FF: + if mantissa_part == 0: + return 1 + return 0 diff --git a/vipersimd.vp b/vipersimd.vp new file mode 100644 index 0000000..e567495 --- /dev/null +++ b/vipersimd.vp @@ -0,0 +1,492 @@ +import t, c + + +# ============================================================ +# AVX2 double precision vector operations (4 x double, 256-bit YMM) +# ============================================================ + +def simd_add4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] + b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vaddpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_sub4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] - b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vsubpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_mul4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] * b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmulpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_div4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] / b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vdivpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_sqrt4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = sqrt(a[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vsqrtpd ymm0, ymm0 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0']) + + +def simd_neg4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = -a[0:4] (flip sign bit via XOR)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vpcmpeqd ymm1, ymm1, ymm1 +vpsllq ymm1, ymm1, 63 +vxorpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_abs4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = |a[0:4]| (clear sign bit via ANDN)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vpcmpeqd ymm1, ymm1, ymm1 +vpsllq ymm1, ymm1, 63 +vandnpd ymm0, ymm1, ymm0 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_max4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = max(a[0:4], b[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmaxpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_min4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = min(a[0:4], b[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vminpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_mul_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] * scalar (broadcast)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vbroadcastsd ymm1, [{c.AsmInp(scalar, t.ASM_DESCR.REG_ANY)}] +vmulpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_add_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] + scalar (broadcast)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vbroadcastsd ymm1, [{c.AsmInp(scalar, t.ASM_DESCR.REG_ANY)}] +vaddpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_hsum4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0] = a[0]+a[1]+a[2]+a[3] (horizontal sum)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vextractf128 xmm1, ymm0, 1 +vaddpd xmm0, xmm0, xmm1 +vhaddpd xmm0, xmm0, xmm0 +vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_dot4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0] = dot(a[0:4], b[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmulpd ymm0, ymm0, ymm1 +vextractf128 xmm1, ymm0, 1 +vaddpd xmm0, xmm0, xmm1 +vhaddpd xmm0, xmm0, xmm0 +vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_fma4d(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4]*b[0:4] + c[0:4] (fused multiply-add) + Uses vfmadd213pd: ymm0 = ymm1 * ymm0 + ymm2 + Load order: b->ymm0, a->ymm1, c->ymm2""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm2, [{c.AsmInp(c_val, t.ASM_DESCR.REG_ANY)}] +vfmadd213pd ymm0, ymm1, ymm2 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'ymm2']) + + +# ============================================================ +# SSE2 single precision vector operations (4 x float, 128-bit XMM) +# ============================================================ + +def simd_add4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] + b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +addps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +def simd_sub4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] - b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +subps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +def simd_mul4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] * b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +mulps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +def simd_div4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] / b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +divps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +# ============================================================ +# Batch array operations (AVX2 loop, process N double values) +# ============================================================ + +def simd_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] + b[i:i+4], i=0,4,8,...""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Ladd_end +.Ladd_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vaddpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Ladd_loop +.Ladd_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_sub_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] - b[i:i+4]""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Lsub_end +.Lsub_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vsubpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Lsub_loop +.Lsub_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] * b[i:i+4]""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Lmul_end +.Lmul_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vmulpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Lmul_loop +.Lmul_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_div_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] / b[i:i+4]""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Ldiv_end +.Ldiv_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vdivpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Ldiv_loop +.Ldiv_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = sqrt(a[i:i+4])""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Lsqrt_end +.Lsqrt_loop: +vmovupd ymm0, [r8] +vsqrtpd ymm0, ymm0 +vmovupd [r10], ymm0 +add r8, 32 +add r10, 32 +dec rcx +jnz .Lsqrt_loop +.Lsqrt_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'rcx', 'r8', 'r10']) + + +def simd_abs_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = |a[i:i+4]|""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +vpcmpeqd ymm2, ymm2, ymm2 +vpsllq ymm2, ymm2, 63 +test rcx, rcx +jz .Labs_end +.Labs_loop: +vmovupd ymm0, [r8] +vandnpd ymm0, ymm2, ymm0 +vmovupd [r10], ymm0 +add r8, 32 +add r10, 32 +dec rcx +jnz .Labs_loop +.Labs_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm2', 'rcx', 'r8', 'r10']) + + +def simd_neg_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = -a[i:i+4] (flip sign bit via XOR)""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +vpcmpeqd ymm2, ymm2, ymm2 +vpsllq ymm2, ymm2, 63 +test rcx, rcx +jz .Lneg_end +.Lneg_loop: +vmovupd ymm0, [r8] +vxorpd ymm0, ymm0, ymm2 +vmovupd [r10], ymm0 +add r8, 32 +add r10, 32 +dec rcx +jnz .Lneg_loop +.Lneg_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm2', 'rcx', 'r8', 'r10']) + + +def simd_dot_array(a: t.CPtr, b: t.CPtr, n: t.CSizeT, out: t.CPtr) -> t.CVoid: + """AVX2 batch: out[0] = dot(a[0:n], b[0:n]) using FMA accumulation""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +vxorpd ymm2, ymm2, ymm2 +test rcx, rcx +jz .Ldot_end +.Ldot_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vfmadd231pd ymm2, ymm0, ymm1 +add r8, 32 +add r9, 32 +dec rcx +jnz .Ldot_loop +.Ldot_end: +vextractf128 xmm1, ymm2, 1 +vaddpd xmm2, xmm2, xmm1 +vhaddpd xmm2, xmm2, xmm2 +vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm2 +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'ymm2', 'rcx', 'r8', 'r9']) + + +# ============================================================ +# LLVMIR precise scalar operations (LLVM intrinsic functions) +# ============================================================ + +def simd_sqrt(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: sqrt(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.sqrt.f64(double {c.LInp(x)})") + return out + + +def simd_fabs(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: |x|""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.fabs.f64(double {c.LInp(x)})") + return out + + +def simd_floor(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: floor(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.floor.f64(double {c.LInp(x)})") + return out + + +def simd_ceil(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: ceil(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.ceil.f64(double {c.LInp(x)})") + return out + + +def simd_round(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: round(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.round.f64(double {c.LInp(x)})") + return out + + +def simd_trunc(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: trunc(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.trunc.f64(double {c.LInp(x)})") + return out + + +def simd_fma(a: t.CDouble, b: t.CDouble, c_val: t.CDouble) -> t.CDouble: + """LLVM intrinsic: a*b + c (single rounding)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.fma.f64(double {c.LInp(a)}, double {c.LInp(b)}, double {c.LInp(c_val)})") + return out + + +def simd_copysign(mag: t.CDouble, sign: t.CDouble) -> t.CDouble: + """LLVM intrinsic: copysign(mag, sign)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.copysign.f64(double {c.LInp(mag)}, double {c.LInp(sign)})") + return out + + +def simd_neg(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: -x (via copysign, correct for negative/-0.0/NaN inputs) + + copysign(x, -1.0) is wrong for x < 0 (returns -|x| instead of +|x|). + copysign(x, -x) = |x| * sign(-x) = -x is correct for all IEEE 754 values. + """ + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.copysign.f64(double {c.LInp(x)}, double {c.LInp(t.CDouble(0.0) - x)})") + return out + + +def simd_minnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: + """LLVM intrinsic: min(a, b) (NaN-aware)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.minnum.f64(double {c.LInp(a)}, double {c.LInp(b)})") + return out + + +def simd_maxnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: + """LLVM intrinsic: max(a, b) (NaN-aware)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.maxnum.f64(double {c.LInp(a)}, double {c.LInp(b)})") + return out + + +def simd_exp(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: e^x""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.exp.f64(double {c.LInp(x)})") + return out + + +def simd_log(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: ln(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.log.f64(double {c.LInp(x)})") + return out + + +def simd_sin(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: sin(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.sin.f64(double {c.LInp(x)})") + return out + + +def simd_cos(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: cos(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.cos.f64(double {c.LInp(x)})") + return out + + +def simd_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: + """LLVM intrinsic: x^y""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.pow.f64(double {c.LInp(x)}, double {c.LInp(y)})") + return out diff --git a/viperstring.vp b/viperstring.vp new file mode 100644 index 0000000..212d749 --- /dev/null +++ b/viperstring.vp @@ -0,0 +1 @@ +from .string import * diff --git a/vqt6 copy/CMakeLists.txt b/vqt6 copy/CMakeLists.txt new file mode 100644 index 0000000..d08d121 --- /dev/null +++ b/vqt6 copy/CMakeLists.txt @@ -0,0 +1,110 @@ +# ============================================================ +# vqt6 CMakeLists.txt — 构建 vqt6 C 桥接层 +# +# 默认产物: libvqt6_bridge.a (静态库) +# 可选产物: vqt6_bridge.dll (动态库) +# +# 使用: +# cmake -B build -S . +# cmake --build build --config Release +# ============================================================ + +cmake_minimum_required(VERSION 3.16) +project(vqt6_bridge CXX C) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) + +# 构建选项 +option(VQT6_BUILD_SHARED "Build vqt6 as shared library (DLL)" OFF) +option(VQT6_BUILD_STATIC "Build vqt6 as static library" ON) +option(VQT6_BUILD_EXAMPLES "Build example programs" OFF) + +# Qt6 依赖 +find_package(Qt6 6.5 REQUIRED COMPONENTS + Core + Gui + Widgets + Network +) + +# Win32 GUI 应用不需要控制台 +if(WIN32) + set(CMAKE_WIN32_EXECUTABLE OFF) +endif() + +# 公共源文件 +set(VQT6_SOURCES + _bridge_core.cpp + _bridge_widgets.cpp + _bridge_gui.cpp + _bridge_network.cpp +) + +set(VQT6_HEADERS + _bridge.h + _bridge_widgets.h + _bridge_gui.h + _bridge_network.h +) + +# Qt 模块 +set(VQT6_QT_MODULES + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Network +) + +# ============================================================ +# 静态库 +# ============================================================ +if(VQT6_BUILD_STATIC) + add_library(vqt6_bridge_static STATIC ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge_static PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge_static PUBLIC VQT6_BRIDGE_STATIC) + target_include_directories(vqt6_bridge_static PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge_static PROPERTIES + OUTPUT_NAME vqt6_bridge + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ) +endif() + +# ============================================================ +# 动态库 +# ============================================================ +if(VQT6_BUILD_SHARED) + add_library(vqt6_bridge SHARED ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge PRIVATE VQT6_BRIDGE_BUILD) + target_include_directories(vqt6_bridge PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + ) +endif() + +# ============================================================ +# 安装 +# ============================================================ +install(TARGETS vqt6_bridge_static vqt6_bridge + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install(FILES ${VQT6_HEADERS} + DESTINATION include/vqt6 +) + +# ============================================================ +# 示例 +# ============================================================ +if(VQT6_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/vqt6 copy/README.md b/vqt6 copy/README.md new file mode 100644 index 0000000..eba4e88 --- /dev/null +++ b/vqt6 copy/README.md @@ -0,0 +1,90 @@ +# vqt6 — Viper 的 Qt6 绑定包 + +`vqt6` 是 [Viper](https://git.gvsds.com/GVSDS/TransPyC) 语言的 **Qt6 GUI 框架绑定**,是 Viper 包管理器分发的"包"(类似于 Python 的 PyQt6、Node.js 的 node-gtk)。 + +> 注意:`vqt6` **不是** 包管理器,而是一个**被包管理器管理的包**(库)。 +> 包管理器负责下载、预编译、安装;`vqt6` 只负责把 Qt6 C++ API 暴露给 Viper 代码。 + +## 架构 + +``` ++--------------------+ +-----------------------+ +------------+ +| Viper 用户代码 | FFI | vqt6 桥接层 (libvqt6) | C++ | Qt6 C++ | +| (app.vp) | <----> | - t.State 声明 | <-----> | QtCore | +| | | - C 桥接函数 | | QtGui | +| vqt6.QApplication | | (extern "C") | | QtWidgets | +| vqt6.QLabel | | - 静态库 / 动态库 | | QtNetwork | ++--------------------+ +-----------------------+ +------------+ +``` + +**FFI 路径**: +1. Viper 编译器把 `t.State` 声明的 `def xxx() -> t.State: pass` 解析为外部函数符号 +2. 链接时通过 `libvqt6_bridge.a`(静态)或 `vqt6_bridge.dll`(动态)解析符号 +3. 运行时 C 桥接层调用 Qt6 C++ API 完成实际工作 + +## 链接模式 + +| 模式 | 产物 | 优点 | 缺点 | +|------|------|------|------| +| **静态**(默认) | `libvqt6_bridge.a` | 部署简单(一个 exe),无需分发 dll | exe 体积较大 | +| **动态** | `vqt6_bridge.dll` | 共享内存,多个程序共用 | 需随 exe 分发 dll | + +vqt6 同一套 C 桥接源代码,可同时编译为两种产物。Viper 项目通过 `project.vpj` 切换。 + +## 目录结构 + +``` +includes/vqt6/ +├── README.md # 本文件 +├── __init__.vp # 公共 Pythonic API(用户使用) +├── _types.vp # 公共类型(不透明指针 typedef) +├── _qtcore.vp # QtCore 的 t.State FFI 声明 +├── _qtwidgets.vp # QtWidgets 的 t.State FFI 声明 +├── _qtgui.vp # QtGui 的 t.State FFI 声明 +├── _qtnetwork.vp # QtNetwork 的 t.State FFI 声明 +├── _bridge.h # C 桥接层头文件 +├── _bridge.cpp # C 桥接层实现(extern "C" 包装 Qt6 C++ API) +└── CMakeLists.txt # 构建脚本(生成 libvqt6_bridge.a) +``` + +## 使用示例 + +```python +# App/main.vp +import t +import c +import vqt6 + +# 1. 创建 QApplication +app: vqt6.QApplication | t.CPtr = vqt6.QApplication([]) + +# 2. 创建窗口 +window: vqt6.QWidget | t.CPtr = vqt6.QWidget() +window.setWindowTitle("vqt6 Hello") +window.resize(400, 300) + +# 3. 创建标签 +label: vqt6.QLabel | t.CPtr = vqt6.QLabel("你好,Viper!", window) +label.move(50, 50) + +# 4. 显示并进入事件循环 +window.show() +app.exec() +``` + +## 设计原则 + +1. **不透明指针**:Viper 端不直接操作 Qt6 C++ 类(`QWidget*`、`QString*` 等),所有操作通过 C 桥接函数 `vqt6_xxx()` 转发。 +2. **t.State 声明**:所有 FFI 函数返回 `t.State`,C 桥接层函数实现负责实际操作。 +3. **句柄化对象模型**:Viper 端的对象是 `t.CPtr`(不透明指针),C 端管理生命周期(构造函数/析构函数)。 +4. **跨平台**:同一套 C 桥接代码可在 Windows / Linux / macOS 编译(差异在 Qt6 安装路径)。 + +## 当前状态 + +- [x] 架构设计 +- [x] FFI 覆盖:QtCore / QtWidgets / QtGui / QtNetwork +- [x] FFI 粒度:仅暴露 C 桥接函数 +- [ ] FFI 声明文件编写中 +- [ ] C 桥接层实现 +- [ ] CMakeLists.txt 构建脚本 +- [ ] Hello World 示例验证 diff --git a/vqt6 copy/__init__.vp b/vqt6 copy/__init__.vp new file mode 100644 index 0000000..16446c3 --- /dev/null +++ b/vqt6 copy/__init__.vp @@ -0,0 +1,208 @@ +# ============================================================ +# vqt6 — Viper 的 Qt6 绑定包 +# +# 公共 Pythonic API(基于 C 桥接层) +# 用户用法: +# import vqt6 +# app = vqt6.QApplication([]) +# win = vqt6.QWidget() +# win.setWindowTitle("Hello") +# win.show() +# app.exec() +# ============================================================ + +import t +from stdint import * +from vqt6._types import * +from vqt6._qtcore import * +from vqt6._qtwidgets import * +from vqt6._qtgui import * +from vqt6._qtnetwork import * + + +# ============================================================ +# 高级 API 类(Pythonic 包装,不透明指针) +# ============================================================ +@t.NoVTable +class QApplication: + """QApplication 包装(不透明指针)""" + _ptr: QtAppPtr + + def __init__(self, argv: list[str] | t.CPtr): + # 把 argv 转换为 argc/argv 数组 + argc: t.CInt = 1 + # Viper 端 argv 是 c_char_p 指针数组 + # 这里仅传空 argv,避免 C ABI 复杂性 + argv_ptr: t.CPtr = t.CPtr(0) + self._ptr = vqt6_qapplication_create(argc, argv_ptr) + if self._ptr is None: + raise RuntimeError("Failed to create QApplication") + + def exec(self) -> int: + return vqt6_qapplication_exec(self._ptr) + + def quit(self): + vqt6_qapplication_quit(self._ptr) + + def exit(self, code: int): + vqt6_qapplication_exit(self._ptr, code) + + def process_events(self): + vqt6_qapplication_process_events(self._ptr) + + def desktop_width(self) -> int: + return vqt6_qapplication_desktop_width(self._ptr) + + def desktop_height(self) -> int: + return vqt6_qapplication_desktop_height(self._ptr) + + +@t.NoVTable +class QWidget: + """QWidget 包装""" + _ptr: QtWidgetPtr + + def __init__(self, parent: "QWidget | None" = None): + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qwidget_create_with_parent(parent._ptr) + else: + self._ptr = vqt6_qwidget_create() + if self._ptr is None: + raise RuntimeError("Failed to create QWidget") + + def show(self): + vqt6_qwidget_show(self._ptr) + + def hide(self): + vqt6_qwidget_hide(self._ptr) + + def close(self) -> int: + return vqt6_qwidget_close(self._ptr) + + def setWindowTitle(self, title: str): + title_qs: QtStringPtr = vqt6_qstring_create(title) + vqt6_qwidget_set_window_title(self._ptr, title_qs) + vqt6_qstring_free(title_qs) + + def windowTitle(self) -> str: + result: QtStringPtr = vqt6_qwidget_window_title(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def resize(self, w: int, h: int): + vqt6_qwidget_resize(self._ptr, w, h) + + def move(self, x: int, y: int): + vqt6_qwidget_move(self._ptr, x, y) + + def setGeometry(self, x: int, y: int, w: int, h: int): + vqt6_qwidget_set_geometry(self._ptr, x, y, w, h) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + def setVisible(self, visible: int): + vqt6_qwidget_set_visible(self._ptr, visible) + + def isVisible(self) -> int: + return vqt6_qwidget_is_visible(self._ptr) + + def setToolTip(self, tip: str): + tip_qs: QtStringPtr = vqt6_qstring_create(tip) + vqt6_qwidget_set_tool_tip(self._ptr, tip_qs) + vqt6_qstring_free(tip_qs) + + +@t.NoVTable +class QLabel: + """QLabel 包装""" + _ptr: QtLabelPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qlabel_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qlabel_create_with_text(text_qs) + else: + self._ptr = vqt6_qlabel_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QLabel") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qlabel_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qlabel_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def setAlignment(self, alignment: int): + vqt6_qlabel_set_alignment(self._ptr, alignment) + + +@t.NoVTable +class QPushButton: + """QPushButton 包装""" + _ptr: QtPushButtonPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qpushbutton_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qpushbutton_create_with_text(text_qs) + else: + self._ptr = vqt6_qpushbutton_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QPushButton") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qpushbutton_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qpushbutton_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def click(self): + vqt6_qpushbutton_click(self._ptr) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + +# ============================================================ +# 模块导出 +# ============================================================ +__all__ = [ + # 高层类 + "QApplication", "QWidget", "QLabel", "QPushButton", + # 类型 + "QtObjectPtr", "QtStringPtr", "QtByteArrayPtr", "QtWidgetPtr", "QtAppPtr", + "QtLabelPtr", "QtPushButtonPtr", + "QtColorPtr", "QtFontPtr", "QtPixmapPtr", "QtImagePtr", "QtPainterPtr", + "QtTcpSocketPtr", "QtHostAddressPtr", "QtNetworkRequestPtr", "QtNetworkReplyPtr", + # 常量 + "QT_KEY_ESCAPE", "QT_KEY_RETURN", "QT_KEY_A", "QT_KEY_Z", + "QT_LEFT_BUTTON", "QT_RIGHT_BUTTON", "QT_MID_BUTTON", + "QT_HORIZONTAL", "QT_VERTICAL", + "QT_ALIGN_LEFT", "QT_ALIGN_CENTER", "QT_ALIGN_RIGHT", + "QT_PORT_HTTP", "QT_PORT_HTTPS", "QT_PORT_FTP", + "QT_OK", "QT_CANCEL", "QT_YES", "QT_NO", "QT_CLOSE", +] diff --git a/vqt6 copy/_bridge.h b/vqt6 copy/_bridge.h new file mode 100644 index 0000000..e573ea8 --- /dev/null +++ b/vqt6 copy/_bridge.h @@ -0,0 +1,151 @@ +// ============================================================ +// vqt6/_bridge.h — C 桥接层头文件 +// +// 作用: 把 Qt6 C++ API 包装成 extern "C" 函数,供 Viper FFI 调用 +// 编译: 作为静态库 libvqt6_bridge.a 或动态库 vqt6_bridge.dll +// ============================================================ + +#ifndef VQT6_BRIDGE_H +#define VQT6_BRIDGE_H + +#include +#include + +#if defined(_WIN32) +# if defined(VQT6_BRIDGE_STATIC) +# define VQT6_API +# elif defined(VQT6_BRIDGE_BUILD) +# define VQT6_API __declspec(dllexport) +# else +# define VQT6_API __declspec(dllimport) +# endif +#else +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define VQT6_API __attribute__((visibility("default"))) +# else +# define VQT6_API +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QString +// ============================================================ +VQT6_API void* vqt6_qstring_create(const char* utf8); +VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size); +VQT6_API void vqt6_qstring_free(void* qstr); +VQT6_API int vqt6_qstring_length(void* qstr); +VQT6_API int vqt6_qstring_is_empty(void* qstr); +VQT6_API int vqt6_qstring_equals(void* qstr, void* other); +VQT6_API void* vqt6_qstring_append(void* qstr, void* other); + +// ============================================================ +// QByteArray +// ============================================================ +VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size); +VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size); +VQT6_API size_t vqt6_qbytearray_size(void* qba); +VQT6_API void vqt6_qbytearray_free(void* qba); + +// ============================================================ +// QObject +// ============================================================ +VQT6_API void vqt6_qobject_delete(void* obj); +VQT6_API void vqt6_qobject_delete_later(void* obj); +VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name); +VQT6_API void* vqt6_qobject_object_name(void* obj); +VQT6_API void vqt6_qobject_set_parent(void* child, void* parent); +VQT6_API void* vqt6_qobject_parent(void* obj); +VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter); +VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter); + +// ============================================================ +// QCoreApplication +// ============================================================ +VQT6_API void* vqt6_qcoreapp_create(const char* app_name); +VQT6_API void* vqt6_qcoreapp_instance(void); +VQT6_API int vqt6_qcoreapp_exec(void* app); +VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags); +VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event); +VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event); +VQT6_API void* vqt6_qcoreapp_organization_name(void* app); +VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name); +VQT6_API void* vqt6_qcoreapp_application_name(void* app); +VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name); + +// ============================================================ +// QTimer +// ============================================================ +VQT6_API void* vqt6_qtimer_create(void); +VQT6_API void* vqt6_qtimer_create_with_parent(void* parent); +VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms); +VQT6_API void vqt6_qtimer_stop(void* timer); +VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms); +VQT6_API int vqt6_qtimer_interval(void* timer); +VQT6_API int vqt6_qtimer_is_active(void* timer); +VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot); +VQT6_API int vqt6_qtimer_is_single_shot(void* timer); + +// ============================================================ +// QVariant +// ============================================================ +VQT6_API void* vqt6_qvariant_create_int(int value); +VQT6_API void* vqt6_qvariant_create_double(double value); +VQT6_API void* vqt6_qvariant_create_bool(int value); +VQT6_API void* vqt6_qvariant_create_string(void* s); +VQT6_API int vqt6_qvariant_to_int(void* v, int* ok); +VQT6_API double vqt6_qvariant_to_double(void* v, int* ok); +VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok); +VQT6_API void* vqt6_qvariant_to_string(void* v); +VQT6_API int vqt6_qvariant_type_id(void* v); +VQT6_API int vqt6_qvariant_is_valid(void* v); +VQT6_API void vqt6_qvariant_free(void* v); + +// ============================================================ +// QEvent +// ============================================================ +VQT6_API int vqt6_qevent_type(void* event); +VQT6_API void vqt6_qevent_accept(void* event); +VQT6_API void vqt6_qevent_ignore(void* event); +VQT6_API int vqt6_qevent_is_accepted(void* event); + +// ============================================================ +// QStringList +// ============================================================ +VQT6_API void* vqt6_qstringlist_create(void); +VQT6_API void vqt6_qstringlist_append(void* list, void* str); +VQT6_API int vqt6_qstringlist_size(void* list); +VQT6_API void* vqt6_qstringlist_at(void* list, int index); +VQT6_API void vqt6_qstringlist_free(void* list); + +// ============================================================ +// QByteArrayList +// ============================================================ +VQT6_API void* vqt6_qbytearraylist_create(void); +VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba); +VQT6_API int vqt6_qbytearraylist_size(void* list); +VQT6_API void* vqt6_qbytearraylist_at(void* list, int index); +VQT6_API void vqt6_qbytearraylist_free(void* list); + +// ============================================================ +// 全局回调注册表 +// ============================================================ +typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +VQT6_API void vqt6_register_slot(int slot_id, void* user_data); +VQT6_API void vqt6_unregister_slot(int slot_id); +VQT6_API void vqt6_trigger_slot(int slot_id); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_H diff --git a/vqt6 copy/_bridge_core.cpp b/vqt6 copy/_bridge_core.cpp new file mode 100644 index 0000000..3f420d8 --- /dev/null +++ b/vqt6 copy/_bridge_core.cpp @@ -0,0 +1,433 @@ +// ============================================================ +// vqt6/_bridge_core.cpp — QtCore C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 全局回调表(线程安全) +namespace { + QMutex g_slot_mutex; + QHash> g_slots; +} + +// ============================================================ +// QString +// ============================================================ +extern "C" VQT6_API void* vqt6_qstring_create(const char* utf8) { + if (utf8 == nullptr) return nullptr; + return new QString(QString::fromUtf8(utf8)); +} + +extern "C" VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size) { + if (qstr == nullptr || buf == nullptr || buf_size == 0) return 0; + QString* s = static_cast(qstr); + QByteArray ba = s->toUtf8(); + size_t len = static_cast(ba.size()); + if (len >= buf_size) len = buf_size - 1; + std::memcpy(buf, ba.constData(), len); + buf[len] = '\0'; + return len; +} + +extern "C" VQT6_API void vqt6_qstring_free(void* qstr) { + delete static_cast(qstr); +} + +extern "C" VQT6_API int vqt6_qstring_length(void* qstr) { + if (qstr == nullptr) return 0; + return static_cast(qstr)->length(); +} + +extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) { + if (qstr == nullptr) return 1; + return static_cast(qstr)->isEmpty() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qstring_equals(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return 0; + return *static_cast(qstr) == *static_cast(other) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qstring_append(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return nullptr; + return new QString(*static_cast(qstr) + *static_cast(other)); +} + +// ============================================================ +// QByteArray +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size) { + if (data == nullptr) return new QByteArray(); + return new QByteArray(static_cast(data), static_cast(size)); +} + +extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) { + if (qba == nullptr) return nullptr; + QByteArray* ba = static_cast(qba); + if (out_size != nullptr) *out_size = static_cast(ba->size()); + return ba->data(); +} + +extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) { + if (qba == nullptr) return 0; + return static_cast(static_cast(qba)->size()); +} + +extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) { + delete static_cast(qba); +} + +// ============================================================ +// QObject +// ============================================================ +extern "C" VQT6_API void vqt6_qobject_delete(void* obj) { + if (obj == nullptr) return; + delete static_cast(obj); +} + +extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) { + if (obj == nullptr) return; + static_cast(obj)->deleteLater(); +} + +extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) { + if (obj == nullptr || name == nullptr) return; + static_cast(obj)->setObjectName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) { + if (obj == nullptr) return nullptr; + return new QString(static_cast(obj)->objectName()); +} + +extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) { + if (child == nullptr) return; + static_cast(child)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) { + if (obj == nullptr) return nullptr; + return static_cast(obj)->parent(); +} + +extern "C" VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr || signal_name == nullptr || slot_name == nullptr) + return 0; + return QObject::connect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr) return 0; + return QObject::disconnect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->installEventFilter(static_cast(filter)); +} + +extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->removeEventFilter(static_cast(filter)); +} + +// ============================================================ +// QCoreApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qcoreapp_create(const char* app_name) { + if (app_name == nullptr) return nullptr; + int argc = 1; + static char app_name_copy[1024]; + std::strncpy(app_name_copy, app_name, sizeof(app_name_copy) - 1); + app_name_copy[sizeof(app_name_copy) - 1] = '\0'; + char* argv[] = { app_name_copy, nullptr }; + return new QCoreApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_instance(void) { + return QCoreApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qcoreapp_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code) { + if (app == nullptr) return; + // 优先使用 exit_code 重载 + QCoreApplication* a = static_cast(app); + if (a == QCoreApplication::instance()) { + a->exit(exit_code); + } +} + +extern "C" VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) { + if (app == nullptr) return; + static_cast(app)->processEvents(static_cast(flags)); +} + +extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return; + QCoreApplication::postEvent(static_cast(receiver), static_cast(event)); +} + +extern "C" VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return 0; + return QCoreApplication::sendEvent(static_cast(receiver), static_cast(event)) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qcoreapp_organization_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::organizationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setOrganizationName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_application_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::applicationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setApplicationName(*static_cast(name)); +} + +// ============================================================ +// QTimer +// ============================================================ +extern "C" VQT6_API void* vqt6_qtimer_create(void) { + return new QTimer(); +} + +extern "C" VQT6_API void* vqt6_qtimer_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTimer(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->start(interval_ms); +} + +extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) { + if (timer == nullptr) return; + static_cast(timer)->stop(); +} + +extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->setInterval(interval_ms); +} + +extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->interval(); +} + +extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot) { + if (timer == nullptr) return; + static_cast(timer)->setSingleShot(single_shot != 0); +} + +extern "C" VQT6_API int vqt6_qtimer_is_single_shot(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isSingleShot() ? 1 : 0; +} + +// ============================================================ +// QVariant +// ============================================================ +extern "C" VQT6_API void* vqt6_qvariant_create_int(int value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_double(double value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_bool(int value) { + return new QVariant(value != 0); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_string(void* s) { + if (s == nullptr) return new QVariant(); + return new QVariant(*static_cast(s)); +} + +extern "C" VQT6_API int vqt6_qvariant_to_int(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + int val = static_cast(v)->toInt(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API double vqt6_qvariant_to_double(void* v, int* ok) { + if (v == nullptr) return 0.0; + bool bok = false; + double val = static_cast(v)->toDouble(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + bool val = static_cast(v)->toBool(); + if (ok != nullptr) *ok = 1; + return val ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qvariant_to_string(void* v) { + if (v == nullptr) return nullptr; + return new QString(static_cast(v)->toString()); +} + +extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) { + if (v == nullptr) return 0; + return static_cast(static_cast(v)->typeId()); +} + +extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) { + if (v == nullptr) return 0; + return static_cast(v)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qvariant_free(void* v) { + delete static_cast(v); +} + +// ============================================================ +// QEvent +// ============================================================ +extern "C" VQT6_API int vqt6_qevent_type(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->type()); +} + +extern "C" VQT6_API void vqt6_qevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +// ============================================================ +// QStringList +// ============================================================ +extern "C" VQT6_API void* vqt6_qstringlist_create(void) { + return new QStringList(); +} + +extern "C" VQT6_API void vqt6_qstringlist_append(void* list, void* str) { + if (list == nullptr || str == nullptr) return; + static_cast(list)->append(*static_cast(str)); +} + +extern "C" VQT6_API int vqt6_qstringlist_size(void* list) { + if (list == nullptr) return 0; + return static_cast(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QStringList* sl = static_cast(list); + if (index < 0 || index >= sl->size()) return nullptr; + return new QString(sl->at(index)); +} + +extern "C" VQT6_API void vqt6_qstringlist_free(void* list) { + delete static_cast(list); +} + +// ============================================================ +// QByteArrayList +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) { + return new QList(); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) { + if (list == nullptr || qba == nullptr) return; + static_cast*>(list)->append(*static_cast(qba)); +} + +extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) { + if (list == nullptr) return 0; + return static_cast*>(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QList* qbl = static_cast*>(list); + if (index < 0 || index >= qbl->size()) return nullptr; + return new QByteArray(qbl->at(index)); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_free(void* list) { + delete static_cast*>(list); +} + +// ============================================================ +// 全局回调注册表 +// ============================================================ +extern "C" VQT6_API void vqt6_register_slot(int slot_id, void* user_data) { + QMutexLocker locker(&g_slot_mutex); + g_slots.insert(slot_id, QPair(nullptr, user_data)); +} + +extern "C" VQT6_API void vqt6_unregister_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + g_slots.remove(slot_id); +} + +extern "C" VQT6_API void vqt6_trigger_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + auto it = g_slots.find(slot_id); + if (it != g_slots.end() && it.value().first != nullptr) { + it.value().first(slot_id, it.value().second); + } +} diff --git a/vqt6 copy/_bridge_gui.cpp b/vqt6 copy/_bridge_gui.cpp new file mode 100644 index 0000000..089f0d7 --- /dev/null +++ b/vqt6 copy/_bridge_gui.cpp @@ -0,0 +1,868 @@ +// ============================================================ +// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QColor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b) { + return new QColor(r, g, b); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a) { + return new QColor(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_name(void* name) { + if (name == nullptr) return new QColor(); + return new QColor(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_hex(void* hex_str) { + if (hex_str == nullptr) return new QColor(); + return new QColor(*static_cast(hex_str)); +} + +extern "C" VQT6_API int vqt6_qcolor_red(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->red(); +} + +extern "C" VQT6_API int vqt6_qcolor_green(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->green(); +} + +extern "C" VQT6_API int vqt6_qcolor_blue(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->blue(); +} + +extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) { + if (c == nullptr) return 255; + return static_cast(c)->alpha(); +} + +extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) { + if (c == nullptr) return; + static_cast(c)->setRed(r); +} + +extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) { + if (c == nullptr) return; + static_cast(c)->setGreen(g); +} + +extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) { + if (c == nullptr) return; + static_cast(c)->setBlue(b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) { + if (c == nullptr) return; + static_cast(c)->setAlpha(a); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b) { + if (c == nullptr) return; + static_cast(c)->setRgb(r, g, b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a) { + if (c == nullptr) return; + static_cast(c)->setRgba(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_name(void* c) { + if (c == nullptr) return nullptr; + return new QString(static_cast(c)->name()); +} + +extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcolor_free(void* c) { + delete static_cast(c); +} + +// ============================================================ +// QFont +// ============================================================ +extern "C" VQT6_API void* vqt6_qfont_create(void) { + return new QFont(); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family(void* family) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family), point_size); +} + +extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) { + if (font == nullptr || family == nullptr) return; + static_cast(font)->setFamily(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_family(void* font) { + if (font == nullptr) return nullptr; + return new QString(static_cast(font)->family()); +} + +extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) { + if (font == nullptr) return; + static_cast(font)->setPointSize(point_size); +} + +extern "C" VQT6_API int vqt6_qfont_point_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pointSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) { + if (font == nullptr) return; + static_cast(font)->setPixelSize(pixel_size); +} + +extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pixelSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) { + if (font == nullptr) return; + static_cast(font)->setBold(bold != 0); +} + +extern "C" VQT6_API int vqt6_qfont_bold(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->bold() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) { + if (font == nullptr) return; + static_cast(font)->setItalic(italic != 0); +} + +extern "C" VQT6_API int vqt6_qfont_italic(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->italic() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) { + if (font == nullptr) return; + static_cast(font)->setUnderline(underline != 0); +} + +extern "C" VQT6_API int vqt6_qfont_underline(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->underline() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out) { + if (font == nullptr) return; + static_cast(font)->setStrikeOut(strike_out != 0); +} + +extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->strikeOut() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) { + if (font == nullptr) return; + static_cast(font)->setWeight(static_cast(weight)); +} + +extern "C" VQT6_API int vqt6_qfont_weight(void* font) { + if (font == nullptr) return 0; + return static_cast(static_cast(font)->weight()); +} + +extern "C" VQT6_API void vqt6_qfont_free(void* font) { + delete static_cast(font); +} + +// ============================================================ +// QFontMetrics +// ============================================================ +extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) { + if (font == nullptr) return nullptr; + return new QFontMetrics(*static_cast(font)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) { + if (fm == nullptr || text == nullptr) return 0; + return static_cast(fm)->horizontalAdvance(*static_cast(text)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->height(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->ascent(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->descent(); +} + +extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) { + delete static_cast(fm); +} + +// ============================================================ +// QPixmap +// ============================================================ +extern "C" VQT6_API void* vqt6_qpixmap_create(void) { + return new QPixmap(); +} + +extern "C" VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h) { + return new QPixmap(w, h); +} + +extern "C" VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size) { + if (pm == nullptr || data == nullptr) return 0; + return static_cast(pm)->loadFromData(static_cast(data), static_cast(size)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->width(); +} + +extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->height(); +} + +extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h) { + if (pm == nullptr) return nullptr; + return new QPixmap(static_cast(pm)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qpixmap_fill(void* pm, void* color) { + if (pm == nullptr) return; + if (color != nullptr) { + static_cast(pm)->fill(*static_cast(color)); + } else { + static_cast(pm)->fill(); + } +} + +extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) { + delete static_cast(pm); +} + +// ============================================================ +// QImage +// ============================================================ +extern "C" VQT6_API void* vqt6_qimage_create(void) { + return new QImage(); +} + +extern "C" VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format) { + return new QImage(w, h, static_cast(format)); +} + +extern "C" VQT6_API int vqt6_qimage_load(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_save(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_width(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->width(); +} + +extern "C" VQT6_API int vqt6_qimage_height(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->height(); +} + +extern "C" VQT6_API int vqt6_qimage_format(void* img) { + if (img == nullptr) return 0; + return static_cast(static_cast(img)->format()); +} + +extern "C" VQT6_API int vqt6_qimage_is_null(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qimage_fill(void* img, void* color) { + if (img == nullptr) return; + if (color != nullptr) { + static_cast(img)->fill(*static_cast(color)); + } +} + +extern "C" VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h) { + if (img == nullptr) return nullptr; + return new QImage(static_cast(img)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qimage_free(void* img) { + delete static_cast(img); +} + +// ============================================================ +// QPainter +// ============================================================ +extern "C" VQT6_API void* vqt6_qpainter_create(void) { + return new QPainter(); +} + +extern "C" VQT6_API int vqt6_qpainter_begin(void* p, void* device) { + if (p == nullptr || device == nullptr) return 0; + return static_cast(p)->begin(static_cast(device)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_end(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->end() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen) { + if (p == nullptr || pen == nullptr) return; + static_cast(p)->setPen(*static_cast(pen)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) { + if (p == nullptr || brush == nullptr) return; + static_cast(p)->setBrush(*static_cast(brush)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) { + if (p == nullptr || font == nullptr) return; + static_cast(p)->setFont(*static_cast(font)); +} + +extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) { + if (p == nullptr) return nullptr; + return new QPen(static_cast(p)->pen()); +} + +extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) { + if (p == nullptr) return nullptr; + return new QBrush(static_cast(p)->brush()); +} + +extern "C" VQT6_API void* vqt6_qpainter_font(void* p) { + if (p == nullptr) return nullptr; + return new QFont(static_cast(p)->font()); +} + +extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) { + if (p == nullptr) return; + static_cast(p)->setOpacity(opacity); +} + +extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) { + if (p == nullptr) return 1.0; + return static_cast(p)->opacity(); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2) { + if (p == nullptr) return; + static_cast(p)->drawLine(x1, y1, x2, y2); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawRect(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color) { + if (p == nullptr || color == nullptr) return; + static_cast(p)->fillRect(x, y, w, h, *static_cast(color)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawEllipse(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawArc(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawChord(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawPie(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polygon; + for (int i = 0; i < point_count; ++i) { + polygon << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolygon(polygon); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polyline; + for (int i = 0; i < point_count; ++i) { + polyline << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolyline(polyline); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) { + if (p == nullptr) return; + static_cast(p)->drawPoint(x, y); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon pts; + for (int i = 0; i < point_count; ++i) { + pts << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPoints(pts); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, w, h, flags, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawPixmap(x, y, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image) { + if (p == nullptr || image == nullptr) return; + static_cast(p)->drawImage(x, y, *static_cast(image)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawTiledPixmap(x, y, w, h, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) { + if (p == nullptr) return; + static_cast(p)->translate(dx, dy); +} + +extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) { + if (p == nullptr) return; + static_cast(p)->rotate(angle); +} + +extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) { + if (p == nullptr) return; + static_cast(p)->scale(sx, sy); +} + +extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) { + if (p == nullptr) return; + static_cast(p)->resetTransform(); +} + +extern "C" VQT6_API void vqt6_qpainter_save(void* p) { + if (p == nullptr) return; + static_cast(p)->save(); +} + +extern "C" VQT6_API void vqt6_qpainter_restore(void* p) { + if (p == nullptr) return; + static_cast(p)->restore(); +} + +extern "C" VQT6_API void vqt6_qpainter_free(void* p) { + delete static_cast(p); +} + +// ============================================================ +// QPen +// ============================================================ +extern "C" VQT6_API void* vqt6_qpen_create(void) { + return new QPen(); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color(void* color) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color), width); +} + +extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) { + if (pen == nullptr || color == nullptr) return; + static_cast(pen)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_color(void* pen) { + if (pen == nullptr) return nullptr; + return new QColor(static_cast(pen)->color()); +} + +extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) { + if (pen == nullptr) return; + static_cast(pen)->setWidth(width); +} + +extern "C" VQT6_API int vqt6_qpen_width(void* pen) { + if (pen == nullptr) return 0; + return static_cast(pen)->width(); +} + +extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) { + if (pen == nullptr) return; + static_cast(pen)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qpen_style(void* pen) { + if (pen == nullptr) return 0; + return static_cast(static_cast(pen)->style()); +} + +extern "C" VQT6_API void vqt6_qpen_free(void* pen) { + delete static_cast(pen); +} + +// ============================================================ +// QBrush +// ============================================================ +extern "C" VQT6_API void* vqt6_qbrush_create(void) { + return new QBrush(); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_color(void* color) { + if (color == nullptr) return new QBrush(); + return new QBrush(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) { + return new QBrush(static_cast(style)); +} + +extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) { + if (brush == nullptr || color == nullptr) return; + static_cast(brush)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) { + if (brush == nullptr) return nullptr; + return new QColor(static_cast(brush)->color()); +} + +extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) { + if (brush == nullptr) return; + static_cast(brush)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qbrush_style(void* brush) { + if (brush == nullptr) return 0; + return static_cast(static_cast(brush)->style()); +} + +extern "C" VQT6_API void vqt6_qbrush_free(void* brush) { + delete static_cast(brush); +} + +// ============================================================ +// QIcon +// ============================================================ +extern "C" VQT6_API void* vqt6_qicon_create(void) { + return new QIcon(); +} + +extern "C" VQT6_API void* vqt6_qicon_create_with_file(void* file_name) { + if (file_name == nullptr) return new QIcon(); + return new QIcon(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name) { + if (icon == nullptr || file_name == nullptr) return; + static_cast(icon)->addFile(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) { + if (icon == nullptr || pixmap == nullptr) return; + static_cast(icon)->addPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) { + if (icon == nullptr) return 0; + return static_cast(icon)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h) { + if (icon == nullptr) return nullptr; + return new QPixmap(static_cast(icon)->pixmap(w, h)); +} + +extern "C" VQT6_API void vqt6_qicon_free(void* icon) { + delete static_cast(icon); +} + +// ============================================================ +// QCursor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcursor_create(void) { + return new QCursor(); +} + +extern "C" VQT6_API void* vqt6_qcursor_create_with_shape(int shape) { + return new QCursor(static_cast(shape)); +} + +extern "C" VQT6_API void vqt6_qcursor_pos(int* x, int* y) { + QPoint p = QCursor::pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API void vqt6_qcursor_set_pos(int x, int y) { + QCursor::setPos(x, y); +} + +extern "C" VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape) { + if (cursor == nullptr) return; + static_cast(cursor)->setShape(static_cast(shape)); +} + +extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) { + if (cursor == nullptr) return 0; + return static_cast(static_cast(cursor)->shape()); +} + +extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) { + delete static_cast(cursor); +} + +// ============================================================ +// QKeyEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) { + QString* t = static_cast(text); + return new QKeyEvent(static_cast(type), key, static_cast(modifiers), + t != nullptr ? *t : QString()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->key(); +} + +extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) { + if (event == nullptr) return nullptr; + return new QString(static_cast(event)->text()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAutoRepeat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QMouseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers) { + QPointF* lp = static_cast(local_pos); + return new QMouseEvent( + static_cast(type), + lp != nullptr ? *lp : QPointF(0, 0), + Qt::NoButton, + static_cast(button), + static_cast(modifiers) + ); +} + +extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->button()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->buttons()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height) { + return new QResizeEvent(QSize(width, height), QSize(old_width, old_height)); +} + +extern "C" VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->oldSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h) { + return new QPaintEvent(QRect(rect_x, rect_y, rect_w, rect_h)); +} + +extern "C" VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h) { + if (event == nullptr) return; + QRect r = static_cast(event)->rect(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qpaintevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qcloseevent_create(void) { + return new QCloseEvent(); +} + +extern "C" VQT6_API int vqt6_qcloseevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) { + delete static_cast(event); +} diff --git a/vqt6 copy/_bridge_gui.h b/vqt6 copy/_bridge_gui.h new file mode 100644 index 0000000..d2bb224 --- /dev/null +++ b/vqt6 copy/_bridge_gui.h @@ -0,0 +1,231 @@ +// ============================================================ +// vqt6/_bridge_gui.h — QtGui C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_GUI_H +#define VQT6_BRIDGE_GUI_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QColor +// ============================================================ +VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b); +VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_create_name(void* name); +VQT6_API void* vqt6_qcolor_create_hex(void* hex_str); +VQT6_API int vqt6_qcolor_red(void* c); +VQT6_API int vqt6_qcolor_green(void* c); +VQT6_API int vqt6_qcolor_blue(void* c); +VQT6_API int vqt6_qcolor_alpha(void* c); +VQT6_API void vqt6_qcolor_set_red(void* c, int r); +VQT6_API void vqt6_qcolor_set_green(void* c, int g); +VQT6_API void vqt6_qcolor_set_blue(void* c, int b); +VQT6_API void vqt6_qcolor_set_alpha(void* c, int a); +VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b); +VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_name(void* c); +VQT6_API int vqt6_qcolor_is_valid(void* c); +VQT6_API void vqt6_qcolor_free(void* c); + +// ============================================================ +// QFont +// ============================================================ +VQT6_API void* vqt6_qfont_create(void); +VQT6_API void* vqt6_qfont_create_with_family(void* family); +VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size); +VQT6_API void vqt6_qfont_set_family(void* font, void* family); +VQT6_API void* vqt6_qfont_family(void* font); +VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size); +VQT6_API int vqt6_qfont_point_size(void* font); +VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size); +VQT6_API int vqt6_qfont_pixel_size(void* font); +VQT6_API void vqt6_qfont_set_bold(void* font, int bold); +VQT6_API int vqt6_qfont_bold(void* font); +VQT6_API void vqt6_qfont_set_italic(void* font, int italic); +VQT6_API int vqt6_qfont_italic(void* font); +VQT6_API void vqt6_qfont_set_underline(void* font, int underline); +VQT6_API int vqt6_qfont_underline(void* font); +VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out); +VQT6_API int vqt6_qfont_strike_out(void* font); +VQT6_API void vqt6_qfont_set_weight(void* font, int weight); +VQT6_API int vqt6_qfont_weight(void* font); +VQT6_API void vqt6_qfont_free(void* font); + +// ============================================================ +// QFontMetrics +// ============================================================ +VQT6_API void* vqt6_qfontmetrics_create(void* font); +VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text); +VQT6_API int vqt6_qfontmetrics_height(void* fm); +VQT6_API int vqt6_qfontmetrics_ascent(void* fm); +VQT6_API int vqt6_qfontmetrics_descent(void* fm); +VQT6_API void vqt6_qfontmetrics_free(void* fm); + +// ============================================================ +// QPixmap +// ============================================================ +VQT6_API void* vqt6_qpixmap_create(void); +VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h); +VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size); +VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_width(void* pm); +VQT6_API int vqt6_qpixmap_height(void* pm); +VQT6_API int vqt6_qpixmap_is_null(void* pm); +VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h); +VQT6_API void vqt6_qpixmap_fill(void* pm, void* color); +VQT6_API void vqt6_qpixmap_free(void* pm); + +// ============================================================ +// QImage +// ============================================================ +VQT6_API void* vqt6_qimage_create(void); +VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format); +VQT6_API int vqt6_qimage_load(void* img, void* file_name); +VQT6_API int vqt6_qimage_save(void* img, void* file_name); +VQT6_API int vqt6_qimage_width(void* img); +VQT6_API int vqt6_qimage_height(void* img); +VQT6_API int vqt6_qimage_format(void* img); +VQT6_API int vqt6_qimage_is_null(void* img); +VQT6_API void vqt6_qimage_fill(void* img, void* color); +VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h); +VQT6_API void vqt6_qimage_free(void* img); + +// ============================================================ +// QPainter +// ============================================================ +VQT6_API void* vqt6_qpainter_create(void); +VQT6_API int vqt6_qpainter_begin(void* p, void* device); +VQT6_API int vqt6_qpainter_end(void* p); +VQT6_API int vqt6_qpainter_is_active(void* p); +VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen); +VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush); +VQT6_API void vqt6_qpainter_set_font(void* p, void* font); +VQT6_API void* vqt6_qpainter_pen(void* p); +VQT6_API void* vqt6_qpainter_brush(void* p); +VQT6_API void* vqt6_qpainter_font(void* p); +VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity); +VQT6_API double vqt6_qpainter_opacity(void* p); +VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2); +VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color); +VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y); +VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text); +VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text); +VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap); +VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image); +VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap); +VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy); +VQT6_API void vqt6_qpainter_rotate(void* p, double angle); +VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy); +VQT6_API void vqt6_qpainter_reset_transform(void* p); +VQT6_API void vqt6_qpainter_save(void* p); +VQT6_API void vqt6_qpainter_restore(void* p); +VQT6_API void vqt6_qpainter_free(void* p); + +// ============================================================ +// QPen +// ============================================================ +VQT6_API void* vqt6_qpen_create(void); +VQT6_API void* vqt6_qpen_create_with_color(void* color); +VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width); +VQT6_API void vqt6_qpen_set_color(void* pen, void* color); +VQT6_API void* vqt6_qpen_color(void* pen); +VQT6_API void vqt6_qpen_set_width(void* pen, int width); +VQT6_API int vqt6_qpen_width(void* pen); +VQT6_API void vqt6_qpen_set_style(void* pen, int style); +VQT6_API int vqt6_qpen_style(void* pen); +VQT6_API void vqt6_qpen_free(void* pen); + +// ============================================================ +// QBrush +// ============================================================ +VQT6_API void* vqt6_qbrush_create(void); +VQT6_API void* vqt6_qbrush_create_with_color(void* color); +VQT6_API void* vqt6_qbrush_create_with_style(int style); +VQT6_API void vqt6_qbrush_set_color(void* brush, void* color); +VQT6_API void* vqt6_qbrush_color(void* brush); +VQT6_API void vqt6_qbrush_set_style(void* brush, int style); +VQT6_API int vqt6_qbrush_style(void* brush); +VQT6_API void vqt6_qbrush_free(void* brush); + +// ============================================================ +// QIcon +// ============================================================ +VQT6_API void* vqt6_qicon_create(void); +VQT6_API void* vqt6_qicon_create_with_file(void* file_name); +VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name); +VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap); +VQT6_API int vqt6_qicon_is_null(void* icon); +VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h); +VQT6_API void vqt6_qicon_free(void* icon); + +// ============================================================ +// QCursor +// ============================================================ +VQT6_API void* vqt6_qcursor_create(void); +VQT6_API void* vqt6_qcursor_create_with_shape(int shape); +VQT6_API void vqt6_qcursor_pos(int* x, int* y); +VQT6_API void vqt6_qcursor_set_pos(int x, int y); +VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape); +VQT6_API int vqt6_qcursor_shape(void* cursor); +VQT6_API void vqt6_qcursor_free(void* cursor); + +// ============================================================ +// QKeyEvent +// ============================================================ +VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text); +VQT6_API int vqt6_qkeyevent_key(void* event); +VQT6_API void* vqt6_qkeyevent_text(void* event); +VQT6_API int vqt6_qkeyevent_modifiers(void* event); +VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event); +VQT6_API void vqt6_qkeyevent_free(void* event); + +// ============================================================ +// QMouseEvent +// ============================================================ +VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers); +VQT6_API int vqt6_qmouseevent_button(void* event); +VQT6_API int vqt6_qmouseevent_buttons(void* event); +VQT6_API int vqt6_qmouseevent_x(void* event); +VQT6_API int vqt6_qmouseevent_y(void* event); +VQT6_API int vqt6_qmouseevent_global_x(void* event); +VQT6_API int vqt6_qmouseevent_global_y(void* event); +VQT6_API int vqt6_qmouseevent_modifiers(void* event); +VQT6_API void vqt6_qmouseevent_free(void* event); + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height); +VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_free(void* event); + +VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h); +VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qpaintevent_free(void* event); + +VQT6_API void* vqt6_qcloseevent_create(void); +VQT6_API int vqt6_qcloseevent_is_accepted(void* event); +VQT6_API void vqt6_qcloseevent_accept(void* event); +VQT6_API void vqt6_qcloseevent_ignore(void* event); +VQT6_API void vqt6_qcloseevent_free(void* event); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_GUI_H diff --git a/vqt6 copy/_bridge_network.cpp b/vqt6 copy/_bridge_network.cpp new file mode 100644 index 0000000..00cab5e --- /dev/null +++ b/vqt6 copy/_bridge_network.cpp @@ -0,0 +1,519 @@ +// ============================================================ +// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_network.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QHostAddress +// ============================================================ +extern "C" VQT6_API void* vqt6_qhostaddress_create(void) { + return new QHostAddress(); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4) { + return new QHostAddress(static_cast(ipv4)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) { + if (address == nullptr) return new QHostAddress(); + return new QHostAddress(*static_cast(address)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_host(void) { + return new QHostAddress(QHostAddress::LocalHost); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void) { + return new QHostAddress(QHostAddress::LocalHostIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void) { + return new QHostAddress(QHostAddress::Broadcast); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void) { + return new QHostAddress(QHostAddress::AnyIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_to_string(void* addr) { + if (addr == nullptr) return nullptr; + return new QString(static_cast(addr)->toString()); +} + +extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->toIPv4Address()); +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isLoopback() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isBroadcast() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->protocol()); +} + +extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) { + delete static_cast(addr); +} + +// ============================================================ +// QAbstractSocket +// ============================================================ +extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->state()); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->error()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) { + if (socket == nullptr) return nullptr; + return new QString(static_cast(socket)->errorString()); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->disconnectFromHost(); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForConnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForReadyRead(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForBytesWritten(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForDisconnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_valid(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isOpen() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->flush() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size) { + if (socket == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(socket)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size) { + if (socket == nullptr) return nullptr; + QByteArray ba = static_cast(socket)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size) { + if (socket == nullptr || data == nullptr) return 0; + return static_cast(static_cast(socket)->write(static_cast(data), static_cast(size))); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesAvailable()); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesToWrite()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->peerAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->peerPort()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->localAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->localPort()); +} + +// ============================================================ +// QTcpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qtcpsocket_create(void) { + return new QTcpSocket(); +} + +extern "C" VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTcpSocket(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port, + static_cast(mode)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port, + static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor) { + if (socket == nullptr) return 0; + return static_cast(socket)->setSocketDescriptor(static_cast(socket_descriptor)) ? 1 : 0; +} + +extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) { + if (socket == nullptr) return -1; + return static_cast(static_cast(socket)->socketDescriptor()); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type) { + Q_UNUSED(socket); + Q_UNUSED(proxy_type); + // QNetworkProxy 配置在更高层 +} + +extern "C" VQT6_API void vqt6_qtcpsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +// ============================================================ +// QUdpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qudpsocket_create(void) { + return new QUdpSocket(); +} + +extern "C" VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QUdpSocket(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) { + if (socket == nullptr) return 0; + return static_cast(socket)->bind(port) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return 0; + return static_cast(socket)->bind(*static_cast(address), port) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port) { + if (socket == nullptr || data == nullptr || host == nullptr) return 0; + return static_cast(static_cast(socket)->writeDatagram( + static_cast(data), static_cast(size), + *static_cast(host), port)); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port) { + if (socket == nullptr || data == nullptr) return 0; + QHostAddress sender; + quint16 sender_port = 0; + qint64 n = static_cast(socket)->readDatagram( + static_cast(data), static_cast(max_size), &sender, &sender_port); + if (host != nullptr) { + QHostAddress* dst = static_cast(host); + *dst = sender; + } + if (port != nullptr) { + *port = sender_port; + } + return static_cast(n); +} + +extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->hasPendingDatagrams() ? 1 : 0; +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->pendingDatagramSize()); +} + +extern "C" VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->joinMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->leaveMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +// ============================================================ +// QNetworkRequest +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkrequest_create(void) { + return new QNetworkRequest(); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url) { + if (url == nullptr) return new QNetworkRequest(); + return new QNetworkRequest(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) { + if (req == nullptr || url == nullptr) return; + static_cast(req)->setUrl(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) { + if (req == nullptr) return nullptr; + return new QString(static_cast(req)->url().toString()); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setHeader(static_cast(header_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size) { + if (req == nullptr || header_name == nullptr) return; + static_cast(req)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size) { + if (req == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(req)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setAttribute(static_cast(attr_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->attribute(static_cast(attr_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) { + delete static_cast(req); +} + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create(void) { + return new QNetworkAccessManager(); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QNetworkAccessManager(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->get(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->post(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->put(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->deleteResource(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->head(*static_cast(req)); +} + +extern "C" VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store) { + if (nam == nullptr || store == nullptr) return; + QNetworkCookieJar* jar = qobject_cast(static_cast(store)); + if (jar != nullptr) { + static_cast(nam)->setCookieJar(jar); + } +} + +// ============================================================ +// QNetworkReply +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->url().toString()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) { + if (reply == nullptr) return nullptr; + return new QNetworkRequest(static_cast(reply)->request()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->error()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->errorString()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isFinished() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isRunning() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) { + if (reply == nullptr) return; + static_cast(reply)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size) { + if (reply == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(reply)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size) { + if (reply == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->bytesAvailable()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size) { + if (reply == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->attribute(static_cast(attribute_code))); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value) { + if (reply == nullptr) return default_value; + return static_cast(reply)->attribute(static_cast(attribute_code)).toInt(default_value); +} + +extern "C" VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size) { + if (reply == nullptr || header_name == nullptr) return; + static_cast(reply)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} diff --git a/vqt6 copy/_bridge_network.h b/vqt6 copy/_bridge_network.h new file mode 100644 index 0000000..2f99580 --- /dev/null +++ b/vqt6 copy/_bridge_network.h @@ -0,0 +1,137 @@ +// ============================================================ +// vqt6/_bridge_network.h — QtNetwork C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_NETWORK_H +#define VQT6_BRIDGE_NETWORK_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QHostAddress +// ============================================================ +VQT6_API void* vqt6_qhostaddress_create(void); +VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4); +VQT6_API void* vqt6_qhostaddress_create_with_string(void* address); +VQT6_API void* vqt6_qhostaddress_create_with_local_host(void); +VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void); +VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void); +VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void); +VQT6_API void* vqt6_qhostaddress_to_string(void* addr); +VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr); +VQT6_API int vqt6_qhostaddress_is_null(void* addr); +VQT6_API int vqt6_qhostaddress_is_loopback(void* addr); +VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr); +VQT6_API int vqt6_qhostaddress_protocol(void* addr); +VQT6_API void vqt6_qhostaddress_free(void* addr); + +// ============================================================ +// QAbstractSocket +// ============================================================ +VQT6_API int vqt6_qabstractsocket_state(void* socket); +VQT6_API int vqt6_qabstractsocket_error(void* socket); +VQT6_API void* vqt6_qabstractsocket_error_string(void* socket); +VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port); +VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket); +VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_is_valid(void* socket); +VQT6_API int vqt6_qabstractsocket_is_open(void* socket); +VQT6_API int vqt6_qabstractsocket_flush(void* socket); +VQT6_API void vqt6_qabstractsocket_close(void* socket); +VQT6_API void vqt6_qabstractsocket_abort(void* socket); +VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size); +VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size); +VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size); +VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket); +VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket); +VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket); +VQT6_API void* vqt6_qabstractsocket_local_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket); + +// ============================================================ +// QTcpSocket +// ============================================================ +VQT6_API void* vqt6_qtcpsocket_create(void); +VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent); +VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode); +VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode); +VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor); +VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket); +VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type); +VQT6_API void vqt6_qtcpsocket_abort(void* socket); + +// ============================================================ +// QUdpSocket +// ============================================================ +VQT6_API void* vqt6_qudpsocket_create(void); +VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent); +VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port); +VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qudpsocket_close(void* socket); +VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port); +VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port); +VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket); +VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket); +VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address); +VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address); + +// ============================================================ +// QNetworkRequest +// ============================================================ +VQT6_API void* vqt6_qnetworkrequest_create(void); +VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url); +VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url); +VQT6_API void* vqt6_qnetworkrequest_url(void* req); +VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type); +VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size); +VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size); +VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type); +VQT6_API void vqt6_qnetworkrequest_free(void* req); + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +VQT6_API void* vqt6_qnetworkaccessmanager_create(void); +VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent); +VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req); +VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store); + +// ============================================================ +// QNetworkReply +// ============================================================ +VQT6_API void* vqt6_qnetworkreply_url(void* reply); +VQT6_API void* vqt6_qnetworkreply_request(void* reply); +VQT6_API int vqt6_qnetworkreply_error(void* reply); +VQT6_API void* vqt6_qnetworkreply_error_string(void* reply); +VQT6_API int vqt6_qnetworkreply_is_finished(void* reply); +VQT6_API int vqt6_qnetworkreply_is_running(void* reply); +VQT6_API void vqt6_qnetworkreply_abort(void* reply); +VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size); +VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size); +VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply); +VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type); +VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size); +VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code); +VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value); +VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_NETWORK_H diff --git a/vqt6 copy/_bridge_widgets.cpp b/vqt6 copy/_bridge_widgets.cpp new file mode 100644 index 0000000..2b963a5 --- /dev/null +++ b/vqt6 copy/_bridge_widgets.cpp @@ -0,0 +1,1745 @@ +// ============================================================ +// vqt6/_bridge_widgets.cpp — QtWidgets C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_widgets.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qapplication_create(int argc, char** argv) { + return new QApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qapplication_instance(void) { + return QApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qapplication_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qapplication_quit(void* app) { + if (app == nullptr) return; + static_cast(app)->quit(); +} + +extern "C" VQT6_API void vqt6_qapplication_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qapplication_process_events(void* app) { + if (app == nullptr) return; + static_cast(app)->processEvents(); +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_width(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().width() : 0; +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_height(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().height() : 0; +} + +extern "C" VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit) { + if (app == nullptr) return; + static_cast(app)->setQuitOnLastWindowClosed(quit != 0); +} + +extern "C" VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app) { + if (app == nullptr) return 0; + return QApplication::quitOnLastWindowClosed() ? 1 : 0; +} + +// ============================================================ +// QWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qwidget_create(void) { + return new QWidget(); +} + +extern "C" VQT6_API void* vqt6_qwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qwidget_show(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->show(); +} + +extern "C" VQT6_API void vqt6_qwidget_hide(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->hide(); +} + +extern "C" VQT6_API int vqt6_qwidget_close(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->close() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qwidget_is_visible(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isVisible() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible) { + if (widget == nullptr) return; + static_cast(widget)->setVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setGeometry(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h) { + if (widget == nullptr) return; + QRect r = static_cast(widget)->geometry(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->resize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_move(void* widget, int x, int y) { + if (widget == nullptr) return; + static_cast(widget)->move(x, y); +} + +extern "C" VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y) { + if (widget == nullptr) return; + QPoint p = static_cast(widget)->pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API int vqt6_qwidget_width(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->width(); +} + +extern "C" VQT6_API int vqt6_qwidget_height(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->height(); +} + +extern "C" VQT6_API int vqt6_qwidget_x(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->x(); +} + +extern "C" VQT6_API int vqt6_qwidget_y(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->y(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title) { + if (widget == nullptr || title == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qwidget_window_title(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_text(void* widget, void* text) { + if (widget == nullptr || text == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qwidget_text(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qwidget_is_enabled(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent) { + if (widget == nullptr) return; + static_cast(widget)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qwidget_parent_widget(void* widget) { + if (widget == nullptr) return nullptr; + return static_cast(widget)->parentWidget(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->setFocus(); +} + +extern "C" VQT6_API void vqt6_qwidget_clear_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->clearFocus(); +} + +extern "C" VQT6_API int vqt6_qwidget_has_focus(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->hasFocus() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy) { + if (widget == nullptr) return; + static_cast(widget)->setFocusPolicy(static_cast(policy)); +} + +extern "C" VQT6_API void vqt6_qwidget_update(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->update(); +} + +extern "C" VQT6_API void vqt6_qwidget_repaint(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->repaint(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setUpdatesEnabled(enabled != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags) { + if (widget == nullptr) return; + static_cast(widget)->setWindowFlags(static_cast(flags)); +} + +extern "C" VQT6_API int vqt6_qwidget_window_flags(void* widget) { + if (widget == nullptr) return 0; + return static_cast(static_cast(widget)->windowFlags()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor) { + if (widget == nullptr || cursor == nullptr) return; + static_cast(widget)->setCursor(*static_cast(cursor)); +} + +extern "C" VQT6_API void* vqt6_qwidget_cursor(void* widget) { + if (widget == nullptr) return nullptr; + return new QCursor(static_cast(widget)->cursor()); +} + +extern "C" VQT6_API void vqt6_qwidget_unset_cursor(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->unsetCursor(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setToolTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_tool_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->toolTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setStatusTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_status_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->statusTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMinimumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMaximumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setFixedSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->minimumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->maximumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +// ============================================================ +// QDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qdialog_create(void) { + return new QDialog(); +} + +extern "C" VQT6_API void* vqt6_qdialog_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QDialog(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qdialog_exec(void* dialog) { + if (dialog == nullptr) return -1; + return static_cast(dialog)->exec(); +} + +extern "C" VQT6_API void vqt6_qdialog_done(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->done(result); +} + +extern "C" VQT6_API void vqt6_qdialog_accept(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->accept(); +} + +extern "C" VQT6_API void vqt6_qdialog_reject(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->reject(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_result(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->setResult(result); +} + +extern "C" VQT6_API int vqt6_qdialog_result(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->result(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal) { + if (dialog == nullptr) return; + static_cast(dialog)->setModal(modal != 0); +} + +extern "C" VQT6_API int vqt6_qdialog_is_modal(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->isModal() ? 1 : 0; +} + +// ============================================================ +// QMainWindow +// ============================================================ +extern "C" VQT6_API void* vqt6_qmainwindow_create(void) { + return new QMainWindow(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMainWindow(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget) { + if (mw == nullptr) return; + static_cast(mw)->setCentralWidget(static_cast(widget)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_central_widget(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->centralWidget(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->menuBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar) { + if (mw == nullptr) return; + static_cast(mw)->setMenuBar(static_cast(menubar)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_status_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->statusBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar) { + if (mw == nullptr) return; + static_cast(mw)->setStatusBar(static_cast(statusbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar) { + if (mw == nullptr) return; + static_cast(mw)->addToolBar(static_cast(toolbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw) { + if (mw == nullptr) return; + static_cast(mw)->addToolBarBreak(); +} + +// ============================================================ +// QLabel +// ============================================================ +extern "C" VQT6_API void* vqt6_qlabel_create(void) { + return new QLabel(); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLabel(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLabel(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlabel_set_text(void* label, void* text) { + if (label == nullptr || text == nullptr) return; + static_cast(label)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_text(void* label) { + if (label == nullptr) return nullptr; + return new QString(static_cast(label)->text()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment) { + if (label == nullptr) return; + static_cast(label)->setAlignment(static_cast(alignment)); +} + +extern "C" VQT6_API int vqt6_qlabel_alignment(void* label) { + if (label == nullptr) return 0; + return static_cast(static_cast(label)->alignment()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap) { + if (label == nullptr || pixmap == nullptr) return; + static_cast(label)->setPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API void* vqt6_qlabel_pixmap(void* label) { + if (label == nullptr) return nullptr; + return new QPixmap(static_cast(label)->pixmap()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_indent(void* label, int indent) { + if (label == nullptr) return; + static_cast(label)->setIndent(indent); +} + +extern "C" VQT6_API void vqt6_qlabel_set_margin(void* label, int margin) { + if (label == nullptr) return; + static_cast(label)->setMargin(margin); +} + +extern "C" VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap) { + if (label == nullptr) return; + static_cast(label)->setWordWrap(wrap != 0); +} + +extern "C" VQT6_API int vqt6_qlabel_word_wrap(void* label) { + if (label == nullptr) return 0; + return static_cast(label)->wordWrap() ? 1 : 0; +} + +// ============================================================ +// QPushButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qpushbutton_create(void) { + return new QPushButton(); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QPushButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QPushButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text) { + if (btn == nullptr || text == nullptr) return; + static_cast(btn)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_text(void* btn) { + if (btn == nullptr) return nullptr; + return new QString(static_cast(btn)->text()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon) { + if (btn == nullptr || icon == nullptr) return; + static_cast(btn)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_icon(void* btn) { + if (btn == nullptr) return nullptr; + return new QIcon(static_cast(btn)->icon()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default) { + if (btn == nullptr) return; + static_cast(btn)->setDefault(is_default != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_default(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isDefault() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat) { + if (btn == nullptr) return; + static_cast(btn)->setFlat(flat != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_flat(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isFlat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable) { + if (btn == nullptr) return; + static_cast(btn)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checkable(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked) { + if (btn == nullptr) return; + static_cast(btn)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checked(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_click(void* btn) { + if (btn == nullptr) return; + static_cast(btn)->click(); +} + +// ============================================================ +// QLineEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qlineedit_create(void) { + return new QLineEdit(); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLineEdit(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLineEdit(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->text()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_placeholder_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->placeholderText()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setPlaceholderText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max) { + if (le == nullptr) return; + static_cast(le)->setMaxLength(max); +} + +extern "C" VQT6_API int vqt6_qlineedit_max_length(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->maxLength(); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro) { + if (le == nullptr) return; + static_cast(le)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qlineedit_is_read_only(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode) { + if (le == nullptr) return; + static_cast(le)->setEchoMode(static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qlineedit_echo_mode(void* le) { + if (le == nullptr) return 0; + return static_cast(static_cast(le)->echoMode()); +} + +extern "C" VQT6_API void vqt6_qlineedit_select_all(void* le) { + if (le == nullptr) return; + static_cast(le)->selectAll(); +} + +extern "C" VQT6_API void vqt6_qlineedit_clear(void* le) { + if (le == nullptr) return; + static_cast(le)->clear(); +} + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qtextedit_create(void) { + return new QTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_plain_text(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_html(void* te, void* html) { + if (te == nullptr || html == nullptr) return; + static_cast(te)->setHtml(*static_cast(html)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_html(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toHtml()); +} + +extern "C" VQT6_API void vqt6_qtextedit_append(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->append(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_clear(void* te) { + if (te == nullptr) return; + static_cast(te)->clear(); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro) { + if (te == nullptr) return; + static_cast(te)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qtextedit_is_read_only(void* te) { + if (te == nullptr) return 0; + return static_cast(te)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create(void) { + return new QPlainTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QPlainTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte) { + if (pte == nullptr) return nullptr; + return new QString(static_cast(pte)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->appendPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_clear(void* pte) { + if (pte == nullptr) return; + static_cast(pte)->clear(); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro) { + if (pte == nullptr) return; + static_cast(pte)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qplaintextedit_line_count(void* pte) { + if (pte == nullptr) return 0; + return static_cast(pte)->blockCount(); +} + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qcheckbox_create(void) { + return new QCheckBox(); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QCheckBox(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QCheckBox(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked) { + if (cb == nullptr) return; + static_cast(cb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_checked(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->text()); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate) { + if (cb == nullptr) return; + static_cast(cb)->setTristate(tristate != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_tristate(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isTristate() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create(void) { + return new QRadioButton(); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QRadioButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QRadioButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked) { + if (rb == nullptr) return; + static_cast(rb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qradiobutton_is_checked(void* rb) { + if (rb == nullptr) return 0; + return static_cast(rb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text) { + if (rb == nullptr || text == nullptr) return; + static_cast(rb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_text(void* rb) { + if (rb == nullptr) return nullptr; + return new QString(static_cast(rb)->text()); +} + +// ============================================================ +// QComboBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qcombobox_create(void) { + return new QComboBox(); +} + +extern "C" VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QComboBox(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items) { + if (cb == nullptr || items == nullptr) return; + static_cast(cb)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->insertItem(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->removeItem(index); +} + +extern "C" VQT6_API void vqt6_qcombobox_clear(void* cb) { + if (cb == nullptr) return; + static_cast(cb)->clear(); +} + +extern "C" VQT6_API int vqt6_qcombobox_count(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->count(); +} + +extern "C" VQT6_API int vqt6_qcombobox_current_index(void* cb) { + if (cb == nullptr) return -1; + return static_cast(cb)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qcombobox_current_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->currentText()); +} + +extern "C" VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->itemText(index)); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable) { + if (cb == nullptr) return; + static_cast(cb)->setEditable(editable != 0); +} + +extern "C" VQT6_API int vqt6_qcombobox_is_editable(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isEditable() ? 1 : 0; +} + +// ============================================================ +// QListWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qlistwidget_create(void) { + return new QListWidget(); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QListWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items) { + if (lw == nullptr || items == nullptr) return; + static_cast(lw)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->insertItem(row, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row) { + if (lw == nullptr) return nullptr; + return static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void vqt6_qlistwidget_clear(void* lw) { + if (lw == nullptr) return; + static_cast(lw)->clear(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_count(void* lw) { + if (lw == nullptr) return 0; + return static_cast(lw)->count(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_current_row(void* lw) { + if (lw == nullptr) return -1; + return static_cast(lw)->currentRow(); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->setCurrentRow(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->currentItem(); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it != nullptr) it->setText(*static_cast(text)); +} + +// ============================================================ +// QProgressBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qprogressbar_create(void) { + return new QProgressBar(); +} + +extern "C" VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QProgressBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value) { + if (pb == nullptr) return; + static_cast(pb)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qprogressbar_value(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->value(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min) { + if (pb == nullptr) return; + static_cast(pb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max) { + if (pb == nullptr) return; + static_cast(pb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max) { + if (pb == nullptr) return; + static_cast(pb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qprogressbar_minimum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qprogressbar_maximum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible) { + if (pb == nullptr) return; + static_cast(pb)->setTextVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format) { + if (pb == nullptr || format == nullptr) return; + static_cast(pb)->setFormat(*static_cast(format)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_reset(void* pb) { + if (pb == nullptr) return; + static_cast(pb)->reset(); +} + +// ============================================================ +// QSlider +// ============================================================ +extern "C" VQT6_API void* vqt6_qslider_create(void) { + return new QSlider(); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation(int orientation) { + return new QSlider(static_cast(orientation)); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent) { + if (parent == nullptr) return nullptr; + return new QSlider(static_cast(orientation), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qslider_set_value(void* s, int value) { + if (s == nullptr) return; + static_cast(s)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qslider_value(void* s) { + if (s == nullptr) return 0; + return static_cast(s)->value(); +} + +extern "C" VQT6_API void vqt6_qslider_set_minimum(void* s, int min) { + if (s == nullptr) return; + static_cast(s)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qslider_set_maximum(void* s, int max) { + if (s == nullptr) return; + static_cast(s)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qslider_set_range(void* s, int min, int max) { + if (s == nullptr) return; + static_cast(s)->setRange(min, max); +} + +extern "C" VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation) { + if (s == nullptr) return; + static_cast(s)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qslider_orientation(void* s) { + if (s == nullptr) return 0; + return static_cast(static_cast(s)->orientation()); +} + +extern "C" VQT6_API void vqt6_qslider_set_single_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qslider_set_page_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setPageStep(step); +} + +// ============================================================ +// QSpinBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qspinbox_create(void) { + return new QSpinBox(); +} + +extern "C" VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QSpinBox(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qspinbox_value(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->value(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_value(void* sb, int value) { + if (sb == nullptr) return; + static_cast(sb)->setValue(value); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min) { + if (sb == nullptr) return; + static_cast(sb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max) { + if (sb == nullptr) return; + static_cast(sb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max) { + if (sb == nullptr) return; + static_cast(sb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qspinbox_minimum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qspinbox_maximum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step) { + if (sb == nullptr) return; + static_cast(sb)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix) { + if (sb == nullptr || prefix == nullptr) return; + static_cast(sb)->setPrefix(*static_cast(prefix)); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix) { + if (sb == nullptr || suffix == nullptr) return; + static_cast(sb)->setSuffix(*static_cast(suffix)); +} + +extern "C" VQT6_API void* vqt6_qspinbox_prefix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->prefix()); +} + +extern "C" VQT6_API void* vqt6_qspinbox_suffix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->suffix()); +} + +// ============================================================ +// Layouts +// ============================================================ +extern "C" VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->addWidget(static_cast(widget)); +} + +extern "C" VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->removeWidget(static_cast(widget)); +} + +extern "C" VQT6_API int vqt6_qlayout_count(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->count(); +} + +extern "C" VQT6_API void* vqt6_qlayout_item_at(void* layout, int index) { + if (layout == nullptr) return nullptr; + QLayoutItem* item = static_cast(layout)->itemAt(index); + return item != nullptr ? item->widget() : nullptr; +} + +extern "C" VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom) { + if (layout == nullptr) return; + static_cast(layout)->setContentsMargins(left, top, right, bottom); +} + +extern "C" VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing) { + if (layout == nullptr) return; + static_cast(layout)->setSpacing(spacing); +} + +extern "C" VQT6_API int vqt6_qlayout_spacing(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->spacing(); +} + +extern "C" VQT6_API void vqt6_qlayout_invalidate(void* layout) { + if (layout == nullptr) return; + static_cast(layout)->invalidate(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create(void) { + return new QHBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QHBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create(void) { + return new QVBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QVBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create(void) { + return new QGridLayout(); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QGridLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col, row_span, col_span); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create(void) { + return new QFormLayout(); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QFormLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(*static_cast(label), static_cast(field)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(static_cast(label), static_cast(field)); +} + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qstackedwidget_create(void) { + return new QStackedWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStackedWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return -1; + return static_cast(sw)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return; + static_cast(sw)->removeWidget(static_cast(w)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_count(void* sw) { + if (sw == nullptr) return 0; + return static_cast(sw)->count(); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_current_index(void* sw) { + if (sw == nullptr) return -1; + return static_cast(sw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index) { + if (sw == nullptr) return; + static_cast(sw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->currentWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->widget(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create(void) { + return new QTabWidget(); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTabWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->addTab(static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->insertTab(index, static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->removeTab(index); +} + +extern "C" VQT6_API int vqt6_qtabwidget_count(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->count(); +} + +extern "C" VQT6_API int vqt6_qtabwidget_current_index(void* tw) { + if (tw == nullptr) return -1; + return static_cast(tw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index) { + if (tw == nullptr) return nullptr; + return new QString(static_cast(tw)->tabText(index)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text) { + if (tw == nullptr || text == nullptr) return; + static_cast(tw)->setTabText(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable) { + if (tw == nullptr) return; + static_cast(tw)->setTabsClosable(closable != 0); +} + +extern "C" VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->tabsClosable() ? 1 : 0; +} + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +extern "C" VQT6_API void* vqt6_qmenubar_create(void) { + return new QMenuBar(); +} + +extern "C" VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMenuBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title) { + if (mb == nullptr || title == nullptr) return nullptr; + return static_cast(mb)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu) { + if (mb == nullptr || menu == nullptr) return; + static_cast(mb)->addMenu(static_cast(menu)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action) { + if (mb == nullptr || action == nullptr) return; + static_cast(mb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenubar_clear(void* mb) { + if (mb == nullptr) return; + static_cast(mb)->clear(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create(void) { + return new QMenu(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title(void* title) { + if (title == nullptr) return nullptr; + return new QMenu(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent) { + if (title == nullptr || parent == nullptr) return nullptr; + return new QMenu(*static_cast(title), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return nullptr; + return static_cast(menu)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_action(void* menu, void* action) { + if (menu == nullptr || action == nullptr) return; + static_cast(menu)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_separator(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qmenu_clear(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->clear(); +} + +extern "C" VQT6_API void vqt6_qmenu_set_title(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return; + static_cast(menu)->setTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_title(void* menu) { + if (menu == nullptr) return nullptr; + return new QString(static_cast(menu)->title()); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text) { + if (menu == nullptr || text == nullptr) return nullptr; + return static_cast(menu)->addAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create(void) { + return new QAction(); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QAction(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qaction_set_text(void* action, void* text) { + if (action == nullptr || text == nullptr) return; + static_cast(action)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_text(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->text()); +} + +extern "C" VQT6_API void vqt6_qaction_set_icon(void* action, void* icon) { + if (action == nullptr || icon == nullptr) return; + static_cast(action)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qaction_icon(void* action) { + if (action == nullptr) return nullptr; + return new QIcon(static_cast(action)->icon()); +} + +extern "C" VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence) { + if (action == nullptr || key_sequence == nullptr) return; + static_cast(action)->setShortcut(QKeySequence(*static_cast(key_sequence))); +} + +extern "C" VQT6_API void* vqt6_qaction_shortcut(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->shortcut().toString()); +} + +extern "C" VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable) { + if (action == nullptr) return; + static_cast(action)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checkable(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_checked(void* action, int checked) { + if (action == nullptr) return; + static_cast(action)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checked(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled) { + if (action == nullptr) return; + static_cast(action)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_enabled(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_trigger(void* action) { + if (action == nullptr) return; + static_cast(action)->trigger(); +} + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qstatusbar_create(void) { + return new QStatusBar(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStatusBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms) { + if (sb == nullptr || message == nullptr) return; + static_cast(sb)->showMessage(*static_cast(message), timeout_ms); +} + +extern "C" VQT6_API void vqt6_qstatusbar_clear_message(void* sb) { + if (sb == nullptr) return; + static_cast(sb)->clearMessage(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_current_message(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->currentMessage()); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addPermanentWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create(void) { + return new QToolBar(); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QToolBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w) { + if (tb == nullptr || w == nullptr) return nullptr; + return static_cast(tb)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action) { + if (tb == nullptr || action == nullptr) return; + static_cast(tb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_separator(void* tb) { + if (tb == nullptr) return; + static_cast(tb)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h) { + if (tb == nullptr) return; + static_cast(tb)->setIconSize(QSize(w, h)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation) { + if (tb == nullptr) return; + static_cast(tb)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qtoolbar_orientation(void* tb) { + if (tb == nullptr) return 0; + return static_cast(static_cast(tb)->orientation()); +} + +// ============================================================ +// QMessageBox +// ============================================================ +extern "C" VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0400), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0100), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text) { + if (title == nullptr || text == nullptr) return; + QMessageBox::about(static_cast(parent), *static_cast(title), *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about_qt(void* parent) { + QMessageBox::aboutQt(static_cast(parent)); +} + +// ============================================================ +// QFileDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getOpenFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getSaveFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir) { + QString* result = new QString(QFileDialog::getExistingDirectory( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter) { + return new QStringList(QFileDialog::getOpenFileNames( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); +} diff --git a/vqt6 copy/_bridge_widgets.h b/vqt6 copy/_bridge_widgets.h new file mode 100644 index 0000000..0197377 --- /dev/null +++ b/vqt6 copy/_bridge_widgets.h @@ -0,0 +1,432 @@ +// ============================================================ +// vqt6/_bridge_widgets.h — QtWidgets C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_WIDGETS_H +#define VQT6_BRIDGE_WIDGETS_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QApplication +// ============================================================ +VQT6_API void* vqt6_qapplication_create(int argc, char** argv); +VQT6_API void* vqt6_qapplication_instance(void); +VQT6_API int vqt6_qapplication_exec(void* app); +VQT6_API void vqt6_qapplication_quit(void* app); +VQT6_API void vqt6_qapplication_exit(void* app, int exit_code); +VQT6_API void vqt6_qapplication_process_events(void* app); +VQT6_API int vqt6_qapplication_desktop_width(void* app); +VQT6_API int vqt6_qapplication_desktop_height(void* app); +VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit); +VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app); + +// ============================================================ +// QWidget +// ============================================================ +VQT6_API void* vqt6_qwidget_create(void); +VQT6_API void* vqt6_qwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qwidget_show(void* widget); +VQT6_API void vqt6_qwidget_hide(void* widget); +VQT6_API int vqt6_qwidget_close(void* widget); +VQT6_API int vqt6_qwidget_is_visible(void* widget); +VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible); +VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h); +VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_move(void* widget, int x, int y); +VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y); +VQT6_API int vqt6_qwidget_width(void* widget); +VQT6_API int vqt6_qwidget_height(void* widget); +VQT6_API int vqt6_qwidget_x(void* widget); +VQT6_API int vqt6_qwidget_y(void* widget); +VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title); +VQT6_API void* vqt6_qwidget_window_title(void* widget); +VQT6_API void vqt6_qwidget_set_text(void* widget, void* text); +VQT6_API void* vqt6_qwidget_text(void* widget); +VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled); +VQT6_API int vqt6_qwidget_is_enabled(void* widget); +VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent); +VQT6_API void* vqt6_qwidget_parent_widget(void* widget); +VQT6_API void vqt6_qwidget_set_focus(void* widget); +VQT6_API void vqt6_qwidget_clear_focus(void* widget); +VQT6_API int vqt6_qwidget_has_focus(void* widget); +VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy); +VQT6_API void vqt6_qwidget_update(void* widget); +VQT6_API void vqt6_qwidget_repaint(void* widget); +VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled); +VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags); +VQT6_API int vqt6_qwidget_window_flags(void* widget); +VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor); +VQT6_API void* vqt6_qwidget_cursor(void* widget); +VQT6_API void vqt6_qwidget_unset_cursor(void* widget); +VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_tool_tip(void* widget); +VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_status_tip(void* widget); +VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h); + +// ============================================================ +// QDialog +// ============================================================ +VQT6_API void* vqt6_qdialog_create(void); +VQT6_API void* vqt6_qdialog_create_with_parent(void* parent); +VQT6_API int vqt6_qdialog_exec(void* dialog); +VQT6_API void vqt6_qdialog_done(void* dialog, int result); +VQT6_API void vqt6_qdialog_accept(void* dialog); +VQT6_API void vqt6_qdialog_reject(void* dialog); +VQT6_API void vqt6_qdialog_set_result(void* dialog, int result); +VQT6_API int vqt6_qdialog_result(void* dialog); +VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal); +VQT6_API int vqt6_qdialog_is_modal(void* dialog); + +// ============================================================ +// QMainWindow +// ============================================================ +VQT6_API void* vqt6_qmainwindow_create(void); +VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent); +VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget); +VQT6_API void* vqt6_qmainwindow_central_widget(void* mw); +VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar); +VQT6_API void* vqt6_qmainwindow_status_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw); + +// ============================================================ +// QLabel +// ============================================================ +VQT6_API void* vqt6_qlabel_create(void); +VQT6_API void* vqt6_qlabel_create_with_text(void* text); +VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qlabel_set_text(void* label, void* text); +VQT6_API void* vqt6_qlabel_text(void* label); +VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment); +VQT6_API int vqt6_qlabel_alignment(void* label); +VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap); +VQT6_API void* vqt6_qlabel_pixmap(void* label); +VQT6_API void vqt6_qlabel_set_indent(void* label, int indent); +VQT6_API void vqt6_qlabel_set_margin(void* label, int margin); +VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap); +VQT6_API int vqt6_qlabel_word_wrap(void* label); + +// ============================================================ +// QPushButton +// ============================================================ +VQT6_API void* vqt6_qpushbutton_create(void); +VQT6_API void* vqt6_qpushbutton_create_with_text(void* text); +VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text); +VQT6_API void* vqt6_qpushbutton_text(void* btn); +VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon); +VQT6_API void* vqt6_qpushbutton_icon(void* btn); +VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default); +VQT6_API int vqt6_qpushbutton_is_default(void* btn); +VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat); +VQT6_API int vqt6_qpushbutton_is_flat(void* btn); +VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable); +VQT6_API int vqt6_qpushbutton_is_checkable(void* btn); +VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked); +VQT6_API int vqt6_qpushbutton_is_checked(void* btn); +VQT6_API void vqt6_qpushbutton_click(void* btn); + +// ============================================================ +// QLineEdit +// ============================================================ +VQT6_API void* vqt6_qlineedit_create(void); +VQT6_API void* vqt6_qlineedit_create_with_text(void* text); +VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent); +VQT6_API void* vqt6_qlineedit_text(void* le); +VQT6_API void vqt6_qlineedit_set_text(void* le, void* text); +VQT6_API void* vqt6_qlineedit_placeholder_text(void* le); +VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text); +VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max); +VQT6_API int vqt6_qlineedit_max_length(void* le); +VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro); +VQT6_API int vqt6_qlineedit_is_read_only(void* le); +VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode); +VQT6_API int vqt6_qlineedit_echo_mode(void* le); +VQT6_API void vqt6_qlineedit_select_all(void* le); +VQT6_API void vqt6_qlineedit_clear(void* le); + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +VQT6_API void* vqt6_qtextedit_create(void); +VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qtextedit_to_plain_text(void* te); +VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text); +VQT6_API void vqt6_qtextedit_set_html(void* te, void* html); +VQT6_API void* vqt6_qtextedit_to_html(void* te); +VQT6_API void vqt6_qtextedit_append(void* te, void* text); +VQT6_API void vqt6_qtextedit_clear(void* te); +VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro); +VQT6_API int vqt6_qtextedit_is_read_only(void* te); + +VQT6_API void* vqt6_qplaintextedit_create(void); +VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte); +VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_clear(void* pte); +VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro); +VQT6_API int vqt6_qplaintextedit_line_count(void* pte); + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +VQT6_API void* vqt6_qcheckbox_create(void); +VQT6_API void* vqt6_qcheckbox_create_with_text(void* text); +VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked); +VQT6_API int vqt6_qcheckbox_is_checked(void* cb); +VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text); +VQT6_API void* vqt6_qcheckbox_text(void* cb); +VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate); +VQT6_API int vqt6_qcheckbox_is_tristate(void* cb); + +VQT6_API void* vqt6_qradiobutton_create(void); +VQT6_API void* vqt6_qradiobutton_create_with_text(void* text); +VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked); +VQT6_API int vqt6_qradiobutton_is_checked(void* rb); +VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text); +VQT6_API void* vqt6_qradiobutton_text(void* rb); + +// ============================================================ +// QComboBox +// ============================================================ +VQT6_API void* vqt6_qcombobox_create(void); +VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent); +VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text); +VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items); +VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text); +VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index); +VQT6_API void vqt6_qcombobox_clear(void* cb); +VQT6_API int vqt6_qcombobox_count(void* cb); +VQT6_API int vqt6_qcombobox_current_index(void* cb); +VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index); +VQT6_API void* vqt6_qcombobox_current_text(void* cb); +VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index); +VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable); +VQT6_API int vqt6_qcombobox_is_editable(void* cb); + +// ============================================================ +// QListWidget +// ============================================================ +VQT6_API void* vqt6_qlistwidget_create(void); +VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text); +VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items); +VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text); +VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row); +VQT6_API void vqt6_qlistwidget_clear(void* lw); +VQT6_API int vqt6_qlistwidget_count(void* lw); +VQT6_API int vqt6_qlistwidget_current_row(void* lw); +VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw); +VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row); +VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text); + +// ============================================================ +// QProgressBar +// ============================================================ +VQT6_API void* vqt6_qprogressbar_create(void); +VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent); +VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value); +VQT6_API int vqt6_qprogressbar_value(void* pb); +VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min); +VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max); +VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max); +VQT6_API int vqt6_qprogressbar_minimum(void* pb); +VQT6_API int vqt6_qprogressbar_maximum(void* pb); +VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible); +VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format); +VQT6_API void vqt6_qprogressbar_reset(void* pb); + +// ============================================================ +// QSlider +// ============================================================ +VQT6_API void* vqt6_qslider_create(void); +VQT6_API void* vqt6_qslider_create_with_orientation(int orientation); +VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent); +VQT6_API void vqt6_qslider_set_value(void* s, int value); +VQT6_API int vqt6_qslider_value(void* s); +VQT6_API void vqt6_qslider_set_minimum(void* s, int min); +VQT6_API void vqt6_qslider_set_maximum(void* s, int max); +VQT6_API void vqt6_qslider_set_range(void* s, int min, int max); +VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation); +VQT6_API int vqt6_qslider_orientation(void* s); +VQT6_API void vqt6_qslider_set_single_step(void* s, int step); +VQT6_API void vqt6_qslider_set_page_step(void* s, int step); + +// ============================================================ +// QSpinBox +// ============================================================ +VQT6_API void* vqt6_qspinbox_create(void); +VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent); +VQT6_API int vqt6_qspinbox_value(void* sb); +VQT6_API void vqt6_qspinbox_set_value(void* sb, int value); +VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min); +VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max); +VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max); +VQT6_API int vqt6_qspinbox_minimum(void* sb); +VQT6_API int vqt6_qspinbox_maximum(void* sb); +VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step); +VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix); +VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix); +VQT6_API void* vqt6_qspinbox_prefix(void* sb); +VQT6_API void* vqt6_qspinbox_suffix(void* sb); + +// ============================================================ +// Layouts +// ============================================================ +VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget); +VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget); +VQT6_API int vqt6_qlayout_count(void* layout); +VQT6_API void* vqt6_qlayout_item_at(void* layout, int index); +VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom); +VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing); +VQT6_API int vqt6_qlayout_spacing(void* layout); +VQT6_API void vqt6_qlayout_invalidate(void* layout); + +VQT6_API void* vqt6_qhboxlayout_create(void); +VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qvboxlayout_create(void); +VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qgridlayout_create(void); +VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col); +VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span); + +VQT6_API void* vqt6_qformlayout_create(void); +VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field); +VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field); + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +VQT6_API void* vqt6_qstackedwidget_create(void); +VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w); +VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w); +VQT6_API int vqt6_qstackedwidget_count(void* sw); +VQT6_API int vqt6_qstackedwidget_current_index(void* sw); +VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index); +VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw); +VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index); + +VQT6_API void* vqt6_qtabwidget_create(void); +VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label); +VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label); +VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index); +VQT6_API int vqt6_qtabwidget_count(void* tw); +VQT6_API int vqt6_qtabwidget_current_index(void* tw); +VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index); +VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index); +VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text); +VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable); +VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw); + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +VQT6_API void* vqt6_qmenubar_create(void); +VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent); +VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title); +VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu); +VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action); +VQT6_API void vqt6_qmenubar_clear(void* mb); + +VQT6_API void* vqt6_qmenu_create(void); +VQT6_API void* vqt6_qmenu_create_with_title(void* title); +VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent); +VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title); +VQT6_API void vqt6_qmenu_add_action(void* menu, void* action); +VQT6_API void vqt6_qmenu_add_separator(void* menu); +VQT6_API void vqt6_qmenu_clear(void* menu); +VQT6_API void vqt6_qmenu_set_title(void* menu, void* title); +VQT6_API void* vqt6_qmenu_title(void* menu); +VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text); + +VQT6_API void* vqt6_qaction_create(void); +VQT6_API void* vqt6_qaction_create_with_text(void* text); +VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qaction_set_text(void* action, void* text); +VQT6_API void* vqt6_qaction_text(void* action); +VQT6_API void vqt6_qaction_set_icon(void* action, void* icon); +VQT6_API void* vqt6_qaction_icon(void* action); +VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence); +VQT6_API void* vqt6_qaction_shortcut(void* action); +VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable); +VQT6_API int vqt6_qaction_is_checkable(void* action); +VQT6_API void vqt6_qaction_set_checked(void* action, int checked); +VQT6_API int vqt6_qaction_is_checked(void* action); +VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled); +VQT6_API int vqt6_qaction_is_enabled(void* action); +VQT6_API void vqt6_qaction_trigger(void* action); + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +VQT6_API void* vqt6_qstatusbar_create(void); +VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent); +VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms); +VQT6_API void vqt6_qstatusbar_clear_message(void* sb); +VQT6_API void* vqt6_qstatusbar_current_message(void* sb); +VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch); +VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch); + +VQT6_API void* vqt6_qtoolbar_create(void); +VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent); +VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w); +VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action); +VQT6_API void vqt6_qtoolbar_add_separator(void* tb); +VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h); +VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation); +VQT6_API int vqt6_qtoolbar_orientation(void* tb); + +// ============================================================ +// QMessageBox +// ============================================================ +VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons); +VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text); +VQT6_API void vqt6_qmessagebox_about_qt(void* parent); + +// ============================================================ +// QFileDialog +// ============================================================ +VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir); +VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_WIDGETS_H diff --git a/vqt6 copy/_qtcore.vp b/vqt6 copy/_qtcore.vp new file mode 100644 index 0000000..ddb7035 --- /dev/null +++ b/vqt6 copy/_qtcore.vp @@ -0,0 +1,157 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtcore.py — QtCore 的 t.State FFI 声明 +# +# 所有函数都是 C 桥接层 (libvqt6_bridge.a) 的 extern "C" 函数 +# 命名规范: vqt6__ +# ============================================================ + +# ============================================================ +# QString — UTF-16 字符串 +# ============================================================ +# 创建 QString(从 UTF-8 C 字符串) +def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass + +# 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0) +# buf 需足够大(建议 4 * qstring.length() + 1) +def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass + +# 释放 QString +def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass + +# 获取 QString 字符数 +def vqt6_qstring_length(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 是否为空 +def vqt6_qstring_is_empty(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 比较 +def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.State: pass + +# QString 拼接(返回新 QString) +def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QByteArray — 字节数组 +# ============================================================ +def vqt6_qbytearray_create(data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass +def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass + + +# ============================================================ +# QObject — 所有 Qt 对象的基类 +# ============================================================ +# 注意: Qt 对象的内存由 C++ 管理,Viper 端不应直接 free +def vqt6_qobject_delete(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_delete_later(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_set_object_name(obj: QtObjectPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qobject_object_name(obj: QtObjectPtr) -> QtStringPtr | t.State: pass +def vqt6_qobject_set_parent(child: QtObjectPtr, parent: QtObjectPtr) -> t.State: pass +def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass + +# 信号/槽连接 (简化版: 函数指针形式) +# typedef void (*vqt6_callback_t)(void* user_data); +# vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理 +# 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表 +def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +# 事件过滤器 +def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass +def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QCoreApplication — 事件循环基类 +# ============================================================ +def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_exit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_process_events(app: QtCoreAppPtr, flags: t.CInt) -> t.State: pass +def vqt6_qcoreapp_post_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.State: pass +def vqt6_qcoreapp_send_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_organization_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_organization_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qcoreapp_application_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_application_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QTimer — 定时器 +# ============================================================ +def vqt6_qtimer_create() -> QtTimerPtr | t.State: pass +def vqt6_qtimer_create_with_parent(parent: QtObjectPtr) -> QtTimerPtr | t.State: pass +def vqt6_qtimer_start(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_stop(timer: QtTimerPtr) -> t.State: pass +def vqt6_qtimer_set_interval(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_interval(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_is_active(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_set_single_shot(timer: QtTimerPtr, single_shot: t.CInt) -> t.State: pass +def vqt6_qtimer_is_single_shot(timer: QtTimerPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QVariant — 通用数据容器 +# ============================================================ +def vqt6_qvariant_create_int(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_double(value: t.CDouble) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_bool(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_string(s: QtStringPtr) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_to_int(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_double(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qvariant_to_bool(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_string(v: QtVariantPtr) -> QtStringPtr | t.State: pass +def vqt6_qvariant_type_id(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_is_valid(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_free(v: QtVariantPtr) -> t.State: pass + + +# ============================================================ +# QEvent — 事件基类 +# ============================================================ +def vqt6_qevent_type(event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qevent_accept(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_ignore(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_is_accepted(event: QtEventPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 字符串列表 (QStringList / QList) +# ============================================================ +def vqt6_qstringlist_create() -> QtStringListPtr | t.State: pass +def vqt6_qstringlist_append(list: QtStringListPtr, str: QtStringPtr) -> t.State: pass +def vqt6_qstringlist_size(list: QtStringListPtr) -> t.CInt | t.State: pass +def vqt6_qstringlist_at(list: QtStringListPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qstringlist_free(list: QtStringListPtr) -> t.State: pass + + +# ============================================================ +# 字节数组列表 (QList) +# ============================================================ +def vqt6_qbytearraylist_create() -> QtByteArrayListPtr | t.State: pass +def vqt6_qbytearraylist_append(list: QtByteArrayListPtr, qba: QtByteArrayPtr) -> t.State: pass +def vqt6_qbytearraylist_size(list: QtByteArrayListPtr) -> t.CInt | t.State: pass +def vqt6_qbytearraylist_at(list: QtByteArrayListPtr, index: t.CInt) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearraylist_free(list: QtByteArrayListPtr) -> t.State: pass + + +# ============================================================ +# 全局回调注册表 +# ============================================================ +# 用于从 C++ 端回调 Viper 代码 +# Viper 注册一个 slot 函数(用整数 ID 标识),C++ 在触发信号时通过 ID 查找 +# typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +def vqt6_register_slot(slot_id: t.CInt, user_data: t.CVoid | t.CPtr) -> t.State: pass +def vqt6_unregister_slot(slot_id: t.CInt) -> t.State: pass +def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用 diff --git a/vqt6 copy/_qtgui.vp b/vqt6 copy/_qtgui.vp new file mode 100644 index 0000000..80f0094 --- /dev/null +++ b/vqt6 copy/_qtgui.vp @@ -0,0 +1,237 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtgui.py — QtGui 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QColor — 颜色 +# ============================================================ +def vqt6_qcolor_create_rgb(r: t.CInt, g: t.CInt, b: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_rgba(r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_name(name: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_hex(hex_str: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_red(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_green(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_blue(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_alpha(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_set_red(c: QtColorPtr, r: t.CInt) -> t.State: pass +def vqt6_qcolor_set_green(c: QtColorPtr, g: t.CInt) -> t.State: pass +def vqt6_qcolor_set_blue(c: QtColorPtr, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_alpha(c: QtColorPtr, a: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgb(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgba(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> t.State: pass +def vqt6_qcolor_name(c: QtColorPtr) -> QtStringPtr | t.State: pass +def vqt6_qcolor_is_valid(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_free(c: QtColorPtr) -> t.State: pass + + +# ============================================================ +# QFont — 字体 +# ============================================================ +def vqt6_qfont_create() -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family(family: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family_size(family: QtStringPtr, point_size: t.CInt) -> QtFontPtr | t.State: pass +def vqt6_qfont_set_family(font: QtFontPtr, family: QtStringPtr) -> t.State: pass +def vqt6_qfont_family(font: QtFontPtr) -> QtStringPtr | t.State: pass +def vqt6_qfont_set_point_size(font: QtFontPtr, point_size: t.CInt) -> t.State: pass +def vqt6_qfont_point_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_pixel_size(font: QtFontPtr, pixel_size: t.CInt) -> t.State: pass +def vqt6_qfont_pixel_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_bold(font: QtFontPtr, bold: t.CInt) -> t.State: pass +def vqt6_qfont_bold(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_italic(font: QtFontPtr, italic: t.CInt) -> t.State: pass +def vqt6_qfont_italic(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_underline(font: QtFontPtr, underline: t.CInt) -> t.State: pass +def vqt6_qfont_underline(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_strike_out(font: QtFontPtr, strike_out: t.CInt) -> t.State: pass +def vqt6_qfont_strike_out(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_weight(font: QtFontPtr, weight: t.CInt) -> t.State: pass +def vqt6_qfont_weight(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_free(font: QtFontPtr) -> t.State: pass + + +# ============================================================ +# QFontMetrics — 字体度量 +# ============================================================ +def vqt6_qfontmetrics_create(font: QtFontPtr) -> QtFontMetricsPtr | t.State: pass +def vqt6_qfontmetrics_width(fm: QtFontMetricsPtr, text: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_height(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_ascent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_descent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_free(fm: QtFontMetricsPtr) -> t.State: pass + + +# ============================================================ +# QPixmap — 像素图 +# ============================================================ +def vqt6_qpixmap_create() -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_create_with_size(w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_load(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_load_from_data(pm: QtPixmapPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CInt | t.State: pass +def vqt6_qpixmap_save(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_width(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_height(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_is_null(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_scaled(pm: QtPixmapPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_fill(pm: QtPixmapPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpixmap_free(pm: QtPixmapPtr) -> t.State: pass + + +# ============================================================ +# QImage — 图像 +# ============================================================ +def vqt6_qimage_create() -> QtImagePtr | t.State: pass +def vqt6_qimage_create_with_size(w: t.CInt, h: t.CInt, format: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_load(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_save(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_width(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_height(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_format(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_is_null(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_fill(img: QtImagePtr, color: QtColorPtr) -> t.State: pass +def vqt6_qimage_scaled(img: QtImagePtr, w: t.CInt, h: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_free(img: QtImagePtr) -> t.State: pass + + +# ============================================================ +# QPainter — 绘画器 +# ============================================================ +def vqt6_qpainter_create() -> QtPainterPtr | t.State: pass +def vqt6_qpainter_begin(p: QtPainterPtr, device: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_end(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_is_active(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_set_pen(p: QtPainterPtr, pen: QtPenPtr) -> t.State: pass +def vqt6_qpainter_set_brush(p: QtPainterPtr, brush: QtBrushPtr) -> t.State: pass +def vqt6_qpainter_set_font(p: QtPainterPtr, font: QtFontPtr) -> t.State: pass +def vqt6_qpainter_pen(p: QtPainterPtr) -> QtPenPtr | t.State: pass +def vqt6_qpainter_brush(p: QtPainterPtr) -> QtBrushPtr | t.State: pass +def vqt6_qpainter_font(p: QtPainterPtr) -> QtFontPtr | t.State: pass +def vqt6_qpainter_set_opacity(p: QtPainterPtr, opacity: t.CDouble) -> t.State: pass +def vqt6_qpainter_opacity(p: QtPainterPtr) -> t.CDouble | t.State: pass + +# 绘图原语 +def vqt6_qpainter_draw_line(p: QtPainterPtr, x1: t.CInt, y1: t.CInt, x2: t.CInt, y2: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_fill_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, color: QtColorPtr) -> t.State: pass +def vqt6_qpainter_draw_ellipse(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_arc(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_chord(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_pie(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polygon(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polyline(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_point(p: QtPainterPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_points(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_text(p: QtPainterPtr, x: t.CInt, y: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_text_in_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, flags: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qpainter_draw_image(p: QtPainterPtr, x: t.CInt, y: t.CInt, image: QtImagePtr) -> t.State: pass +def vqt6_qpainter_draw_tiled_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass + +# 变换 +def vqt6_qpainter_translate(p: QtPainterPtr, dx: t.CInt, dy: t.CInt) -> t.State: pass +def vqt6_qpainter_rotate(p: QtPainterPtr, angle: t.CDouble) -> t.State: pass +def vqt6_qpainter_scale(p: QtPainterPtr, sx: t.CDouble, sy: t.CDouble) -> t.State: pass +def vqt6_qpainter_reset_transform(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_save(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_restore(p: QtPainterPtr) -> t.State: pass + +def vqt6_qpainter_free(p: QtPainterPtr) -> t.State: pass + + +# ============================================================ +# QPen — 画笔 +# ============================================================ +def vqt6_qpen_create() -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color(color: QtColorPtr) -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color_width(color: QtColorPtr, width: t.CInt) -> QtPenPtr | t.State: pass +def vqt6_qpen_set_color(pen: QtPenPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpen_color(pen: QtPenPtr) -> QtColorPtr | t.State: pass +def vqt6_qpen_set_width(pen: QtPenPtr, width: t.CInt) -> t.State: pass +def vqt6_qpen_width(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_set_style(pen: QtPenPtr, style: t.CInt) -> t.State: pass +def vqt6_qpen_style(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_free(pen: QtPenPtr) -> t.State: pass + + +# ============================================================ +# QBrush — 画刷 +# ============================================================ +def vqt6_qbrush_create() -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_color(color: QtColorPtr) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_style(style: t.CInt) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_set_color(brush: QtBrushPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qbrush_color(brush: QtBrushPtr) -> QtColorPtr | t.State: pass +def vqt6_qbrush_set_style(brush: QtBrushPtr, style: t.CInt) -> t.State: pass +def vqt6_qbrush_style(brush: QtBrushPtr) -> t.CInt | t.State: pass +def vqt6_qbrush_free(brush: QtBrushPtr) -> t.State: pass + + +# ============================================================ +# QIcon — 图标 +# ============================================================ +def vqt6_qicon_create() -> QtIconPtr | t.State: pass +def vqt6_qicon_create_with_file(file_name: QtStringPtr) -> QtIconPtr | t.State: pass +def vqt6_qicon_add_file(icon: QtIconPtr, file_name: QtStringPtr) -> t.State: pass +def vqt6_qicon_add_pixmap(icon: QtIconPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qicon_is_null(icon: QtIconPtr) -> t.CInt | t.State: pass +def vqt6_qicon_pixmap(icon: QtIconPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qicon_free(icon: QtIconPtr) -> t.State: pass + + +# ============================================================ +# QCursor — 鼠标光标 +# ============================================================ +def vqt6_qcursor_create() -> QtCursorPtr | t.State: pass +def vqt6_qcursor_create_with_shape(shape: t.CInt) -> QtCursorPtr | t.State: pass +def vqt6_qcursor_pos(x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qcursor_set_pos(x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qcursor_set_shape(cursor: QtCursorPtr, shape: t.CInt) -> t.State: pass +def vqt6_qcursor_shape(cursor: QtCursorPtr) -> t.CInt | t.State: pass +def vqt6_qcursor_free(cursor: QtCursorPtr) -> t.State: pass + + +# ============================================================ +# QKeyEvent — 键盘事件 +# ============================================================ +def vqt6_qkeyevent_create(type: t.CInt, key: t.CInt, modifiers: t.CInt, text: QtStringPtr) -> QtKeyEventPtr | t.State: pass +def vqt6_qkeyevent_key(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_text(event: QtKeyEventPtr) -> QtStringPtr | t.State: pass +def vqt6_qkeyevent_modifiers(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_is_auto_repeat(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_free(event: QtKeyEventPtr) -> t.State: pass + + +# ============================================================ +# QMouseEvent — 鼠标事件 +# ============================================================ +def vqt6_qmouseevent_create(type: t.CInt, local_pos: QtObjectPtr, button: t.CInt, buttons: t.CInt, modifiers: t.CInt) -> QtMouseEventPtr | t.State: pass +def vqt6_qmouseevent_button(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_buttons(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_modifiers(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_free(event: QtMouseEventPtr) -> t.State: pass + + +# ============================================================ +# QResizeEvent / QPaintEvent / QCloseEvent +# ============================================================ +def vqt6_qresizeevent_create(width: t.CInt, height: t.CInt, old_width: t.CInt, old_height: t.CInt) -> QtResizeEventPtr | t.State: pass +def vqt6_qresizeevent_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_old_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_free(event: QtResizeEventPtr) -> t.State: pass + +def vqt6_qpaintevent_create(rect_x: t.CInt, rect_y: t.CInt, rect_w: t.CInt, rect_h: t.CInt) -> QtPaintEventPtr | t.State: pass +def vqt6_qpaintevent_rect(event: QtPaintEventPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qpaintevent_free(event: QtPaintEventPtr) -> t.State: pass + +def vqt6_qcloseevent_create() -> QtCloseEventPtr | t.State: pass +def vqt6_qcloseevent_is_accepted(event: QtCloseEventPtr) -> t.CInt | t.State: pass +def vqt6_qcloseevent_accept(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_ignore(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_free(event: QtCloseEventPtr) -> t.State: pass diff --git a/vqt6 copy/_qtnetwork.vp b/vqt6 copy/_qtnetwork.vp new file mode 100644 index 0000000..6859d8b --- /dev/null +++ b/vqt6 copy/_qtnetwork.vp @@ -0,0 +1,184 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtnetwork.py — QtNetwork 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QHostAddress — IP 地址 +# ============================================================ +def vqt6_qhostaddress_create() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_ipv4(ipv4: t.CUInt32T) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_string(address: QtStringPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_host() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_broadcast() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_any_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_to_string(addr: QtHostAddressPtr) -> QtStringPtr | t.State: pass +def vqt6_qhostaddress_to_ipv4(addr: QtHostAddressPtr) -> t.CUInt32T | t.State: pass +def vqt6_qhostaddress_is_null(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_loopback(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_broadcast(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_protocol(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_free(addr: QtHostAddressPtr) -> t.State: pass + + +# ============================================================ +# QAbstractSocket — TCP/UDP 套接字基类 +# ============================================================ +# 套接字状态 +QT_SOCKET_UNCONNECTED_STATE: t.CDefine = 0 +QT_SOCKET_HOST_LOOKUP_STATE: t.CDefine = 1 +QT_SOCKET_CONNECTING_STATE: t.CDefine = 2 +QT_SOCKET_CONNECTED_STATE: t.CDefine = 3 +QT_SOCKET_BOUND_STATE: t.CDefine = 4 +QT_SOCKET_LISTENING_STATE: t.CDefine = 5 +QT_SOCKET_CLOSING_STATE: t.CDefine = 6 + +# 套接字类型 +QT_SOCKET_TCP: t.CDefine = 0 +QT_SOCKET_UDP: t.CDefine = 1 + +# 套接字错误 +QT_SOCKET_NO_ERROR: t.CDefine = 0 + +# 通用方法 +def vqt6_qabstractsocket_state(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error_string(socket: QtAbstractSocketPtr) -> QtStringPtr | t.State: pass +def vqt6_qabstractsocket_connect_to_host(socket: QtAbstractSocketPtr, host_name: QtStringPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_connect_to_host_with_addr(socket: QtAbstractSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_disconnect_from_host(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_wait_for_connected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_ready_read(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_bytes_written(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_disconnected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_valid(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_open(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_flush(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_close(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_abort(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_read(socket: QtAbstractSocketPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_read_all(socket: QtAbstractSocketPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qabstractsocket_write(socket: QtAbstractSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_available(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_to_write(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_peer_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_peer_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass +def vqt6_qabstractsocket_local_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_local_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass + + +# ============================================================ +# QTcpSocket — TCP 套接字 +# ============================================================ +def vqt6_qtcpsocket_create() -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_create_with_parent(parent: QtObjectPtr) -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_connect_to_host(socket: QtTcpSocketPtr, host_name: QtStringPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_connect_to_host_with_addr(socket: QtTcpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_set_socket_descriptor(socket: QtTcpSocketPtr, socket_descriptor: t.CInt) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_socket_descriptor(socket: QtTcpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_set_proxy(socket: QtTcpSocketPtr, proxy_type: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_abort(socket: QtTcpSocketPtr) -> t.State: pass + + +# ============================================================ +# QUdpSocket — UDP 套接字 +# ============================================================ +def vqt6_qudpsocket_create() -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_create_with_parent(parent: QtObjectPtr) -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_bind(socket: QtUdpSocketPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_bind_with_addr(socket: QtUdpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_close(socket: QtUdpSocketPtr) -> t.State: pass +def vqt6_qudpsocket_write_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_read_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, max_size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T | t.CPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_has_pending_datagrams(socket: QtUdpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_pending_datagram_size(socket: QtUdpSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_join_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_leave_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QNetworkRequest — 网络请求 +# ============================================================ +def vqt6_qnetworkrequest_create() -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_create_with_url(url: QtStringPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_set_url(req: QtNetworkRequestPtr, url: QtStringPtr) -> t.State: pass +def vqt6_qnetworkrequest_url(req: QtNetworkRequestPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkrequest_set_header(req: QtNetworkRequestPtr, header_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_header(req: QtNetworkRequestPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_set_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass +def vqt6_qnetworkrequest_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkrequest_set_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_free(req: QtNetworkRequestPtr) -> t.State: pass + + +# ============================================================ +# QNetworkAccessManager — HTTP 客户端管理器 +# ============================================================ +def vqt6_qnetworkaccessmanager_create() -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_create_with_parent(parent: QtObjectPtr) -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_get(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_post(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_put(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_delete_resource(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_head(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_set_cookie_store(nam: QtNetworkAccessManagerPtr, store: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QNetworkReply — 网络响应 +# ============================================================ +def vqt6_qnetworkreply_url(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_request(reply: QtNetworkReplyPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkreply_error(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_error_string(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_is_finished(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_is_running(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_abort(reply: QtNetworkReplyPtr) -> t.State: pass +def vqt6_qnetworkreply_read(reply: QtNetworkReplyPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_read_all(reply: QtNetworkReplyPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_bytes_available(reply: QtNetworkReplyPtr) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_header(reply: QtNetworkReplyPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_attribute(reply: QtNetworkReplyPtr, attribute_code: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_attribute_int(reply: QtNetworkReplyPtr, attribute_code: t.CInt, default_value: t.CInt) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_set_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass + + +# ============================================================ +# 套接字类型枚举 +# ============================================================ +# 套接字类型 +QT_ABSTRACT_SOCKET_TCP: t.CDefine = 0 +QT_ABSTRACT_SOCKET_UDP: t.CDefine = 1 + +# 网络层协议 +QT_NETWORK_IPV4_PROTOCOL: t.CDefine = 0 +QT_NETWORK_IPV6_PROTOCOL: t.CDefine = 1 +QT_NETWORK_ANY_IP_PROTOCOL: t.CDefine = 2 + +# 主机地址特殊情况 +QT_HOST_ADDRESS_LOCAL_HOST: t.CDefine = 0x00000000 +QT_HOST_ADDRESS_LOCAL_HOST_IPV6: t.CDefine = 0x00000001 +QT_HOST_ADDRESS_BROADCAST: t.CDefine = 0x00000002 +QT_HOST_ADDRESS_ANY_IPV4: t.CDefine = 0x00000004 +QT_HOST_ADDRESS_ANY_IPV6: t.CDefine = 0x00000005 + + +# ============================================================ +# 已知端口常量 +# ============================================================ +QT_PORT_FTP: t.CDefine = 21 +QT_PORT_SSH: t.CDefine = 22 +QT_PORT_TELNET: t.CDefine = 23 +QT_PORT_SMTP: t.CDefine = 25 +QT_PORT_DNS: t.CDefine = 53 +QT_PORT_HTTP: t.CDefine = 80 +QT_PORT_POP3: t.CDefine = 110 +QT_PORT_IMAP: t.CDefine = 143 +QT_PORT_HTTPS: t.CDefine = 443 +QT_PORT_SMB: t.CDefine = 445 diff --git a/vqt6 copy/_qtwidgets.vp b/vqt6 copy/_qtwidgets.vp new file mode 100644 index 0000000..025d026 --- /dev/null +++ b/vqt6 copy/_qtwidgets.vp @@ -0,0 +1,478 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtwidgets.py — QtWidgets 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QApplication — GUI 应用入口 +# ============================================================ +# argc/argv 通过单独的 buffer 数组传入(Viper 中 C 数组使用指针+长度) +def vqt6_qapplication_create(argc: t.CInt, argv: t.CPtr | t.CPtr) -> QtAppPtr | t.State: pass +def vqt6_qapplication_instance() -> QtAppPtr | t.State: pass +def vqt6_qapplication_exec(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_quit(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_exit(app: QtAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qapplication_process_events(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_desktop_width(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_desktop_height(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_set_quit_on_last_window_closed(app: QtAppPtr, quit: t.CInt) -> t.State: pass +def vqt6_qapplication_quit_on_last_window_closed(app: QtAppPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QWidget — 所有窗口的基类 +# ============================================================ +def vqt6_qwidget_create() -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_create_with_parent(parent: QtWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_show(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_hide(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_close(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_is_visible(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_visible(widget: QtWidgetPtr, visible: t.CInt) -> t.State: pass + +# 几何 +def vqt6_qwidget_set_geometry(widget: QtWidgetPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_geometry(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_resize(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_move(widget: QtWidgetPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qwidget_pos(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_width(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_height(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_x(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_y(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 文本与标题 +def vqt6_qwidget_set_window_title(widget: QtWidgetPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qwidget_window_title(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qwidget_set_text(widget: QtWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qwidget_text(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 启用 +def vqt6_qwidget_set_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qwidget_is_enabled(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 父对象 +def vqt6_qwidget_set_parent(widget: QtWidgetPtr, parent: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_parent_widget(widget: QtWidgetPtr) -> QtWidgetPtr | t.State: pass + +# 焦点 +def vqt6_qwidget_set_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_clear_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_has_focus(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_focus_policy(widget: QtWidgetPtr, policy: t.CInt) -> t.State: pass + +# 更新 +def vqt6_qwidget_update(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_repaint(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_set_update_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass + +# 窗口标志 +def vqt6_qwidget_set_window_flags(widget: QtWidgetPtr, flags: t.CInt) -> t.State: pass +def vqt6_qwidget_window_flags(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 鼠标光标 +def vqt6_qwidget_set_cursor(widget: QtWidgetPtr, cursor: QtCursorPtr) -> t.State: pass +def vqt6_qwidget_cursor(widget: QtWidgetPtr) -> QtCursorPtr | t.State: pass +def vqt6_qwidget_unset_cursor(widget: QtWidgetPtr) -> t.State: pass + +# 工具提示 +def vqt6_qwidget_set_tool_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_tool_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 状态栏提示 +def vqt6_qwidget_set_status_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_status_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 最小/最大尺寸 +def vqt6_qwidget_set_minimum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_maximum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_fixed_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_minimum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_maximum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass + + +# ============================================================ +# QDialog — 对话框 +# ============================================================ +def vqt6_qdialog_create() -> QtDialogPtr | t.State: pass +def vqt6_qdialog_create_with_parent(parent: QtWidgetPtr) -> QtDialogPtr | t.State: pass +def vqt6_qdialog_exec(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_done(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_accept(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_reject(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_set_result(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_result(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_set_modal(dialog: QtDialogPtr, modal: t.CInt) -> t.State: pass +def vqt6_qdialog_is_modal(dialog: QtDialogPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMainWindow — 主窗口 +# ============================================================ +def vqt6_qmainwindow_create() -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_create_with_parent(parent: QtWidgetPtr) -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_set_central_widget(mw: QtMainWindowPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qmainwindow_central_widget(mw: QtMainWindowPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qmainwindow_menu_bar(mw: QtMainWindowPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmainwindow_set_menu_bar(mw: QtMainWindowPtr, menubar: QtMenuBarPtr) -> t.State: pass +def vqt6_qmainwindow_status_bar(mw: QtMainWindowPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qmainwindow_set_status_bar(mw: QtMainWindowPtr, statusbar: QtStatusBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar(mw: QtMainWindowPtr, toolbar: QtToolBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar_break(mw: QtMainWindowPtr) -> t.State: pass + + +# ============================================================ +# QLabel — 标签 +# ============================================================ +def vqt6_qlabel_create() -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text(text: QtStringPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_set_text(label: QtLabelPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlabel_text(label: QtLabelPtr) -> QtStringPtr | t.State: pass +def vqt6_qlabel_set_alignment(label: QtLabelPtr, alignment: t.CInt) -> t.State: pass +def vqt6_qlabel_alignment(label: QtLabelPtr) -> t.CInt | t.State: pass +def vqt6_qlabel_set_pixmap(label: QtLabelPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qlabel_pixmap(label: QtLabelPtr) -> QtPixmapPtr | t.State: pass +def vqt6_qlabel_set_indent(label: QtLabelPtr, indent: t.CInt) -> t.State: pass +def vqt6_qlabel_set_margin(label: QtLabelPtr, margin: t.CInt) -> t.State: pass +def vqt6_qlabel_set_word_wrap(label: QtLabelPtr, wrap: t.CInt) -> t.State: pass +def vqt6_qlabel_word_wrap(label: QtLabelPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QPushButton — 按钮 +# ============================================================ +def vqt6_qpushbutton_create() -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text(text: QtStringPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_set_text(btn: QtPushButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qpushbutton_text(btn: QtPushButtonPtr) -> QtStringPtr | t.State: pass +def vqt6_qpushbutton_set_icon(btn: QtPushButtonPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qpushbutton_icon(btn: QtPushButtonPtr) -> QtIconPtr | t.State: pass +def vqt6_qpushbutton_set_default(btn: QtPushButtonPtr, is_default: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_default(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_flat(btn: QtPushButtonPtr, flat: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_flat(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checkable(btn: QtPushButtonPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checkable(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checked(btn: QtPushButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checked(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_click(btn: QtPushButtonPtr) -> t.State: pass + + +# ============================================================ +# QLineEdit — 单行输入框 +# ============================================================ +def vqt6_qlineedit_create() -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text(text: QtStringPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_placeholder_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_placeholder_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_set_max_length(le: QtLineEditPtr, max: t.CInt) -> t.State: pass +def vqt6_qlineedit_max_length(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_read_only(le: QtLineEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qlineedit_is_read_only(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_echo_mode(le: QtLineEditPtr, mode: t.CInt) -> t.State: pass +def vqt6_qlineedit_echo_mode(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_select_all(le: QtLineEditPtr) -> t.State: pass +def vqt6_qlineedit_clear(le: QtLineEditPtr) -> t.State: pass + + +# ============================================================ +# QTextEdit / QPlainTextEdit — 多行文本编辑器 +# ============================================================ +def vqt6_qtextedit_create() -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_create_with_parent(parent: QtWidgetPtr) -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_to_plain_text(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_set_plain_text(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_set_html(te: QtTextEditPtr, html: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_to_html(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_append(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_clear(te: QtTextEditPtr) -> t.State: pass +def vqt6_qtextedit_set_read_only(te: QtTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qtextedit_is_read_only(te: QtTextEditPtr) -> t.CInt | t.State: pass + +def vqt6_qplaintextedit_create() -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_create_with_parent(parent: QtWidgetPtr) -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_to_plain_text(pte: QtPlainTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qplaintextedit_set_plain_text(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_append(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_clear(pte: QtPlainTextEditPtr) -> t.State: pass +def vqt6_qplaintextedit_set_read_only(pte: QtPlainTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qplaintextedit_line_count(pte: QtPlainTextEditPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QCheckBox / QRadioButton — 复选/单选 +# ============================================================ +def vqt6_qcheckbox_create() -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text(text: QtStringPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_set_checked(cb: QtCheckBoxPtr, checked: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_checked(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcheckbox_set_text(cb: QtCheckBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcheckbox_text(cb: QtCheckBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcheckbox_set_tristate(cb: QtCheckBoxPtr, tristate: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_tristate(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass + +def vqt6_qradiobutton_create() -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text(text: QtStringPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_set_checked(rb: QtRadioButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qradiobutton_is_checked(rb: QtRadioButtonPtr) -> t.CInt | t.State: pass +def vqt6_qradiobutton_set_text(rb: QtRadioButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qradiobutton_text(rb: QtRadioButtonPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QComboBox — 下拉框 +# ============================================================ +def vqt6_qcombobox_create() -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_create_with_parent(parent: QtWidgetPtr) -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_add_item(cb: QtComboBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_add_items(cb: QtComboBoxPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qcombobox_insert_item(cb: QtComboBoxPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_remove_item(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_clear(cb: QtComboBoxPtr) -> t.State: pass +def vqt6_qcombobox_count(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_current_index(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_set_current_index(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_current_text(cb: QtComboBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_item_text(cb: QtComboBoxPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_set_editable(cb: QtComboBoxPtr, editable: t.CInt) -> t.State: pass +def vqt6_qcombobox_is_editable(cb: QtComboBoxPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QListWidget — 列表控件 +# ============================================================ +def vqt6_qlistwidget_create() -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_create_with_parent(parent: QtWidgetPtr) -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_add_item(lw: QtListWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_add_items(lw: QtListWidgetPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qlistwidget_insert_item(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_remove_item_widget(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_take_item(lw: QtListWidgetPtr, row: t.CInt) -> QtListWidgetItemPtr | t.State: pass +def vqt6_qlistwidget_clear(lw: QtListWidgetPtr) -> t.State: pass +def vqt6_qlistwidget_count(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_current_row(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_set_current_row(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_current_item_text(lw: QtListWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_item_text(lw: QtListWidgetPtr, row: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_set_item_text(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QProgressBar — 进度条 +# ============================================================ +def vqt6_qprogressbar_create() -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_create_with_parent(parent: QtWidgetPtr) -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_set_value(pb: QtProgressBarPtr, value: t.CInt) -> t.State: pass +def vqt6_qprogressbar_value(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_minimum(pb: QtProgressBarPtr, min: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_maximum(pb: QtProgressBarPtr, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_range(pb: QtProgressBarPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_minimum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_maximum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_text_visible(pb: QtProgressBarPtr, visible: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_format(pb: QtProgressBarPtr, format: QtStringPtr) -> t.State: pass +def vqt6_qprogressbar_reset(pb: QtProgressBarPtr) -> t.State: pass + + +# ============================================================ +# QSlider — 滑块 +# ============================================================ +def vqt6_qslider_create() -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation(orientation: t.CInt) -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation_parent(orientation: t.CInt, parent: QtWidgetPtr) -> QtSliderPtr | t.State: pass +def vqt6_qslider_set_value(s: QtSliderPtr, value: t.CInt) -> t.State: pass +def vqt6_qslider_value(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_minimum(s: QtSliderPtr, min: t.CInt) -> t.State: pass +def vqt6_qslider_set_maximum(s: QtSliderPtr, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_range(s: QtSliderPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_orientation(s: QtSliderPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qslider_orientation(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_single_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass +def vqt6_qslider_set_page_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass + + +# ============================================================ +# QSpinBox — 数字输入框 +# ============================================================ +def vqt6_qspinbox_create() -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_create_with_parent(parent: QtWidgetPtr) -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_value(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_value(sb: QtSpinBoxPtr, value: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_minimum(sb: QtSpinBoxPtr, min: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_maximum(sb: QtSpinBoxPtr, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_range(sb: QtSpinBoxPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_minimum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_maximum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_single_step(sb: QtSpinBoxPtr, step: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_prefix(sb: QtSpinBoxPtr, prefix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_set_suffix(sb: QtSpinBoxPtr, suffix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_prefix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qspinbox_suffix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# 布局 - QLayout / QBoxLayout / QGridLayout / QFormLayout +# ============================================================ +def vqt6_qlayout_add_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_remove_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_count(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_item_at(layout: QtLayoutPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass +def vqt6_qlayout_set_contents_margins(layout: QtLayoutPtr, left: t.CInt, top: t.CInt, right: t.CInt, bottom: t.CInt) -> t.State: pass +def vqt6_qlayout_set_spacing(layout: QtLayoutPtr, spacing: t.CInt) -> t.State: pass +def vqt6_qlayout_spacing(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_invalidate(layout: QtLayoutPtr) -> t.State: pass + +# QHBoxLayout +def vqt6_qhboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qhboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qhboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QVBoxLayout +def vqt6_qvboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qvboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qvboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QGridLayout +def vqt6_qgridlayout_create() -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_create_with_parent(parent: QtWidgetPtr) -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_add_widget(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt) -> t.State: pass +def vqt6_qgridlayout_add_widget_with_span(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt, row_span: t.CInt, col_span: t.CInt) -> t.State: pass + +# QFormLayout +def vqt6_qformlayout_create() -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_create_with_parent(parent: QtWidgetPtr) -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_add_row(fl: QtFormLayoutPtr, label: QtStringPtr, field: QtWidgetPtr) -> t.State: pass +def vqt6_qformlayout_add_row_widget_pair(fl: QtFormLayoutPtr, label: QtWidgetPtr, field: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QStackedWidget / QTabWidget +# ============================================================ +def vqt6_qstackedwidget_create() -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_create_with_parent(parent: QtWidgetPtr) -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_add_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_remove_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.State: pass +def vqt6_qstackedwidget_count(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_current_index(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_set_current_index(sw: QtStackedWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qstackedwidget_current_widget(sw: QtStackedWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qstackedwidget_widget(sw: QtStackedWidgetPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass + +def vqt6_qtabwidget_create() -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_create_with_parent(parent: QtWidgetPtr) -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_add_tab(tw: QtTabWidgetPtr, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_insert_tab(tw: QtTabWidgetPtr, index: t.CInt, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_remove_tab(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_count(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_current_index(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_set_current_index(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tab_text(tw: QtTabWidgetPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qtabwidget_set_tab_text(tw: QtTabWidgetPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qtabwidget_set_tabs_closable(tw: QtTabWidgetPtr, closable: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tabs_closable(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMenuBar / QMenu / QAction +# ============================================================ +def vqt6_qmenubar_create() -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_create_with_parent(parent: QtWidgetPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_add_menu(mb: QtMenuBarPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenubar_add_menu_with_menu(mb: QtMenuBarPtr, menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenubar_add_action(mb: QtMenuBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenubar_clear(mb: QtMenuBarPtr) -> t.State: pass + +def vqt6_qmenu_create() -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title(title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title_parent(title: QtStringPtr, parent: QtWidgetPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_menu(menu: QtMenuPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_action(menu: QtMenuPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenu_add_separator(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_clear(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_set_title(menu: QtMenuPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qmenu_title(menu: QtMenuPtr) -> QtStringPtr | t.State: pass +def vqt6_qmenu_add_action_with_text(menu: QtMenuPtr, text: QtStringPtr) -> QtActionPtr | t.State: pass + +def vqt6_qaction_create() -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text(text: QtStringPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_set_text(action: QtActionPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qaction_text(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_icon(action: QtActionPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qaction_icon(action: QtActionPtr) -> QtIconPtr | t.State: pass +def vqt6_qaction_set_shortcut(action: QtActionPtr, key_sequence: QtStringPtr) -> t.State: pass +def vqt6_qaction_shortcut(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_checkable(action: QtActionPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qaction_is_checkable(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_checked(action: QtActionPtr, checked: t.CInt) -> t.State: pass +def vqt6_qaction_is_checked(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_enabled(action: QtActionPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qaction_is_enabled(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_trigger(action: QtActionPtr) -> t.State: pass + + +# ============================================================ +# QStatusBar / QToolBar +# ============================================================ +def vqt6_qstatusbar_create() -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_create_with_parent(parent: QtWidgetPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_show_message(sb: QtStatusBarPtr, message: QtStringPtr, timeout_ms: t.CInt) -> t.State: pass +def vqt6_qstatusbar_clear_message(sb: QtStatusBarPtr) -> t.State: pass +def vqt6_qstatusbar_current_message(sb: QtStatusBarPtr) -> QtStringPtr | t.State: pass +def vqt6_qstatusbar_add_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qstatusbar_add_permanent_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass + +def vqt6_qtoolbar_create() -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_create_with_parent(parent: QtWidgetPtr) -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_add_widget(tb: QtToolBarPtr, w: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qtoolbar_add_action(tb: QtToolBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qtoolbar_add_separator(tb: QtToolBarPtr) -> t.State: pass +def vqt6_qtoolbar_set_icon_size(tb: QtToolBarPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qtoolbar_set_orientation(tb: QtToolBarPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qtoolbar_orientation(tb: QtToolBarPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMessageBox — 消息对话框(静态方法) +# ============================================================ +def vqt6_qmessagebox_information(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_warning(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_critical(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_question(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_about(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qmessagebox_about_qt(parent: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QFileDialog — 文件选择对话框(静态方法) +# ============================================================ +def vqt6_qfiledialog_get_open_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_save_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_existing_directory(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_open_file_names(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringListPtr | t.State: pass + + +# ============================================================ +# QColorDialog / QFontDialog / QInputDialog — 各种对话框 +# ============================================================ +def vqt6_qcolordialog_get_color(initial: QtColorPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qfontdialog_get_font(initial: QtFontPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qinputdialog_get_text(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, echo_mode: t.CInt, text: QtStringPtr, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass +def vqt6_qinputdialog_get_int(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CInt, min_val: t.CInt, max_val: t.CInt, step: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qinputdialog_get_double(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CDouble, min_val: t.CDouble, max_val: t.CDouble, decimals: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qinputdialog_get_item(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, items: QtStringListPtr, current: t.CInt, editable: t.CInt, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass diff --git a/vqt6 copy/_types.vp b/vqt6 copy/_types.vp new file mode 100644 index 0000000..86d1fe5 --- /dev/null +++ b/vqt6 copy/_types.vp @@ -0,0 +1,186 @@ +import t +from stdint import * + +# ============================================================ +# vqt6/_types.py — 公共类型定义 +# +# Qt6 C++ 类在 Viper 端都是不透明指针 (void*) +# 不暴露 C++ 类的内部布局,只暴露指针 +# ============================================================ + +# 不透明指针 typedef(Qt6 C++ 类的 Viper 端表示) +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # void* 通用不透明指针 +QtStringPtr: t.CTypedef = t.CVoid | t.CPtr # QString* +QtByteArrayPtr: t.CTypedef = t.CVoid | t.CPtr # QByteArray* +QtVariantPtr: t.CTypedef = t.CVoid | t.CPtr # QVariant* +QtObjectListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtStringListPtr: t.CTypedef = t.CVoid | t.CPtr # QStringList* +QtByteArrayListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtEventPtr: t.CTypedef = t.CVoid | t.CPtr # QEvent* + +# QtCore +QtCoreAppPtr: t.CTypedef = t.CVoid | t.CPtr # QCoreApplication* +QtTimerPtr: t.CTypedef = t.CVoid | t.CPtr # QTimer* +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # QObject* +QtThreadPtr: t.CTypedef = t.CVoid | t.CPtr # QThread* +QtMutexPtr: t.CTypedef = t.CVoid | t.CPtr # QMutex* +QtWaitConditionPtr: t.CTypedef = t.CVoid | t.CPtr # QWaitCondition* + +# QtGui +QtColorPtr: t.CTypedef = t.CVoid | t.CPtr # QColor* +QtFontPtr: t.CTypedef = t.CVoid | t.CPtr # QFont* +QtFontMetricsPtr: t.CTypedef = t.CVoid | t.CPtr # QFontMetrics* +QtPixmapPtr: t.CTypedef = t.CVoid | t.CPtr # QPixmap* +QtImagePtr: t.CTypedef = t.CVoid | t.CPtr # QImage* +QtPainterPtr: t.CTypedef = t.CVoid | t.CPtr # QPainter* +QtPenPtr: t.CTypedef = t.CVoid | t.CPtr # QPen* +QtBrushPtr: t.CTypedef = t.CVoid | t.CPtr # QBrush* +QtIconPtr: t.CTypedef = t.CVoid | t.CPtr # QIcon* +QtKeyEventPtr: t.CTypedef = t.CVoid | t.CPtr # QKeyEvent* +QtMouseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QMouseEvent* +QtResizeEventPtr: t.CTypedef = t.CVoid | t.CPtr # QResizeEvent* +QtPaintEventPtr: t.CTypedef = t.CVoid | t.CPtr # QPaintEvent* +QtCloseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QCloseEvent* +QtCursorPtr: t.CTypedef = t.CVoid | t.CPtr # QCursor* + +# QtWidgets +QtAppPtr: t.CTypedef = t.CVoid | t.CPtr # QApplication* +QtWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QWidget* +QtDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QDialog* +QtMainWindowPtr: t.CTypedef = t.CVoid | t.CPtr # QMainWindow* +QtLabelPtr: t.CTypedef = t.CVoid | t.CPtr # QLabel* +QtPushButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QPushButton* +QtLineEditPtr: t.CTypedef = t.CVoid | t.CPtr # QLineEdit* +QtTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QTextEdit* +QtPlainTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QPlainTextEdit* +QtCheckBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QCheckBox* +QtRadioButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QRadioButton* +QtComboBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QComboBox* +QtListWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidget* +QtListWidgetItemPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidgetItem* +QtProgressBarPtr: t.CTypedef = t.CVoid | t.CPtr # QProgressBar* +QtSliderPtr: t.CTypedef = t.CVoid | t.CPtr # QSlider* +QtSpinBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QSpinBox* +QtLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QLayout* +QtBoxLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QHBoxLayout / QVBoxLayout* +QtGridLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QGridLayout* +QtFormLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QFormLayout* +QtStackedWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QStackedWidget* +QtTabWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QTabWidget* +QtMenuBarPtr: t.CTypedef = t.CVoid | t.CPtr # QMenuBar* +QtMenuPtr: t.CTypedef = t.CVoid | t.CPtr # QMenu* +QtActionPtr: t.CTypedef = t.CVoid | t.CPtr # QAction* +QtStatusBarPtr: t.CTypedef = t.CVoid | t.CPtr # QStatusBar* +QtToolBarPtr: t.CTypedef = t.CVoid | t.CPtr # QToolBar* +QtMessageBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QMessageBox* +QtFileDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFileDialog* +QtColorDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QColorDialog* +QtFontDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFontDialog* +QtInputDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QInputDialog* + +# QtNetwork +QtTcpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QTcpSocket* +QtUdpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QUdpSocket* +QtHostAddressPtr: t.CTypedef = t.CVoid | t.CPtr # QHostAddress* +QtAbstractSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QAbstractSocket* +QtNetworkAccessManagerPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkAccessManager* +QtNetworkReplyPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkReply* +QtNetworkRequestPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkRequest* + +# ============================================================ +# Qt 通用常量(C++ 枚举值的 C 兼容定义) +# ============================================================ + +# Qt 键盘按键 (Qt::Key) +QT_KEY_ESCAPE: t.CDefine = 0x01000000 +QT_KEY_TAB: t.CDefine = 0x01000001 +QT_KEY_BACKTAB: t.CDefine = 0x01000002 +QT_KEY_BACKSPACE: t.CDefine = 0x01000003 +QT_KEY_RETURN: t.CDefine = 0x01000004 +QT_KEY_ENTER: t.CDefine = 0x01000005 +QT_KEY_INSERT: t.CDefine = 0x01000006 +QT_KEY_DELETE: t.CDefine = 0x01000007 +QT_KEY_PAUSE: t.CDefine = 0x01000008 +QT_KEY_PRINT: t.CDefine = 0x01000009 +QT_KEY_HOME: t.CDefine = 0x01000010 +QT_KEY_END: t.CDefine = 0x01000011 +QT_KEY_LEFT: t.CDefine = 0x01000012 +QT_KEY_UP: t.CDefine = 0x01000013 +QT_KEY_RIGHT: t.CDefine = 0x01000014 +QT_KEY_DOWN: t.CDefine = 0x01000015 +QT_KEY_PAGEUP: t.CDefine = 0x01000016 +QT_KEY_PAGEDOWN: t.CDefine = 0x01000017 +QT_KEY_SHIFT: t.CDefine = 0x01000020 +QT_KEY_CONTROL: t.CDefine = 0x01000021 +QT_KEY_META: t.CDefine = 0x01000022 +QT_KEY_ALT: t.CDefine = 0x01000023 +QT_KEY_F1: t.CDefine = 0x01000030 +QT_KEY_F2: t.CDefine = 0x01000031 +QT_KEY_F12: t.CDefine = 0x0100003b +QT_KEY_SPACE: t.CDefine = 0x20 +QT_KEY_A: t.CDefine = 0x41 +QT_KEY_Z: t.CDefine = 0x5a +QT_KEY_0: t.CDefine = 0x30 +QT_KEY_9: t.CDefine = 0x39 + +# Qt 鼠标按键 (Qt::MouseButton) +QT_NO_BUTTON: t.CDefine = 0x00000000 +QT_LEFT_BUTTON: t.CDefine = 0x00000001 +QT_RIGHT_BUTTON: t.CDefine = 0x00000002 +QT_MID_BUTTON: t.CDefine = 0x00000004 + +# Qt::AlignmentFlag +QT_ALIGN_LEFT: t.CDefine = 0x0001 +QT_ALIGN_RIGHT: t.CDefine = 0x0002 +QT_ALIGN_HCENTER: t.CDefine = 0x0004 +QT_ALIGN_TOP: t.CDefine = 0x0020 +QT_ALIGN_BOTTOM: t.CDefine = 0x0040 +QT_ALIGN_VCENTER: t.CDefine = 0x0080 +QT_ALIGN_CENTER: t.CDefine = QT_ALIGN_HCENTER | QT_ALIGN_VCENTER + +# Qt::Orientation +QT_HORIZONTAL: t.CDefine = 0x1 +QT_VERTICAL: t.CDefine = 0x2 + +# Qt 焦点 +QT_NO_FOCUS: t.CDefine = 0x00 +QT_TAB_FOCUS: t.CDefine = 0x01 +QT_CLICK_FOCUS: t.CDefine = 0x02 +QT_STRONG_FOCUS: t.CDefine = QT_TAB_FOCUS | QT_CLICK_FOCUS +QT_WHEEL_FOCUS: t.CDefine = 0x04 +QT_ALL_FOCUS: t.CDefine = QT_STRONG_FOCUS | QT_WHEEL_FOCUS + +# Qt::WindowFlag +QT_WINDOW: t.CDefine = 0x00000001 +QT_DIALOG: t.CDefine = 0x00000002 | QT_WINDOW +QT_SHEET: t.CDefine = 0x00000004 | QT_WINDOW +QT_DRAWER: t.CDefine = QT_SHEET | 0x00000008 +QT_POPUP: t.CDefine = 0x00000008 | QT_WINDOW +QT_TOOL: t.CDefine = 0x0000000a | QT_WINDOW +QT_TOOLTIP: t.CDefine = 0x0000000c | QT_WINDOW +QT_SPLASH_SCREEN: t.CDefine = 0x0000000e | QT_WINDOW + +QT_WINDOW_TITLE: t.CDefine = 0x00000001 +QT_WINDOW_SYSTEM_MENU: t.CDefine = 0x00000002 +QT_WINDOW_MIN_MAX_BUTTONS: t.CDefine = 0x00000004 +QT_WINDOW_CLOSE_BUTTON: t.CDefine = 0x08000000 +QT_WINDOW_CONTEXT_HELP_BUTTON: t.CDefine = 0x00000008 + +# QMessageBox 标准按钮 +QT_OK: t.CDefine = 0x00000400 +QT_CANCEL: t.CDefine = 0x00400000 +QT_YES: t.CDefine = 0x00004000 +QT_NO: t.CDefine = 0x00010000 +QT_CLOSE: t.CDefine = 0x00200000 + +# 事件类型 +QT_EVENT_NONE: t.CDefine = 0 +QT_EVENT_KEY: t.CDefine = 6 +QT_EVENT_MOUSE_BUTTON_PRESS: t.CDefine = 2 +QT_EVENT_MOUSE_BUTTON_RELEASE: t.CDefine = 3 +QT_EVENT_MOUSE_MOVE: t.CDefine = 5 +QT_EVENT_PAINT: t.CDefine = 12 +QT_EVENT_RESIZE: t.CDefine = 14 +QT_EVENT_CLOSE: t.CDefine = 19 +QT_EVENT_SHOW: t.CDefine = 17 +QT_EVENT_HIDE: t.CDefine = 18 diff --git a/vqt6/CMakeLists.txt b/vqt6/CMakeLists.txt new file mode 100644 index 0000000..d08d121 --- /dev/null +++ b/vqt6/CMakeLists.txt @@ -0,0 +1,110 @@ +# ============================================================ +# vqt6 CMakeLists.txt — 构建 vqt6 C 桥接层 +# +# 默认产物: libvqt6_bridge.a (静态库) +# 可选产物: vqt6_bridge.dll (动态库) +# +# 使用: +# cmake -B build -S . +# cmake --build build --config Release +# ============================================================ + +cmake_minimum_required(VERSION 3.16) +project(vqt6_bridge CXX C) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) + +# 构建选项 +option(VQT6_BUILD_SHARED "Build vqt6 as shared library (DLL)" OFF) +option(VQT6_BUILD_STATIC "Build vqt6 as static library" ON) +option(VQT6_BUILD_EXAMPLES "Build example programs" OFF) + +# Qt6 依赖 +find_package(Qt6 6.5 REQUIRED COMPONENTS + Core + Gui + Widgets + Network +) + +# Win32 GUI 应用不需要控制台 +if(WIN32) + set(CMAKE_WIN32_EXECUTABLE OFF) +endif() + +# 公共源文件 +set(VQT6_SOURCES + _bridge_core.cpp + _bridge_widgets.cpp + _bridge_gui.cpp + _bridge_network.cpp +) + +set(VQT6_HEADERS + _bridge.h + _bridge_widgets.h + _bridge_gui.h + _bridge_network.h +) + +# Qt 模块 +set(VQT6_QT_MODULES + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Network +) + +# ============================================================ +# 静态库 +# ============================================================ +if(VQT6_BUILD_STATIC) + add_library(vqt6_bridge_static STATIC ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge_static PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge_static PUBLIC VQT6_BRIDGE_STATIC) + target_include_directories(vqt6_bridge_static PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge_static PROPERTIES + OUTPUT_NAME vqt6_bridge + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ) +endif() + +# ============================================================ +# 动态库 +# ============================================================ +if(VQT6_BUILD_SHARED) + add_library(vqt6_bridge SHARED ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge PRIVATE VQT6_BRIDGE_BUILD) + target_include_directories(vqt6_bridge PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + ) +endif() + +# ============================================================ +# 安装 +# ============================================================ +install(TARGETS vqt6_bridge_static vqt6_bridge + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install(FILES ${VQT6_HEADERS} + DESTINATION include/vqt6 +) + +# ============================================================ +# 示例 +# ============================================================ +if(VQT6_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/vqt6/README.md b/vqt6/README.md new file mode 100644 index 0000000..eba4e88 --- /dev/null +++ b/vqt6/README.md @@ -0,0 +1,90 @@ +# vqt6 — Viper 的 Qt6 绑定包 + +`vqt6` 是 [Viper](https://git.gvsds.com/GVSDS/TransPyC) 语言的 **Qt6 GUI 框架绑定**,是 Viper 包管理器分发的"包"(类似于 Python 的 PyQt6、Node.js 的 node-gtk)。 + +> 注意:`vqt6` **不是** 包管理器,而是一个**被包管理器管理的包**(库)。 +> 包管理器负责下载、预编译、安装;`vqt6` 只负责把 Qt6 C++ API 暴露给 Viper 代码。 + +## 架构 + +``` ++--------------------+ +-----------------------+ +------------+ +| Viper 用户代码 | FFI | vqt6 桥接层 (libvqt6) | C++ | Qt6 C++ | +| (app.vp) | <----> | - t.State 声明 | <-----> | QtCore | +| | | - C 桥接函数 | | QtGui | +| vqt6.QApplication | | (extern "C") | | QtWidgets | +| vqt6.QLabel | | - 静态库 / 动态库 | | QtNetwork | ++--------------------+ +-----------------------+ +------------+ +``` + +**FFI 路径**: +1. Viper 编译器把 `t.State` 声明的 `def xxx() -> t.State: pass` 解析为外部函数符号 +2. 链接时通过 `libvqt6_bridge.a`(静态)或 `vqt6_bridge.dll`(动态)解析符号 +3. 运行时 C 桥接层调用 Qt6 C++ API 完成实际工作 + +## 链接模式 + +| 模式 | 产物 | 优点 | 缺点 | +|------|------|------|------| +| **静态**(默认) | `libvqt6_bridge.a` | 部署简单(一个 exe),无需分发 dll | exe 体积较大 | +| **动态** | `vqt6_bridge.dll` | 共享内存,多个程序共用 | 需随 exe 分发 dll | + +vqt6 同一套 C 桥接源代码,可同时编译为两种产物。Viper 项目通过 `project.vpj` 切换。 + +## 目录结构 + +``` +includes/vqt6/ +├── README.md # 本文件 +├── __init__.vp # 公共 Pythonic API(用户使用) +├── _types.vp # 公共类型(不透明指针 typedef) +├── _qtcore.vp # QtCore 的 t.State FFI 声明 +├── _qtwidgets.vp # QtWidgets 的 t.State FFI 声明 +├── _qtgui.vp # QtGui 的 t.State FFI 声明 +├── _qtnetwork.vp # QtNetwork 的 t.State FFI 声明 +├── _bridge.h # C 桥接层头文件 +├── _bridge.cpp # C 桥接层实现(extern "C" 包装 Qt6 C++ API) +└── CMakeLists.txt # 构建脚本(生成 libvqt6_bridge.a) +``` + +## 使用示例 + +```python +# App/main.vp +import t +import c +import vqt6 + +# 1. 创建 QApplication +app: vqt6.QApplication | t.CPtr = vqt6.QApplication([]) + +# 2. 创建窗口 +window: vqt6.QWidget | t.CPtr = vqt6.QWidget() +window.setWindowTitle("vqt6 Hello") +window.resize(400, 300) + +# 3. 创建标签 +label: vqt6.QLabel | t.CPtr = vqt6.QLabel("你好,Viper!", window) +label.move(50, 50) + +# 4. 显示并进入事件循环 +window.show() +app.exec() +``` + +## 设计原则 + +1. **不透明指针**:Viper 端不直接操作 Qt6 C++ 类(`QWidget*`、`QString*` 等),所有操作通过 C 桥接函数 `vqt6_xxx()` 转发。 +2. **t.State 声明**:所有 FFI 函数返回 `t.State`,C 桥接层函数实现负责实际操作。 +3. **句柄化对象模型**:Viper 端的对象是 `t.CPtr`(不透明指针),C 端管理生命周期(构造函数/析构函数)。 +4. **跨平台**:同一套 C 桥接代码可在 Windows / Linux / macOS 编译(差异在 Qt6 安装路径)。 + +## 当前状态 + +- [x] 架构设计 +- [x] FFI 覆盖:QtCore / QtWidgets / QtGui / QtNetwork +- [x] FFI 粒度:仅暴露 C 桥接函数 +- [ ] FFI 声明文件编写中 +- [ ] C 桥接层实现 +- [ ] CMakeLists.txt 构建脚本 +- [ ] Hello World 示例验证 diff --git a/vqt6/__init__.vp b/vqt6/__init__.vp new file mode 100644 index 0000000..16446c3 --- /dev/null +++ b/vqt6/__init__.vp @@ -0,0 +1,208 @@ +# ============================================================ +# vqt6 — Viper 的 Qt6 绑定包 +# +# 公共 Pythonic API(基于 C 桥接层) +# 用户用法: +# import vqt6 +# app = vqt6.QApplication([]) +# win = vqt6.QWidget() +# win.setWindowTitle("Hello") +# win.show() +# app.exec() +# ============================================================ + +import t +from stdint import * +from vqt6._types import * +from vqt6._qtcore import * +from vqt6._qtwidgets import * +from vqt6._qtgui import * +from vqt6._qtnetwork import * + + +# ============================================================ +# 高级 API 类(Pythonic 包装,不透明指针) +# ============================================================ +@t.NoVTable +class QApplication: + """QApplication 包装(不透明指针)""" + _ptr: QtAppPtr + + def __init__(self, argv: list[str] | t.CPtr): + # 把 argv 转换为 argc/argv 数组 + argc: t.CInt = 1 + # Viper 端 argv 是 c_char_p 指针数组 + # 这里仅传空 argv,避免 C ABI 复杂性 + argv_ptr: t.CPtr = t.CPtr(0) + self._ptr = vqt6_qapplication_create(argc, argv_ptr) + if self._ptr is None: + raise RuntimeError("Failed to create QApplication") + + def exec(self) -> int: + return vqt6_qapplication_exec(self._ptr) + + def quit(self): + vqt6_qapplication_quit(self._ptr) + + def exit(self, code: int): + vqt6_qapplication_exit(self._ptr, code) + + def process_events(self): + vqt6_qapplication_process_events(self._ptr) + + def desktop_width(self) -> int: + return vqt6_qapplication_desktop_width(self._ptr) + + def desktop_height(self) -> int: + return vqt6_qapplication_desktop_height(self._ptr) + + +@t.NoVTable +class QWidget: + """QWidget 包装""" + _ptr: QtWidgetPtr + + def __init__(self, parent: "QWidget | None" = None): + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qwidget_create_with_parent(parent._ptr) + else: + self._ptr = vqt6_qwidget_create() + if self._ptr is None: + raise RuntimeError("Failed to create QWidget") + + def show(self): + vqt6_qwidget_show(self._ptr) + + def hide(self): + vqt6_qwidget_hide(self._ptr) + + def close(self) -> int: + return vqt6_qwidget_close(self._ptr) + + def setWindowTitle(self, title: str): + title_qs: QtStringPtr = vqt6_qstring_create(title) + vqt6_qwidget_set_window_title(self._ptr, title_qs) + vqt6_qstring_free(title_qs) + + def windowTitle(self) -> str: + result: QtStringPtr = vqt6_qwidget_window_title(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def resize(self, w: int, h: int): + vqt6_qwidget_resize(self._ptr, w, h) + + def move(self, x: int, y: int): + vqt6_qwidget_move(self._ptr, x, y) + + def setGeometry(self, x: int, y: int, w: int, h: int): + vqt6_qwidget_set_geometry(self._ptr, x, y, w, h) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + def setVisible(self, visible: int): + vqt6_qwidget_set_visible(self._ptr, visible) + + def isVisible(self) -> int: + return vqt6_qwidget_is_visible(self._ptr) + + def setToolTip(self, tip: str): + tip_qs: QtStringPtr = vqt6_qstring_create(tip) + vqt6_qwidget_set_tool_tip(self._ptr, tip_qs) + vqt6_qstring_free(tip_qs) + + +@t.NoVTable +class QLabel: + """QLabel 包装""" + _ptr: QtLabelPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qlabel_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qlabel_create_with_text(text_qs) + else: + self._ptr = vqt6_qlabel_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QLabel") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qlabel_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qlabel_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def setAlignment(self, alignment: int): + vqt6_qlabel_set_alignment(self._ptr, alignment) + + +@t.NoVTable +class QPushButton: + """QPushButton 包装""" + _ptr: QtPushButtonPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qpushbutton_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qpushbutton_create_with_text(text_qs) + else: + self._ptr = vqt6_qpushbutton_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QPushButton") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qpushbutton_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qpushbutton_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def click(self): + vqt6_qpushbutton_click(self._ptr) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + +# ============================================================ +# 模块导出 +# ============================================================ +__all__ = [ + # 高层类 + "QApplication", "QWidget", "QLabel", "QPushButton", + # 类型 + "QtObjectPtr", "QtStringPtr", "QtByteArrayPtr", "QtWidgetPtr", "QtAppPtr", + "QtLabelPtr", "QtPushButtonPtr", + "QtColorPtr", "QtFontPtr", "QtPixmapPtr", "QtImagePtr", "QtPainterPtr", + "QtTcpSocketPtr", "QtHostAddressPtr", "QtNetworkRequestPtr", "QtNetworkReplyPtr", + # 常量 + "QT_KEY_ESCAPE", "QT_KEY_RETURN", "QT_KEY_A", "QT_KEY_Z", + "QT_LEFT_BUTTON", "QT_RIGHT_BUTTON", "QT_MID_BUTTON", + "QT_HORIZONTAL", "QT_VERTICAL", + "QT_ALIGN_LEFT", "QT_ALIGN_CENTER", "QT_ALIGN_RIGHT", + "QT_PORT_HTTP", "QT_PORT_HTTPS", "QT_PORT_FTP", + "QT_OK", "QT_CANCEL", "QT_YES", "QT_NO", "QT_CLOSE", +] diff --git a/vqt6/_bridge.h b/vqt6/_bridge.h new file mode 100644 index 0000000..e573ea8 --- /dev/null +++ b/vqt6/_bridge.h @@ -0,0 +1,151 @@ +// ============================================================ +// vqt6/_bridge.h — C 桥接层头文件 +// +// 作用: 把 Qt6 C++ API 包装成 extern "C" 函数,供 Viper FFI 调用 +// 编译: 作为静态库 libvqt6_bridge.a 或动态库 vqt6_bridge.dll +// ============================================================ + +#ifndef VQT6_BRIDGE_H +#define VQT6_BRIDGE_H + +#include +#include + +#if defined(_WIN32) +# if defined(VQT6_BRIDGE_STATIC) +# define VQT6_API +# elif defined(VQT6_BRIDGE_BUILD) +# define VQT6_API __declspec(dllexport) +# else +# define VQT6_API __declspec(dllimport) +# endif +#else +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define VQT6_API __attribute__((visibility("default"))) +# else +# define VQT6_API +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QString +// ============================================================ +VQT6_API void* vqt6_qstring_create(const char* utf8); +VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size); +VQT6_API void vqt6_qstring_free(void* qstr); +VQT6_API int vqt6_qstring_length(void* qstr); +VQT6_API int vqt6_qstring_is_empty(void* qstr); +VQT6_API int vqt6_qstring_equals(void* qstr, void* other); +VQT6_API void* vqt6_qstring_append(void* qstr, void* other); + +// ============================================================ +// QByteArray +// ============================================================ +VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size); +VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size); +VQT6_API size_t vqt6_qbytearray_size(void* qba); +VQT6_API void vqt6_qbytearray_free(void* qba); + +// ============================================================ +// QObject +// ============================================================ +VQT6_API void vqt6_qobject_delete(void* obj); +VQT6_API void vqt6_qobject_delete_later(void* obj); +VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name); +VQT6_API void* vqt6_qobject_object_name(void* obj); +VQT6_API void vqt6_qobject_set_parent(void* child, void* parent); +VQT6_API void* vqt6_qobject_parent(void* obj); +VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter); +VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter); + +// ============================================================ +// QCoreApplication +// ============================================================ +VQT6_API void* vqt6_qcoreapp_create(const char* app_name); +VQT6_API void* vqt6_qcoreapp_instance(void); +VQT6_API int vqt6_qcoreapp_exec(void* app); +VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags); +VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event); +VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event); +VQT6_API void* vqt6_qcoreapp_organization_name(void* app); +VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name); +VQT6_API void* vqt6_qcoreapp_application_name(void* app); +VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name); + +// ============================================================ +// QTimer +// ============================================================ +VQT6_API void* vqt6_qtimer_create(void); +VQT6_API void* vqt6_qtimer_create_with_parent(void* parent); +VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms); +VQT6_API void vqt6_qtimer_stop(void* timer); +VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms); +VQT6_API int vqt6_qtimer_interval(void* timer); +VQT6_API int vqt6_qtimer_is_active(void* timer); +VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot); +VQT6_API int vqt6_qtimer_is_single_shot(void* timer); + +// ============================================================ +// QVariant +// ============================================================ +VQT6_API void* vqt6_qvariant_create_int(int value); +VQT6_API void* vqt6_qvariant_create_double(double value); +VQT6_API void* vqt6_qvariant_create_bool(int value); +VQT6_API void* vqt6_qvariant_create_string(void* s); +VQT6_API int vqt6_qvariant_to_int(void* v, int* ok); +VQT6_API double vqt6_qvariant_to_double(void* v, int* ok); +VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok); +VQT6_API void* vqt6_qvariant_to_string(void* v); +VQT6_API int vqt6_qvariant_type_id(void* v); +VQT6_API int vqt6_qvariant_is_valid(void* v); +VQT6_API void vqt6_qvariant_free(void* v); + +// ============================================================ +// QEvent +// ============================================================ +VQT6_API int vqt6_qevent_type(void* event); +VQT6_API void vqt6_qevent_accept(void* event); +VQT6_API void vqt6_qevent_ignore(void* event); +VQT6_API int vqt6_qevent_is_accepted(void* event); + +// ============================================================ +// QStringList +// ============================================================ +VQT6_API void* vqt6_qstringlist_create(void); +VQT6_API void vqt6_qstringlist_append(void* list, void* str); +VQT6_API int vqt6_qstringlist_size(void* list); +VQT6_API void* vqt6_qstringlist_at(void* list, int index); +VQT6_API void vqt6_qstringlist_free(void* list); + +// ============================================================ +// QByteArrayList +// ============================================================ +VQT6_API void* vqt6_qbytearraylist_create(void); +VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba); +VQT6_API int vqt6_qbytearraylist_size(void* list); +VQT6_API void* vqt6_qbytearraylist_at(void* list, int index); +VQT6_API void vqt6_qbytearraylist_free(void* list); + +// ============================================================ +// 全局回调注册表 +// ============================================================ +typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +VQT6_API void vqt6_register_slot(int slot_id, void* user_data); +VQT6_API void vqt6_unregister_slot(int slot_id); +VQT6_API void vqt6_trigger_slot(int slot_id); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_H diff --git a/vqt6/_bridge_core.cpp b/vqt6/_bridge_core.cpp new file mode 100644 index 0000000..3f420d8 --- /dev/null +++ b/vqt6/_bridge_core.cpp @@ -0,0 +1,433 @@ +// ============================================================ +// vqt6/_bridge_core.cpp — QtCore C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 全局回调表(线程安全) +namespace { + QMutex g_slot_mutex; + QHash> g_slots; +} + +// ============================================================ +// QString +// ============================================================ +extern "C" VQT6_API void* vqt6_qstring_create(const char* utf8) { + if (utf8 == nullptr) return nullptr; + return new QString(QString::fromUtf8(utf8)); +} + +extern "C" VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size) { + if (qstr == nullptr || buf == nullptr || buf_size == 0) return 0; + QString* s = static_cast(qstr); + QByteArray ba = s->toUtf8(); + size_t len = static_cast(ba.size()); + if (len >= buf_size) len = buf_size - 1; + std::memcpy(buf, ba.constData(), len); + buf[len] = '\0'; + return len; +} + +extern "C" VQT6_API void vqt6_qstring_free(void* qstr) { + delete static_cast(qstr); +} + +extern "C" VQT6_API int vqt6_qstring_length(void* qstr) { + if (qstr == nullptr) return 0; + return static_cast(qstr)->length(); +} + +extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) { + if (qstr == nullptr) return 1; + return static_cast(qstr)->isEmpty() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qstring_equals(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return 0; + return *static_cast(qstr) == *static_cast(other) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qstring_append(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return nullptr; + return new QString(*static_cast(qstr) + *static_cast(other)); +} + +// ============================================================ +// QByteArray +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size) { + if (data == nullptr) return new QByteArray(); + return new QByteArray(static_cast(data), static_cast(size)); +} + +extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) { + if (qba == nullptr) return nullptr; + QByteArray* ba = static_cast(qba); + if (out_size != nullptr) *out_size = static_cast(ba->size()); + return ba->data(); +} + +extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) { + if (qba == nullptr) return 0; + return static_cast(static_cast(qba)->size()); +} + +extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) { + delete static_cast(qba); +} + +// ============================================================ +// QObject +// ============================================================ +extern "C" VQT6_API void vqt6_qobject_delete(void* obj) { + if (obj == nullptr) return; + delete static_cast(obj); +} + +extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) { + if (obj == nullptr) return; + static_cast(obj)->deleteLater(); +} + +extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) { + if (obj == nullptr || name == nullptr) return; + static_cast(obj)->setObjectName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) { + if (obj == nullptr) return nullptr; + return new QString(static_cast(obj)->objectName()); +} + +extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) { + if (child == nullptr) return; + static_cast(child)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) { + if (obj == nullptr) return nullptr; + return static_cast(obj)->parent(); +} + +extern "C" VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr || signal_name == nullptr || slot_name == nullptr) + return 0; + return QObject::connect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr) return 0; + return QObject::disconnect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->installEventFilter(static_cast(filter)); +} + +extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->removeEventFilter(static_cast(filter)); +} + +// ============================================================ +// QCoreApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qcoreapp_create(const char* app_name) { + if (app_name == nullptr) return nullptr; + int argc = 1; + static char app_name_copy[1024]; + std::strncpy(app_name_copy, app_name, sizeof(app_name_copy) - 1); + app_name_copy[sizeof(app_name_copy) - 1] = '\0'; + char* argv[] = { app_name_copy, nullptr }; + return new QCoreApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_instance(void) { + return QCoreApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qcoreapp_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code) { + if (app == nullptr) return; + // 优先使用 exit_code 重载 + QCoreApplication* a = static_cast(app); + if (a == QCoreApplication::instance()) { + a->exit(exit_code); + } +} + +extern "C" VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) { + if (app == nullptr) return; + static_cast(app)->processEvents(static_cast(flags)); +} + +extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return; + QCoreApplication::postEvent(static_cast(receiver), static_cast(event)); +} + +extern "C" VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return 0; + return QCoreApplication::sendEvent(static_cast(receiver), static_cast(event)) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qcoreapp_organization_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::organizationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setOrganizationName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_application_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::applicationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setApplicationName(*static_cast(name)); +} + +// ============================================================ +// QTimer +// ============================================================ +extern "C" VQT6_API void* vqt6_qtimer_create(void) { + return new QTimer(); +} + +extern "C" VQT6_API void* vqt6_qtimer_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTimer(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->start(interval_ms); +} + +extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) { + if (timer == nullptr) return; + static_cast(timer)->stop(); +} + +extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->setInterval(interval_ms); +} + +extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->interval(); +} + +extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot) { + if (timer == nullptr) return; + static_cast(timer)->setSingleShot(single_shot != 0); +} + +extern "C" VQT6_API int vqt6_qtimer_is_single_shot(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isSingleShot() ? 1 : 0; +} + +// ============================================================ +// QVariant +// ============================================================ +extern "C" VQT6_API void* vqt6_qvariant_create_int(int value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_double(double value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_bool(int value) { + return new QVariant(value != 0); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_string(void* s) { + if (s == nullptr) return new QVariant(); + return new QVariant(*static_cast(s)); +} + +extern "C" VQT6_API int vqt6_qvariant_to_int(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + int val = static_cast(v)->toInt(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API double vqt6_qvariant_to_double(void* v, int* ok) { + if (v == nullptr) return 0.0; + bool bok = false; + double val = static_cast(v)->toDouble(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + bool val = static_cast(v)->toBool(); + if (ok != nullptr) *ok = 1; + return val ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qvariant_to_string(void* v) { + if (v == nullptr) return nullptr; + return new QString(static_cast(v)->toString()); +} + +extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) { + if (v == nullptr) return 0; + return static_cast(static_cast(v)->typeId()); +} + +extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) { + if (v == nullptr) return 0; + return static_cast(v)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qvariant_free(void* v) { + delete static_cast(v); +} + +// ============================================================ +// QEvent +// ============================================================ +extern "C" VQT6_API int vqt6_qevent_type(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->type()); +} + +extern "C" VQT6_API void vqt6_qevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +// ============================================================ +// QStringList +// ============================================================ +extern "C" VQT6_API void* vqt6_qstringlist_create(void) { + return new QStringList(); +} + +extern "C" VQT6_API void vqt6_qstringlist_append(void* list, void* str) { + if (list == nullptr || str == nullptr) return; + static_cast(list)->append(*static_cast(str)); +} + +extern "C" VQT6_API int vqt6_qstringlist_size(void* list) { + if (list == nullptr) return 0; + return static_cast(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QStringList* sl = static_cast(list); + if (index < 0 || index >= sl->size()) return nullptr; + return new QString(sl->at(index)); +} + +extern "C" VQT6_API void vqt6_qstringlist_free(void* list) { + delete static_cast(list); +} + +// ============================================================ +// QByteArrayList +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) { + return new QList(); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) { + if (list == nullptr || qba == nullptr) return; + static_cast*>(list)->append(*static_cast(qba)); +} + +extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) { + if (list == nullptr) return 0; + return static_cast*>(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QList* qbl = static_cast*>(list); + if (index < 0 || index >= qbl->size()) return nullptr; + return new QByteArray(qbl->at(index)); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_free(void* list) { + delete static_cast*>(list); +} + +// ============================================================ +// 全局回调注册表 +// ============================================================ +extern "C" VQT6_API void vqt6_register_slot(int slot_id, void* user_data) { + QMutexLocker locker(&g_slot_mutex); + g_slots.insert(slot_id, QPair(nullptr, user_data)); +} + +extern "C" VQT6_API void vqt6_unregister_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + g_slots.remove(slot_id); +} + +extern "C" VQT6_API void vqt6_trigger_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + auto it = g_slots.find(slot_id); + if (it != g_slots.end() && it.value().first != nullptr) { + it.value().first(slot_id, it.value().second); + } +} diff --git a/vqt6/_bridge_gui.cpp b/vqt6/_bridge_gui.cpp new file mode 100644 index 0000000..089f0d7 --- /dev/null +++ b/vqt6/_bridge_gui.cpp @@ -0,0 +1,868 @@ +// ============================================================ +// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QColor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b) { + return new QColor(r, g, b); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a) { + return new QColor(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_name(void* name) { + if (name == nullptr) return new QColor(); + return new QColor(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_hex(void* hex_str) { + if (hex_str == nullptr) return new QColor(); + return new QColor(*static_cast(hex_str)); +} + +extern "C" VQT6_API int vqt6_qcolor_red(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->red(); +} + +extern "C" VQT6_API int vqt6_qcolor_green(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->green(); +} + +extern "C" VQT6_API int vqt6_qcolor_blue(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->blue(); +} + +extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) { + if (c == nullptr) return 255; + return static_cast(c)->alpha(); +} + +extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) { + if (c == nullptr) return; + static_cast(c)->setRed(r); +} + +extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) { + if (c == nullptr) return; + static_cast(c)->setGreen(g); +} + +extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) { + if (c == nullptr) return; + static_cast(c)->setBlue(b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) { + if (c == nullptr) return; + static_cast(c)->setAlpha(a); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b) { + if (c == nullptr) return; + static_cast(c)->setRgb(r, g, b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a) { + if (c == nullptr) return; + static_cast(c)->setRgba(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_name(void* c) { + if (c == nullptr) return nullptr; + return new QString(static_cast(c)->name()); +} + +extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcolor_free(void* c) { + delete static_cast(c); +} + +// ============================================================ +// QFont +// ============================================================ +extern "C" VQT6_API void* vqt6_qfont_create(void) { + return new QFont(); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family(void* family) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family), point_size); +} + +extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) { + if (font == nullptr || family == nullptr) return; + static_cast(font)->setFamily(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_family(void* font) { + if (font == nullptr) return nullptr; + return new QString(static_cast(font)->family()); +} + +extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) { + if (font == nullptr) return; + static_cast(font)->setPointSize(point_size); +} + +extern "C" VQT6_API int vqt6_qfont_point_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pointSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) { + if (font == nullptr) return; + static_cast(font)->setPixelSize(pixel_size); +} + +extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pixelSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) { + if (font == nullptr) return; + static_cast(font)->setBold(bold != 0); +} + +extern "C" VQT6_API int vqt6_qfont_bold(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->bold() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) { + if (font == nullptr) return; + static_cast(font)->setItalic(italic != 0); +} + +extern "C" VQT6_API int vqt6_qfont_italic(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->italic() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) { + if (font == nullptr) return; + static_cast(font)->setUnderline(underline != 0); +} + +extern "C" VQT6_API int vqt6_qfont_underline(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->underline() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out) { + if (font == nullptr) return; + static_cast(font)->setStrikeOut(strike_out != 0); +} + +extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->strikeOut() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) { + if (font == nullptr) return; + static_cast(font)->setWeight(static_cast(weight)); +} + +extern "C" VQT6_API int vqt6_qfont_weight(void* font) { + if (font == nullptr) return 0; + return static_cast(static_cast(font)->weight()); +} + +extern "C" VQT6_API void vqt6_qfont_free(void* font) { + delete static_cast(font); +} + +// ============================================================ +// QFontMetrics +// ============================================================ +extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) { + if (font == nullptr) return nullptr; + return new QFontMetrics(*static_cast(font)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) { + if (fm == nullptr || text == nullptr) return 0; + return static_cast(fm)->horizontalAdvance(*static_cast(text)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->height(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->ascent(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->descent(); +} + +extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) { + delete static_cast(fm); +} + +// ============================================================ +// QPixmap +// ============================================================ +extern "C" VQT6_API void* vqt6_qpixmap_create(void) { + return new QPixmap(); +} + +extern "C" VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h) { + return new QPixmap(w, h); +} + +extern "C" VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size) { + if (pm == nullptr || data == nullptr) return 0; + return static_cast(pm)->loadFromData(static_cast(data), static_cast(size)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->width(); +} + +extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->height(); +} + +extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h) { + if (pm == nullptr) return nullptr; + return new QPixmap(static_cast(pm)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qpixmap_fill(void* pm, void* color) { + if (pm == nullptr) return; + if (color != nullptr) { + static_cast(pm)->fill(*static_cast(color)); + } else { + static_cast(pm)->fill(); + } +} + +extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) { + delete static_cast(pm); +} + +// ============================================================ +// QImage +// ============================================================ +extern "C" VQT6_API void* vqt6_qimage_create(void) { + return new QImage(); +} + +extern "C" VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format) { + return new QImage(w, h, static_cast(format)); +} + +extern "C" VQT6_API int vqt6_qimage_load(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_save(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_width(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->width(); +} + +extern "C" VQT6_API int vqt6_qimage_height(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->height(); +} + +extern "C" VQT6_API int vqt6_qimage_format(void* img) { + if (img == nullptr) return 0; + return static_cast(static_cast(img)->format()); +} + +extern "C" VQT6_API int vqt6_qimage_is_null(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qimage_fill(void* img, void* color) { + if (img == nullptr) return; + if (color != nullptr) { + static_cast(img)->fill(*static_cast(color)); + } +} + +extern "C" VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h) { + if (img == nullptr) return nullptr; + return new QImage(static_cast(img)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qimage_free(void* img) { + delete static_cast(img); +} + +// ============================================================ +// QPainter +// ============================================================ +extern "C" VQT6_API void* vqt6_qpainter_create(void) { + return new QPainter(); +} + +extern "C" VQT6_API int vqt6_qpainter_begin(void* p, void* device) { + if (p == nullptr || device == nullptr) return 0; + return static_cast(p)->begin(static_cast(device)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_end(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->end() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen) { + if (p == nullptr || pen == nullptr) return; + static_cast(p)->setPen(*static_cast(pen)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) { + if (p == nullptr || brush == nullptr) return; + static_cast(p)->setBrush(*static_cast(brush)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) { + if (p == nullptr || font == nullptr) return; + static_cast(p)->setFont(*static_cast(font)); +} + +extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) { + if (p == nullptr) return nullptr; + return new QPen(static_cast(p)->pen()); +} + +extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) { + if (p == nullptr) return nullptr; + return new QBrush(static_cast(p)->brush()); +} + +extern "C" VQT6_API void* vqt6_qpainter_font(void* p) { + if (p == nullptr) return nullptr; + return new QFont(static_cast(p)->font()); +} + +extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) { + if (p == nullptr) return; + static_cast(p)->setOpacity(opacity); +} + +extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) { + if (p == nullptr) return 1.0; + return static_cast(p)->opacity(); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2) { + if (p == nullptr) return; + static_cast(p)->drawLine(x1, y1, x2, y2); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawRect(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color) { + if (p == nullptr || color == nullptr) return; + static_cast(p)->fillRect(x, y, w, h, *static_cast(color)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawEllipse(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawArc(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawChord(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawPie(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polygon; + for (int i = 0; i < point_count; ++i) { + polygon << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolygon(polygon); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polyline; + for (int i = 0; i < point_count; ++i) { + polyline << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolyline(polyline); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) { + if (p == nullptr) return; + static_cast(p)->drawPoint(x, y); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon pts; + for (int i = 0; i < point_count; ++i) { + pts << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPoints(pts); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, w, h, flags, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawPixmap(x, y, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image) { + if (p == nullptr || image == nullptr) return; + static_cast(p)->drawImage(x, y, *static_cast(image)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawTiledPixmap(x, y, w, h, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) { + if (p == nullptr) return; + static_cast(p)->translate(dx, dy); +} + +extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) { + if (p == nullptr) return; + static_cast(p)->rotate(angle); +} + +extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) { + if (p == nullptr) return; + static_cast(p)->scale(sx, sy); +} + +extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) { + if (p == nullptr) return; + static_cast(p)->resetTransform(); +} + +extern "C" VQT6_API void vqt6_qpainter_save(void* p) { + if (p == nullptr) return; + static_cast(p)->save(); +} + +extern "C" VQT6_API void vqt6_qpainter_restore(void* p) { + if (p == nullptr) return; + static_cast(p)->restore(); +} + +extern "C" VQT6_API void vqt6_qpainter_free(void* p) { + delete static_cast(p); +} + +// ============================================================ +// QPen +// ============================================================ +extern "C" VQT6_API void* vqt6_qpen_create(void) { + return new QPen(); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color(void* color) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color), width); +} + +extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) { + if (pen == nullptr || color == nullptr) return; + static_cast(pen)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_color(void* pen) { + if (pen == nullptr) return nullptr; + return new QColor(static_cast(pen)->color()); +} + +extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) { + if (pen == nullptr) return; + static_cast(pen)->setWidth(width); +} + +extern "C" VQT6_API int vqt6_qpen_width(void* pen) { + if (pen == nullptr) return 0; + return static_cast(pen)->width(); +} + +extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) { + if (pen == nullptr) return; + static_cast(pen)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qpen_style(void* pen) { + if (pen == nullptr) return 0; + return static_cast(static_cast(pen)->style()); +} + +extern "C" VQT6_API void vqt6_qpen_free(void* pen) { + delete static_cast(pen); +} + +// ============================================================ +// QBrush +// ============================================================ +extern "C" VQT6_API void* vqt6_qbrush_create(void) { + return new QBrush(); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_color(void* color) { + if (color == nullptr) return new QBrush(); + return new QBrush(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) { + return new QBrush(static_cast(style)); +} + +extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) { + if (brush == nullptr || color == nullptr) return; + static_cast(brush)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) { + if (brush == nullptr) return nullptr; + return new QColor(static_cast(brush)->color()); +} + +extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) { + if (brush == nullptr) return; + static_cast(brush)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qbrush_style(void* brush) { + if (brush == nullptr) return 0; + return static_cast(static_cast(brush)->style()); +} + +extern "C" VQT6_API void vqt6_qbrush_free(void* brush) { + delete static_cast(brush); +} + +// ============================================================ +// QIcon +// ============================================================ +extern "C" VQT6_API void* vqt6_qicon_create(void) { + return new QIcon(); +} + +extern "C" VQT6_API void* vqt6_qicon_create_with_file(void* file_name) { + if (file_name == nullptr) return new QIcon(); + return new QIcon(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name) { + if (icon == nullptr || file_name == nullptr) return; + static_cast(icon)->addFile(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) { + if (icon == nullptr || pixmap == nullptr) return; + static_cast(icon)->addPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) { + if (icon == nullptr) return 0; + return static_cast(icon)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h) { + if (icon == nullptr) return nullptr; + return new QPixmap(static_cast(icon)->pixmap(w, h)); +} + +extern "C" VQT6_API void vqt6_qicon_free(void* icon) { + delete static_cast(icon); +} + +// ============================================================ +// QCursor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcursor_create(void) { + return new QCursor(); +} + +extern "C" VQT6_API void* vqt6_qcursor_create_with_shape(int shape) { + return new QCursor(static_cast(shape)); +} + +extern "C" VQT6_API void vqt6_qcursor_pos(int* x, int* y) { + QPoint p = QCursor::pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API void vqt6_qcursor_set_pos(int x, int y) { + QCursor::setPos(x, y); +} + +extern "C" VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape) { + if (cursor == nullptr) return; + static_cast(cursor)->setShape(static_cast(shape)); +} + +extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) { + if (cursor == nullptr) return 0; + return static_cast(static_cast(cursor)->shape()); +} + +extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) { + delete static_cast(cursor); +} + +// ============================================================ +// QKeyEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) { + QString* t = static_cast(text); + return new QKeyEvent(static_cast(type), key, static_cast(modifiers), + t != nullptr ? *t : QString()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->key(); +} + +extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) { + if (event == nullptr) return nullptr; + return new QString(static_cast(event)->text()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAutoRepeat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QMouseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers) { + QPointF* lp = static_cast(local_pos); + return new QMouseEvent( + static_cast(type), + lp != nullptr ? *lp : QPointF(0, 0), + Qt::NoButton, + static_cast(button), + static_cast(modifiers) + ); +} + +extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->button()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->buttons()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height) { + return new QResizeEvent(QSize(width, height), QSize(old_width, old_height)); +} + +extern "C" VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->oldSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h) { + return new QPaintEvent(QRect(rect_x, rect_y, rect_w, rect_h)); +} + +extern "C" VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h) { + if (event == nullptr) return; + QRect r = static_cast(event)->rect(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qpaintevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qcloseevent_create(void) { + return new QCloseEvent(); +} + +extern "C" VQT6_API int vqt6_qcloseevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) { + delete static_cast(event); +} diff --git a/vqt6/_bridge_gui.h b/vqt6/_bridge_gui.h new file mode 100644 index 0000000..d2bb224 --- /dev/null +++ b/vqt6/_bridge_gui.h @@ -0,0 +1,231 @@ +// ============================================================ +// vqt6/_bridge_gui.h — QtGui C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_GUI_H +#define VQT6_BRIDGE_GUI_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QColor +// ============================================================ +VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b); +VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_create_name(void* name); +VQT6_API void* vqt6_qcolor_create_hex(void* hex_str); +VQT6_API int vqt6_qcolor_red(void* c); +VQT6_API int vqt6_qcolor_green(void* c); +VQT6_API int vqt6_qcolor_blue(void* c); +VQT6_API int vqt6_qcolor_alpha(void* c); +VQT6_API void vqt6_qcolor_set_red(void* c, int r); +VQT6_API void vqt6_qcolor_set_green(void* c, int g); +VQT6_API void vqt6_qcolor_set_blue(void* c, int b); +VQT6_API void vqt6_qcolor_set_alpha(void* c, int a); +VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b); +VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_name(void* c); +VQT6_API int vqt6_qcolor_is_valid(void* c); +VQT6_API void vqt6_qcolor_free(void* c); + +// ============================================================ +// QFont +// ============================================================ +VQT6_API void* vqt6_qfont_create(void); +VQT6_API void* vqt6_qfont_create_with_family(void* family); +VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size); +VQT6_API void vqt6_qfont_set_family(void* font, void* family); +VQT6_API void* vqt6_qfont_family(void* font); +VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size); +VQT6_API int vqt6_qfont_point_size(void* font); +VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size); +VQT6_API int vqt6_qfont_pixel_size(void* font); +VQT6_API void vqt6_qfont_set_bold(void* font, int bold); +VQT6_API int vqt6_qfont_bold(void* font); +VQT6_API void vqt6_qfont_set_italic(void* font, int italic); +VQT6_API int vqt6_qfont_italic(void* font); +VQT6_API void vqt6_qfont_set_underline(void* font, int underline); +VQT6_API int vqt6_qfont_underline(void* font); +VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out); +VQT6_API int vqt6_qfont_strike_out(void* font); +VQT6_API void vqt6_qfont_set_weight(void* font, int weight); +VQT6_API int vqt6_qfont_weight(void* font); +VQT6_API void vqt6_qfont_free(void* font); + +// ============================================================ +// QFontMetrics +// ============================================================ +VQT6_API void* vqt6_qfontmetrics_create(void* font); +VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text); +VQT6_API int vqt6_qfontmetrics_height(void* fm); +VQT6_API int vqt6_qfontmetrics_ascent(void* fm); +VQT6_API int vqt6_qfontmetrics_descent(void* fm); +VQT6_API void vqt6_qfontmetrics_free(void* fm); + +// ============================================================ +// QPixmap +// ============================================================ +VQT6_API void* vqt6_qpixmap_create(void); +VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h); +VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size); +VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_width(void* pm); +VQT6_API int vqt6_qpixmap_height(void* pm); +VQT6_API int vqt6_qpixmap_is_null(void* pm); +VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h); +VQT6_API void vqt6_qpixmap_fill(void* pm, void* color); +VQT6_API void vqt6_qpixmap_free(void* pm); + +// ============================================================ +// QImage +// ============================================================ +VQT6_API void* vqt6_qimage_create(void); +VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format); +VQT6_API int vqt6_qimage_load(void* img, void* file_name); +VQT6_API int vqt6_qimage_save(void* img, void* file_name); +VQT6_API int vqt6_qimage_width(void* img); +VQT6_API int vqt6_qimage_height(void* img); +VQT6_API int vqt6_qimage_format(void* img); +VQT6_API int vqt6_qimage_is_null(void* img); +VQT6_API void vqt6_qimage_fill(void* img, void* color); +VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h); +VQT6_API void vqt6_qimage_free(void* img); + +// ============================================================ +// QPainter +// ============================================================ +VQT6_API void* vqt6_qpainter_create(void); +VQT6_API int vqt6_qpainter_begin(void* p, void* device); +VQT6_API int vqt6_qpainter_end(void* p); +VQT6_API int vqt6_qpainter_is_active(void* p); +VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen); +VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush); +VQT6_API void vqt6_qpainter_set_font(void* p, void* font); +VQT6_API void* vqt6_qpainter_pen(void* p); +VQT6_API void* vqt6_qpainter_brush(void* p); +VQT6_API void* vqt6_qpainter_font(void* p); +VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity); +VQT6_API double vqt6_qpainter_opacity(void* p); +VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2); +VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color); +VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y); +VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text); +VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text); +VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap); +VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image); +VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap); +VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy); +VQT6_API void vqt6_qpainter_rotate(void* p, double angle); +VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy); +VQT6_API void vqt6_qpainter_reset_transform(void* p); +VQT6_API void vqt6_qpainter_save(void* p); +VQT6_API void vqt6_qpainter_restore(void* p); +VQT6_API void vqt6_qpainter_free(void* p); + +// ============================================================ +// QPen +// ============================================================ +VQT6_API void* vqt6_qpen_create(void); +VQT6_API void* vqt6_qpen_create_with_color(void* color); +VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width); +VQT6_API void vqt6_qpen_set_color(void* pen, void* color); +VQT6_API void* vqt6_qpen_color(void* pen); +VQT6_API void vqt6_qpen_set_width(void* pen, int width); +VQT6_API int vqt6_qpen_width(void* pen); +VQT6_API void vqt6_qpen_set_style(void* pen, int style); +VQT6_API int vqt6_qpen_style(void* pen); +VQT6_API void vqt6_qpen_free(void* pen); + +// ============================================================ +// QBrush +// ============================================================ +VQT6_API void* vqt6_qbrush_create(void); +VQT6_API void* vqt6_qbrush_create_with_color(void* color); +VQT6_API void* vqt6_qbrush_create_with_style(int style); +VQT6_API void vqt6_qbrush_set_color(void* brush, void* color); +VQT6_API void* vqt6_qbrush_color(void* brush); +VQT6_API void vqt6_qbrush_set_style(void* brush, int style); +VQT6_API int vqt6_qbrush_style(void* brush); +VQT6_API void vqt6_qbrush_free(void* brush); + +// ============================================================ +// QIcon +// ============================================================ +VQT6_API void* vqt6_qicon_create(void); +VQT6_API void* vqt6_qicon_create_with_file(void* file_name); +VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name); +VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap); +VQT6_API int vqt6_qicon_is_null(void* icon); +VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h); +VQT6_API void vqt6_qicon_free(void* icon); + +// ============================================================ +// QCursor +// ============================================================ +VQT6_API void* vqt6_qcursor_create(void); +VQT6_API void* vqt6_qcursor_create_with_shape(int shape); +VQT6_API void vqt6_qcursor_pos(int* x, int* y); +VQT6_API void vqt6_qcursor_set_pos(int x, int y); +VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape); +VQT6_API int vqt6_qcursor_shape(void* cursor); +VQT6_API void vqt6_qcursor_free(void* cursor); + +// ============================================================ +// QKeyEvent +// ============================================================ +VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text); +VQT6_API int vqt6_qkeyevent_key(void* event); +VQT6_API void* vqt6_qkeyevent_text(void* event); +VQT6_API int vqt6_qkeyevent_modifiers(void* event); +VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event); +VQT6_API void vqt6_qkeyevent_free(void* event); + +// ============================================================ +// QMouseEvent +// ============================================================ +VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers); +VQT6_API int vqt6_qmouseevent_button(void* event); +VQT6_API int vqt6_qmouseevent_buttons(void* event); +VQT6_API int vqt6_qmouseevent_x(void* event); +VQT6_API int vqt6_qmouseevent_y(void* event); +VQT6_API int vqt6_qmouseevent_global_x(void* event); +VQT6_API int vqt6_qmouseevent_global_y(void* event); +VQT6_API int vqt6_qmouseevent_modifiers(void* event); +VQT6_API void vqt6_qmouseevent_free(void* event); + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height); +VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_free(void* event); + +VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h); +VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qpaintevent_free(void* event); + +VQT6_API void* vqt6_qcloseevent_create(void); +VQT6_API int vqt6_qcloseevent_is_accepted(void* event); +VQT6_API void vqt6_qcloseevent_accept(void* event); +VQT6_API void vqt6_qcloseevent_ignore(void* event); +VQT6_API void vqt6_qcloseevent_free(void* event); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_GUI_H diff --git a/vqt6/_bridge_network.cpp b/vqt6/_bridge_network.cpp new file mode 100644 index 0000000..00cab5e --- /dev/null +++ b/vqt6/_bridge_network.cpp @@ -0,0 +1,519 @@ +// ============================================================ +// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_network.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QHostAddress +// ============================================================ +extern "C" VQT6_API void* vqt6_qhostaddress_create(void) { + return new QHostAddress(); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4) { + return new QHostAddress(static_cast(ipv4)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) { + if (address == nullptr) return new QHostAddress(); + return new QHostAddress(*static_cast(address)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_host(void) { + return new QHostAddress(QHostAddress::LocalHost); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void) { + return new QHostAddress(QHostAddress::LocalHostIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void) { + return new QHostAddress(QHostAddress::Broadcast); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void) { + return new QHostAddress(QHostAddress::AnyIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_to_string(void* addr) { + if (addr == nullptr) return nullptr; + return new QString(static_cast(addr)->toString()); +} + +extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->toIPv4Address()); +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isLoopback() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isBroadcast() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->protocol()); +} + +extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) { + delete static_cast(addr); +} + +// ============================================================ +// QAbstractSocket +// ============================================================ +extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->state()); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->error()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) { + if (socket == nullptr) return nullptr; + return new QString(static_cast(socket)->errorString()); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->disconnectFromHost(); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForConnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForReadyRead(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForBytesWritten(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForDisconnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_valid(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isOpen() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->flush() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size) { + if (socket == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(socket)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size) { + if (socket == nullptr) return nullptr; + QByteArray ba = static_cast(socket)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size) { + if (socket == nullptr || data == nullptr) return 0; + return static_cast(static_cast(socket)->write(static_cast(data), static_cast(size))); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesAvailable()); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesToWrite()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->peerAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->peerPort()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->localAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->localPort()); +} + +// ============================================================ +// QTcpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qtcpsocket_create(void) { + return new QTcpSocket(); +} + +extern "C" VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTcpSocket(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port, + static_cast(mode)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port, + static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor) { + if (socket == nullptr) return 0; + return static_cast(socket)->setSocketDescriptor(static_cast(socket_descriptor)) ? 1 : 0; +} + +extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) { + if (socket == nullptr) return -1; + return static_cast(static_cast(socket)->socketDescriptor()); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type) { + Q_UNUSED(socket); + Q_UNUSED(proxy_type); + // QNetworkProxy 配置在更高层 +} + +extern "C" VQT6_API void vqt6_qtcpsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +// ============================================================ +// QUdpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qudpsocket_create(void) { + return new QUdpSocket(); +} + +extern "C" VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QUdpSocket(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) { + if (socket == nullptr) return 0; + return static_cast(socket)->bind(port) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return 0; + return static_cast(socket)->bind(*static_cast(address), port) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port) { + if (socket == nullptr || data == nullptr || host == nullptr) return 0; + return static_cast(static_cast(socket)->writeDatagram( + static_cast(data), static_cast(size), + *static_cast(host), port)); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port) { + if (socket == nullptr || data == nullptr) return 0; + QHostAddress sender; + quint16 sender_port = 0; + qint64 n = static_cast(socket)->readDatagram( + static_cast(data), static_cast(max_size), &sender, &sender_port); + if (host != nullptr) { + QHostAddress* dst = static_cast(host); + *dst = sender; + } + if (port != nullptr) { + *port = sender_port; + } + return static_cast(n); +} + +extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->hasPendingDatagrams() ? 1 : 0; +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->pendingDatagramSize()); +} + +extern "C" VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->joinMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->leaveMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +// ============================================================ +// QNetworkRequest +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkrequest_create(void) { + return new QNetworkRequest(); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url) { + if (url == nullptr) return new QNetworkRequest(); + return new QNetworkRequest(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) { + if (req == nullptr || url == nullptr) return; + static_cast(req)->setUrl(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) { + if (req == nullptr) return nullptr; + return new QString(static_cast(req)->url().toString()); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setHeader(static_cast(header_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size) { + if (req == nullptr || header_name == nullptr) return; + static_cast(req)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size) { + if (req == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(req)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setAttribute(static_cast(attr_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->attribute(static_cast(attr_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) { + delete static_cast(req); +} + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create(void) { + return new QNetworkAccessManager(); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QNetworkAccessManager(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->get(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->post(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->put(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->deleteResource(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->head(*static_cast(req)); +} + +extern "C" VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store) { + if (nam == nullptr || store == nullptr) return; + QNetworkCookieJar* jar = qobject_cast(static_cast(store)); + if (jar != nullptr) { + static_cast(nam)->setCookieJar(jar); + } +} + +// ============================================================ +// QNetworkReply +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->url().toString()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) { + if (reply == nullptr) return nullptr; + return new QNetworkRequest(static_cast(reply)->request()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->error()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->errorString()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isFinished() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isRunning() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) { + if (reply == nullptr) return; + static_cast(reply)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size) { + if (reply == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(reply)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size) { + if (reply == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->bytesAvailable()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size) { + if (reply == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->attribute(static_cast(attribute_code))); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value) { + if (reply == nullptr) return default_value; + return static_cast(reply)->attribute(static_cast(attribute_code)).toInt(default_value); +} + +extern "C" VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size) { + if (reply == nullptr || header_name == nullptr) return; + static_cast(reply)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} diff --git a/vqt6/_bridge_network.h b/vqt6/_bridge_network.h new file mode 100644 index 0000000..2f99580 --- /dev/null +++ b/vqt6/_bridge_network.h @@ -0,0 +1,137 @@ +// ============================================================ +// vqt6/_bridge_network.h — QtNetwork C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_NETWORK_H +#define VQT6_BRIDGE_NETWORK_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QHostAddress +// ============================================================ +VQT6_API void* vqt6_qhostaddress_create(void); +VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4); +VQT6_API void* vqt6_qhostaddress_create_with_string(void* address); +VQT6_API void* vqt6_qhostaddress_create_with_local_host(void); +VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void); +VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void); +VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void); +VQT6_API void* vqt6_qhostaddress_to_string(void* addr); +VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr); +VQT6_API int vqt6_qhostaddress_is_null(void* addr); +VQT6_API int vqt6_qhostaddress_is_loopback(void* addr); +VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr); +VQT6_API int vqt6_qhostaddress_protocol(void* addr); +VQT6_API void vqt6_qhostaddress_free(void* addr); + +// ============================================================ +// QAbstractSocket +// ============================================================ +VQT6_API int vqt6_qabstractsocket_state(void* socket); +VQT6_API int vqt6_qabstractsocket_error(void* socket); +VQT6_API void* vqt6_qabstractsocket_error_string(void* socket); +VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port); +VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket); +VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_is_valid(void* socket); +VQT6_API int vqt6_qabstractsocket_is_open(void* socket); +VQT6_API int vqt6_qabstractsocket_flush(void* socket); +VQT6_API void vqt6_qabstractsocket_close(void* socket); +VQT6_API void vqt6_qabstractsocket_abort(void* socket); +VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size); +VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size); +VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size); +VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket); +VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket); +VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket); +VQT6_API void* vqt6_qabstractsocket_local_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket); + +// ============================================================ +// QTcpSocket +// ============================================================ +VQT6_API void* vqt6_qtcpsocket_create(void); +VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent); +VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode); +VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode); +VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor); +VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket); +VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type); +VQT6_API void vqt6_qtcpsocket_abort(void* socket); + +// ============================================================ +// QUdpSocket +// ============================================================ +VQT6_API void* vqt6_qudpsocket_create(void); +VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent); +VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port); +VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qudpsocket_close(void* socket); +VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port); +VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port); +VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket); +VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket); +VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address); +VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address); + +// ============================================================ +// QNetworkRequest +// ============================================================ +VQT6_API void* vqt6_qnetworkrequest_create(void); +VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url); +VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url); +VQT6_API void* vqt6_qnetworkrequest_url(void* req); +VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type); +VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size); +VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size); +VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type); +VQT6_API void vqt6_qnetworkrequest_free(void* req); + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +VQT6_API void* vqt6_qnetworkaccessmanager_create(void); +VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent); +VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req); +VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store); + +// ============================================================ +// QNetworkReply +// ============================================================ +VQT6_API void* vqt6_qnetworkreply_url(void* reply); +VQT6_API void* vqt6_qnetworkreply_request(void* reply); +VQT6_API int vqt6_qnetworkreply_error(void* reply); +VQT6_API void* vqt6_qnetworkreply_error_string(void* reply); +VQT6_API int vqt6_qnetworkreply_is_finished(void* reply); +VQT6_API int vqt6_qnetworkreply_is_running(void* reply); +VQT6_API void vqt6_qnetworkreply_abort(void* reply); +VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size); +VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size); +VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply); +VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type); +VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size); +VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code); +VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value); +VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_NETWORK_H diff --git a/vqt6/_bridge_widgets.cpp b/vqt6/_bridge_widgets.cpp new file mode 100644 index 0000000..2b963a5 --- /dev/null +++ b/vqt6/_bridge_widgets.cpp @@ -0,0 +1,1745 @@ +// ============================================================ +// vqt6/_bridge_widgets.cpp — QtWidgets C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_widgets.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qapplication_create(int argc, char** argv) { + return new QApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qapplication_instance(void) { + return QApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qapplication_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qapplication_quit(void* app) { + if (app == nullptr) return; + static_cast(app)->quit(); +} + +extern "C" VQT6_API void vqt6_qapplication_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qapplication_process_events(void* app) { + if (app == nullptr) return; + static_cast(app)->processEvents(); +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_width(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().width() : 0; +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_height(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().height() : 0; +} + +extern "C" VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit) { + if (app == nullptr) return; + static_cast(app)->setQuitOnLastWindowClosed(quit != 0); +} + +extern "C" VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app) { + if (app == nullptr) return 0; + return QApplication::quitOnLastWindowClosed() ? 1 : 0; +} + +// ============================================================ +// QWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qwidget_create(void) { + return new QWidget(); +} + +extern "C" VQT6_API void* vqt6_qwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qwidget_show(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->show(); +} + +extern "C" VQT6_API void vqt6_qwidget_hide(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->hide(); +} + +extern "C" VQT6_API int vqt6_qwidget_close(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->close() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qwidget_is_visible(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isVisible() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible) { + if (widget == nullptr) return; + static_cast(widget)->setVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setGeometry(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h) { + if (widget == nullptr) return; + QRect r = static_cast(widget)->geometry(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->resize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_move(void* widget, int x, int y) { + if (widget == nullptr) return; + static_cast(widget)->move(x, y); +} + +extern "C" VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y) { + if (widget == nullptr) return; + QPoint p = static_cast(widget)->pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API int vqt6_qwidget_width(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->width(); +} + +extern "C" VQT6_API int vqt6_qwidget_height(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->height(); +} + +extern "C" VQT6_API int vqt6_qwidget_x(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->x(); +} + +extern "C" VQT6_API int vqt6_qwidget_y(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->y(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title) { + if (widget == nullptr || title == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qwidget_window_title(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_text(void* widget, void* text) { + if (widget == nullptr || text == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qwidget_text(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qwidget_is_enabled(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent) { + if (widget == nullptr) return; + static_cast(widget)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qwidget_parent_widget(void* widget) { + if (widget == nullptr) return nullptr; + return static_cast(widget)->parentWidget(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->setFocus(); +} + +extern "C" VQT6_API void vqt6_qwidget_clear_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->clearFocus(); +} + +extern "C" VQT6_API int vqt6_qwidget_has_focus(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->hasFocus() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy) { + if (widget == nullptr) return; + static_cast(widget)->setFocusPolicy(static_cast(policy)); +} + +extern "C" VQT6_API void vqt6_qwidget_update(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->update(); +} + +extern "C" VQT6_API void vqt6_qwidget_repaint(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->repaint(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setUpdatesEnabled(enabled != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags) { + if (widget == nullptr) return; + static_cast(widget)->setWindowFlags(static_cast(flags)); +} + +extern "C" VQT6_API int vqt6_qwidget_window_flags(void* widget) { + if (widget == nullptr) return 0; + return static_cast(static_cast(widget)->windowFlags()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor) { + if (widget == nullptr || cursor == nullptr) return; + static_cast(widget)->setCursor(*static_cast(cursor)); +} + +extern "C" VQT6_API void* vqt6_qwidget_cursor(void* widget) { + if (widget == nullptr) return nullptr; + return new QCursor(static_cast(widget)->cursor()); +} + +extern "C" VQT6_API void vqt6_qwidget_unset_cursor(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->unsetCursor(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setToolTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_tool_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->toolTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setStatusTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_status_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->statusTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMinimumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMaximumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setFixedSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->minimumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->maximumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +// ============================================================ +// QDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qdialog_create(void) { + return new QDialog(); +} + +extern "C" VQT6_API void* vqt6_qdialog_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QDialog(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qdialog_exec(void* dialog) { + if (dialog == nullptr) return -1; + return static_cast(dialog)->exec(); +} + +extern "C" VQT6_API void vqt6_qdialog_done(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->done(result); +} + +extern "C" VQT6_API void vqt6_qdialog_accept(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->accept(); +} + +extern "C" VQT6_API void vqt6_qdialog_reject(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->reject(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_result(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->setResult(result); +} + +extern "C" VQT6_API int vqt6_qdialog_result(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->result(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal) { + if (dialog == nullptr) return; + static_cast(dialog)->setModal(modal != 0); +} + +extern "C" VQT6_API int vqt6_qdialog_is_modal(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->isModal() ? 1 : 0; +} + +// ============================================================ +// QMainWindow +// ============================================================ +extern "C" VQT6_API void* vqt6_qmainwindow_create(void) { + return new QMainWindow(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMainWindow(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget) { + if (mw == nullptr) return; + static_cast(mw)->setCentralWidget(static_cast(widget)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_central_widget(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->centralWidget(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->menuBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar) { + if (mw == nullptr) return; + static_cast(mw)->setMenuBar(static_cast(menubar)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_status_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->statusBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar) { + if (mw == nullptr) return; + static_cast(mw)->setStatusBar(static_cast(statusbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar) { + if (mw == nullptr) return; + static_cast(mw)->addToolBar(static_cast(toolbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw) { + if (mw == nullptr) return; + static_cast(mw)->addToolBarBreak(); +} + +// ============================================================ +// QLabel +// ============================================================ +extern "C" VQT6_API void* vqt6_qlabel_create(void) { + return new QLabel(); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLabel(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLabel(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlabel_set_text(void* label, void* text) { + if (label == nullptr || text == nullptr) return; + static_cast(label)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_text(void* label) { + if (label == nullptr) return nullptr; + return new QString(static_cast(label)->text()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment) { + if (label == nullptr) return; + static_cast(label)->setAlignment(static_cast(alignment)); +} + +extern "C" VQT6_API int vqt6_qlabel_alignment(void* label) { + if (label == nullptr) return 0; + return static_cast(static_cast(label)->alignment()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap) { + if (label == nullptr || pixmap == nullptr) return; + static_cast(label)->setPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API void* vqt6_qlabel_pixmap(void* label) { + if (label == nullptr) return nullptr; + return new QPixmap(static_cast(label)->pixmap()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_indent(void* label, int indent) { + if (label == nullptr) return; + static_cast(label)->setIndent(indent); +} + +extern "C" VQT6_API void vqt6_qlabel_set_margin(void* label, int margin) { + if (label == nullptr) return; + static_cast(label)->setMargin(margin); +} + +extern "C" VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap) { + if (label == nullptr) return; + static_cast(label)->setWordWrap(wrap != 0); +} + +extern "C" VQT6_API int vqt6_qlabel_word_wrap(void* label) { + if (label == nullptr) return 0; + return static_cast(label)->wordWrap() ? 1 : 0; +} + +// ============================================================ +// QPushButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qpushbutton_create(void) { + return new QPushButton(); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QPushButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QPushButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text) { + if (btn == nullptr || text == nullptr) return; + static_cast(btn)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_text(void* btn) { + if (btn == nullptr) return nullptr; + return new QString(static_cast(btn)->text()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon) { + if (btn == nullptr || icon == nullptr) return; + static_cast(btn)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_icon(void* btn) { + if (btn == nullptr) return nullptr; + return new QIcon(static_cast(btn)->icon()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default) { + if (btn == nullptr) return; + static_cast(btn)->setDefault(is_default != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_default(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isDefault() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat) { + if (btn == nullptr) return; + static_cast(btn)->setFlat(flat != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_flat(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isFlat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable) { + if (btn == nullptr) return; + static_cast(btn)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checkable(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked) { + if (btn == nullptr) return; + static_cast(btn)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checked(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_click(void* btn) { + if (btn == nullptr) return; + static_cast(btn)->click(); +} + +// ============================================================ +// QLineEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qlineedit_create(void) { + return new QLineEdit(); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLineEdit(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLineEdit(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->text()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_placeholder_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->placeholderText()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setPlaceholderText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max) { + if (le == nullptr) return; + static_cast(le)->setMaxLength(max); +} + +extern "C" VQT6_API int vqt6_qlineedit_max_length(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->maxLength(); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro) { + if (le == nullptr) return; + static_cast(le)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qlineedit_is_read_only(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode) { + if (le == nullptr) return; + static_cast(le)->setEchoMode(static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qlineedit_echo_mode(void* le) { + if (le == nullptr) return 0; + return static_cast(static_cast(le)->echoMode()); +} + +extern "C" VQT6_API void vqt6_qlineedit_select_all(void* le) { + if (le == nullptr) return; + static_cast(le)->selectAll(); +} + +extern "C" VQT6_API void vqt6_qlineedit_clear(void* le) { + if (le == nullptr) return; + static_cast(le)->clear(); +} + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qtextedit_create(void) { + return new QTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_plain_text(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_html(void* te, void* html) { + if (te == nullptr || html == nullptr) return; + static_cast(te)->setHtml(*static_cast(html)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_html(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toHtml()); +} + +extern "C" VQT6_API void vqt6_qtextedit_append(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->append(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_clear(void* te) { + if (te == nullptr) return; + static_cast(te)->clear(); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro) { + if (te == nullptr) return; + static_cast(te)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qtextedit_is_read_only(void* te) { + if (te == nullptr) return 0; + return static_cast(te)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create(void) { + return new QPlainTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QPlainTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte) { + if (pte == nullptr) return nullptr; + return new QString(static_cast(pte)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->appendPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_clear(void* pte) { + if (pte == nullptr) return; + static_cast(pte)->clear(); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro) { + if (pte == nullptr) return; + static_cast(pte)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qplaintextedit_line_count(void* pte) { + if (pte == nullptr) return 0; + return static_cast(pte)->blockCount(); +} + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qcheckbox_create(void) { + return new QCheckBox(); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QCheckBox(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QCheckBox(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked) { + if (cb == nullptr) return; + static_cast(cb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_checked(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->text()); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate) { + if (cb == nullptr) return; + static_cast(cb)->setTristate(tristate != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_tristate(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isTristate() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create(void) { + return new QRadioButton(); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QRadioButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QRadioButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked) { + if (rb == nullptr) return; + static_cast(rb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qradiobutton_is_checked(void* rb) { + if (rb == nullptr) return 0; + return static_cast(rb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text) { + if (rb == nullptr || text == nullptr) return; + static_cast(rb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_text(void* rb) { + if (rb == nullptr) return nullptr; + return new QString(static_cast(rb)->text()); +} + +// ============================================================ +// QComboBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qcombobox_create(void) { + return new QComboBox(); +} + +extern "C" VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QComboBox(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items) { + if (cb == nullptr || items == nullptr) return; + static_cast(cb)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->insertItem(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->removeItem(index); +} + +extern "C" VQT6_API void vqt6_qcombobox_clear(void* cb) { + if (cb == nullptr) return; + static_cast(cb)->clear(); +} + +extern "C" VQT6_API int vqt6_qcombobox_count(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->count(); +} + +extern "C" VQT6_API int vqt6_qcombobox_current_index(void* cb) { + if (cb == nullptr) return -1; + return static_cast(cb)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qcombobox_current_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->currentText()); +} + +extern "C" VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->itemText(index)); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable) { + if (cb == nullptr) return; + static_cast(cb)->setEditable(editable != 0); +} + +extern "C" VQT6_API int vqt6_qcombobox_is_editable(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isEditable() ? 1 : 0; +} + +// ============================================================ +// QListWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qlistwidget_create(void) { + return new QListWidget(); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QListWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items) { + if (lw == nullptr || items == nullptr) return; + static_cast(lw)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->insertItem(row, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row) { + if (lw == nullptr) return nullptr; + return static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void vqt6_qlistwidget_clear(void* lw) { + if (lw == nullptr) return; + static_cast(lw)->clear(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_count(void* lw) { + if (lw == nullptr) return 0; + return static_cast(lw)->count(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_current_row(void* lw) { + if (lw == nullptr) return -1; + return static_cast(lw)->currentRow(); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->setCurrentRow(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->currentItem(); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it != nullptr) it->setText(*static_cast(text)); +} + +// ============================================================ +// QProgressBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qprogressbar_create(void) { + return new QProgressBar(); +} + +extern "C" VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QProgressBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value) { + if (pb == nullptr) return; + static_cast(pb)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qprogressbar_value(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->value(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min) { + if (pb == nullptr) return; + static_cast(pb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max) { + if (pb == nullptr) return; + static_cast(pb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max) { + if (pb == nullptr) return; + static_cast(pb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qprogressbar_minimum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qprogressbar_maximum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible) { + if (pb == nullptr) return; + static_cast(pb)->setTextVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format) { + if (pb == nullptr || format == nullptr) return; + static_cast(pb)->setFormat(*static_cast(format)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_reset(void* pb) { + if (pb == nullptr) return; + static_cast(pb)->reset(); +} + +// ============================================================ +// QSlider +// ============================================================ +extern "C" VQT6_API void* vqt6_qslider_create(void) { + return new QSlider(); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation(int orientation) { + return new QSlider(static_cast(orientation)); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent) { + if (parent == nullptr) return nullptr; + return new QSlider(static_cast(orientation), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qslider_set_value(void* s, int value) { + if (s == nullptr) return; + static_cast(s)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qslider_value(void* s) { + if (s == nullptr) return 0; + return static_cast(s)->value(); +} + +extern "C" VQT6_API void vqt6_qslider_set_minimum(void* s, int min) { + if (s == nullptr) return; + static_cast(s)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qslider_set_maximum(void* s, int max) { + if (s == nullptr) return; + static_cast(s)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qslider_set_range(void* s, int min, int max) { + if (s == nullptr) return; + static_cast(s)->setRange(min, max); +} + +extern "C" VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation) { + if (s == nullptr) return; + static_cast(s)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qslider_orientation(void* s) { + if (s == nullptr) return 0; + return static_cast(static_cast(s)->orientation()); +} + +extern "C" VQT6_API void vqt6_qslider_set_single_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qslider_set_page_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setPageStep(step); +} + +// ============================================================ +// QSpinBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qspinbox_create(void) { + return new QSpinBox(); +} + +extern "C" VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QSpinBox(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qspinbox_value(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->value(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_value(void* sb, int value) { + if (sb == nullptr) return; + static_cast(sb)->setValue(value); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min) { + if (sb == nullptr) return; + static_cast(sb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max) { + if (sb == nullptr) return; + static_cast(sb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max) { + if (sb == nullptr) return; + static_cast(sb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qspinbox_minimum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qspinbox_maximum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step) { + if (sb == nullptr) return; + static_cast(sb)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix) { + if (sb == nullptr || prefix == nullptr) return; + static_cast(sb)->setPrefix(*static_cast(prefix)); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix) { + if (sb == nullptr || suffix == nullptr) return; + static_cast(sb)->setSuffix(*static_cast(suffix)); +} + +extern "C" VQT6_API void* vqt6_qspinbox_prefix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->prefix()); +} + +extern "C" VQT6_API void* vqt6_qspinbox_suffix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->suffix()); +} + +// ============================================================ +// Layouts +// ============================================================ +extern "C" VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->addWidget(static_cast(widget)); +} + +extern "C" VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->removeWidget(static_cast(widget)); +} + +extern "C" VQT6_API int vqt6_qlayout_count(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->count(); +} + +extern "C" VQT6_API void* vqt6_qlayout_item_at(void* layout, int index) { + if (layout == nullptr) return nullptr; + QLayoutItem* item = static_cast(layout)->itemAt(index); + return item != nullptr ? item->widget() : nullptr; +} + +extern "C" VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom) { + if (layout == nullptr) return; + static_cast(layout)->setContentsMargins(left, top, right, bottom); +} + +extern "C" VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing) { + if (layout == nullptr) return; + static_cast(layout)->setSpacing(spacing); +} + +extern "C" VQT6_API int vqt6_qlayout_spacing(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->spacing(); +} + +extern "C" VQT6_API void vqt6_qlayout_invalidate(void* layout) { + if (layout == nullptr) return; + static_cast(layout)->invalidate(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create(void) { + return new QHBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QHBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create(void) { + return new QVBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QVBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create(void) { + return new QGridLayout(); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QGridLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col, row_span, col_span); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create(void) { + return new QFormLayout(); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QFormLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(*static_cast(label), static_cast(field)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(static_cast(label), static_cast(field)); +} + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qstackedwidget_create(void) { + return new QStackedWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStackedWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return -1; + return static_cast(sw)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return; + static_cast(sw)->removeWidget(static_cast(w)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_count(void* sw) { + if (sw == nullptr) return 0; + return static_cast(sw)->count(); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_current_index(void* sw) { + if (sw == nullptr) return -1; + return static_cast(sw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index) { + if (sw == nullptr) return; + static_cast(sw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->currentWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->widget(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create(void) { + return new QTabWidget(); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTabWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->addTab(static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->insertTab(index, static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->removeTab(index); +} + +extern "C" VQT6_API int vqt6_qtabwidget_count(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->count(); +} + +extern "C" VQT6_API int vqt6_qtabwidget_current_index(void* tw) { + if (tw == nullptr) return -1; + return static_cast(tw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index) { + if (tw == nullptr) return nullptr; + return new QString(static_cast(tw)->tabText(index)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text) { + if (tw == nullptr || text == nullptr) return; + static_cast(tw)->setTabText(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable) { + if (tw == nullptr) return; + static_cast(tw)->setTabsClosable(closable != 0); +} + +extern "C" VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->tabsClosable() ? 1 : 0; +} + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +extern "C" VQT6_API void* vqt6_qmenubar_create(void) { + return new QMenuBar(); +} + +extern "C" VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMenuBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title) { + if (mb == nullptr || title == nullptr) return nullptr; + return static_cast(mb)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu) { + if (mb == nullptr || menu == nullptr) return; + static_cast(mb)->addMenu(static_cast(menu)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action) { + if (mb == nullptr || action == nullptr) return; + static_cast(mb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenubar_clear(void* mb) { + if (mb == nullptr) return; + static_cast(mb)->clear(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create(void) { + return new QMenu(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title(void* title) { + if (title == nullptr) return nullptr; + return new QMenu(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent) { + if (title == nullptr || parent == nullptr) return nullptr; + return new QMenu(*static_cast(title), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return nullptr; + return static_cast(menu)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_action(void* menu, void* action) { + if (menu == nullptr || action == nullptr) return; + static_cast(menu)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_separator(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qmenu_clear(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->clear(); +} + +extern "C" VQT6_API void vqt6_qmenu_set_title(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return; + static_cast(menu)->setTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_title(void* menu) { + if (menu == nullptr) return nullptr; + return new QString(static_cast(menu)->title()); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text) { + if (menu == nullptr || text == nullptr) return nullptr; + return static_cast(menu)->addAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create(void) { + return new QAction(); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QAction(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qaction_set_text(void* action, void* text) { + if (action == nullptr || text == nullptr) return; + static_cast(action)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_text(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->text()); +} + +extern "C" VQT6_API void vqt6_qaction_set_icon(void* action, void* icon) { + if (action == nullptr || icon == nullptr) return; + static_cast(action)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qaction_icon(void* action) { + if (action == nullptr) return nullptr; + return new QIcon(static_cast(action)->icon()); +} + +extern "C" VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence) { + if (action == nullptr || key_sequence == nullptr) return; + static_cast(action)->setShortcut(QKeySequence(*static_cast(key_sequence))); +} + +extern "C" VQT6_API void* vqt6_qaction_shortcut(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->shortcut().toString()); +} + +extern "C" VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable) { + if (action == nullptr) return; + static_cast(action)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checkable(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_checked(void* action, int checked) { + if (action == nullptr) return; + static_cast(action)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checked(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled) { + if (action == nullptr) return; + static_cast(action)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_enabled(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_trigger(void* action) { + if (action == nullptr) return; + static_cast(action)->trigger(); +} + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qstatusbar_create(void) { + return new QStatusBar(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStatusBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms) { + if (sb == nullptr || message == nullptr) return; + static_cast(sb)->showMessage(*static_cast(message), timeout_ms); +} + +extern "C" VQT6_API void vqt6_qstatusbar_clear_message(void* sb) { + if (sb == nullptr) return; + static_cast(sb)->clearMessage(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_current_message(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->currentMessage()); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addPermanentWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create(void) { + return new QToolBar(); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QToolBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w) { + if (tb == nullptr || w == nullptr) return nullptr; + return static_cast(tb)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action) { + if (tb == nullptr || action == nullptr) return; + static_cast(tb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_separator(void* tb) { + if (tb == nullptr) return; + static_cast(tb)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h) { + if (tb == nullptr) return; + static_cast(tb)->setIconSize(QSize(w, h)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation) { + if (tb == nullptr) return; + static_cast(tb)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qtoolbar_orientation(void* tb) { + if (tb == nullptr) return 0; + return static_cast(static_cast(tb)->orientation()); +} + +// ============================================================ +// QMessageBox +// ============================================================ +extern "C" VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0400), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0100), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text) { + if (title == nullptr || text == nullptr) return; + QMessageBox::about(static_cast(parent), *static_cast(title), *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about_qt(void* parent) { + QMessageBox::aboutQt(static_cast(parent)); +} + +// ============================================================ +// QFileDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getOpenFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getSaveFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir) { + QString* result = new QString(QFileDialog::getExistingDirectory( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter) { + return new QStringList(QFileDialog::getOpenFileNames( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); +} diff --git a/vqt6/_bridge_widgets.h b/vqt6/_bridge_widgets.h new file mode 100644 index 0000000..0197377 --- /dev/null +++ b/vqt6/_bridge_widgets.h @@ -0,0 +1,432 @@ +// ============================================================ +// vqt6/_bridge_widgets.h — QtWidgets C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_WIDGETS_H +#define VQT6_BRIDGE_WIDGETS_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QApplication +// ============================================================ +VQT6_API void* vqt6_qapplication_create(int argc, char** argv); +VQT6_API void* vqt6_qapplication_instance(void); +VQT6_API int vqt6_qapplication_exec(void* app); +VQT6_API void vqt6_qapplication_quit(void* app); +VQT6_API void vqt6_qapplication_exit(void* app, int exit_code); +VQT6_API void vqt6_qapplication_process_events(void* app); +VQT6_API int vqt6_qapplication_desktop_width(void* app); +VQT6_API int vqt6_qapplication_desktop_height(void* app); +VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit); +VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app); + +// ============================================================ +// QWidget +// ============================================================ +VQT6_API void* vqt6_qwidget_create(void); +VQT6_API void* vqt6_qwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qwidget_show(void* widget); +VQT6_API void vqt6_qwidget_hide(void* widget); +VQT6_API int vqt6_qwidget_close(void* widget); +VQT6_API int vqt6_qwidget_is_visible(void* widget); +VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible); +VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h); +VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_move(void* widget, int x, int y); +VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y); +VQT6_API int vqt6_qwidget_width(void* widget); +VQT6_API int vqt6_qwidget_height(void* widget); +VQT6_API int vqt6_qwidget_x(void* widget); +VQT6_API int vqt6_qwidget_y(void* widget); +VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title); +VQT6_API void* vqt6_qwidget_window_title(void* widget); +VQT6_API void vqt6_qwidget_set_text(void* widget, void* text); +VQT6_API void* vqt6_qwidget_text(void* widget); +VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled); +VQT6_API int vqt6_qwidget_is_enabled(void* widget); +VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent); +VQT6_API void* vqt6_qwidget_parent_widget(void* widget); +VQT6_API void vqt6_qwidget_set_focus(void* widget); +VQT6_API void vqt6_qwidget_clear_focus(void* widget); +VQT6_API int vqt6_qwidget_has_focus(void* widget); +VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy); +VQT6_API void vqt6_qwidget_update(void* widget); +VQT6_API void vqt6_qwidget_repaint(void* widget); +VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled); +VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags); +VQT6_API int vqt6_qwidget_window_flags(void* widget); +VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor); +VQT6_API void* vqt6_qwidget_cursor(void* widget); +VQT6_API void vqt6_qwidget_unset_cursor(void* widget); +VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_tool_tip(void* widget); +VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_status_tip(void* widget); +VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h); + +// ============================================================ +// QDialog +// ============================================================ +VQT6_API void* vqt6_qdialog_create(void); +VQT6_API void* vqt6_qdialog_create_with_parent(void* parent); +VQT6_API int vqt6_qdialog_exec(void* dialog); +VQT6_API void vqt6_qdialog_done(void* dialog, int result); +VQT6_API void vqt6_qdialog_accept(void* dialog); +VQT6_API void vqt6_qdialog_reject(void* dialog); +VQT6_API void vqt6_qdialog_set_result(void* dialog, int result); +VQT6_API int vqt6_qdialog_result(void* dialog); +VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal); +VQT6_API int vqt6_qdialog_is_modal(void* dialog); + +// ============================================================ +// QMainWindow +// ============================================================ +VQT6_API void* vqt6_qmainwindow_create(void); +VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent); +VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget); +VQT6_API void* vqt6_qmainwindow_central_widget(void* mw); +VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar); +VQT6_API void* vqt6_qmainwindow_status_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw); + +// ============================================================ +// QLabel +// ============================================================ +VQT6_API void* vqt6_qlabel_create(void); +VQT6_API void* vqt6_qlabel_create_with_text(void* text); +VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qlabel_set_text(void* label, void* text); +VQT6_API void* vqt6_qlabel_text(void* label); +VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment); +VQT6_API int vqt6_qlabel_alignment(void* label); +VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap); +VQT6_API void* vqt6_qlabel_pixmap(void* label); +VQT6_API void vqt6_qlabel_set_indent(void* label, int indent); +VQT6_API void vqt6_qlabel_set_margin(void* label, int margin); +VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap); +VQT6_API int vqt6_qlabel_word_wrap(void* label); + +// ============================================================ +// QPushButton +// ============================================================ +VQT6_API void* vqt6_qpushbutton_create(void); +VQT6_API void* vqt6_qpushbutton_create_with_text(void* text); +VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text); +VQT6_API void* vqt6_qpushbutton_text(void* btn); +VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon); +VQT6_API void* vqt6_qpushbutton_icon(void* btn); +VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default); +VQT6_API int vqt6_qpushbutton_is_default(void* btn); +VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat); +VQT6_API int vqt6_qpushbutton_is_flat(void* btn); +VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable); +VQT6_API int vqt6_qpushbutton_is_checkable(void* btn); +VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked); +VQT6_API int vqt6_qpushbutton_is_checked(void* btn); +VQT6_API void vqt6_qpushbutton_click(void* btn); + +// ============================================================ +// QLineEdit +// ============================================================ +VQT6_API void* vqt6_qlineedit_create(void); +VQT6_API void* vqt6_qlineedit_create_with_text(void* text); +VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent); +VQT6_API void* vqt6_qlineedit_text(void* le); +VQT6_API void vqt6_qlineedit_set_text(void* le, void* text); +VQT6_API void* vqt6_qlineedit_placeholder_text(void* le); +VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text); +VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max); +VQT6_API int vqt6_qlineedit_max_length(void* le); +VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro); +VQT6_API int vqt6_qlineedit_is_read_only(void* le); +VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode); +VQT6_API int vqt6_qlineedit_echo_mode(void* le); +VQT6_API void vqt6_qlineedit_select_all(void* le); +VQT6_API void vqt6_qlineedit_clear(void* le); + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +VQT6_API void* vqt6_qtextedit_create(void); +VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qtextedit_to_plain_text(void* te); +VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text); +VQT6_API void vqt6_qtextedit_set_html(void* te, void* html); +VQT6_API void* vqt6_qtextedit_to_html(void* te); +VQT6_API void vqt6_qtextedit_append(void* te, void* text); +VQT6_API void vqt6_qtextedit_clear(void* te); +VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro); +VQT6_API int vqt6_qtextedit_is_read_only(void* te); + +VQT6_API void* vqt6_qplaintextedit_create(void); +VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte); +VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_clear(void* pte); +VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro); +VQT6_API int vqt6_qplaintextedit_line_count(void* pte); + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +VQT6_API void* vqt6_qcheckbox_create(void); +VQT6_API void* vqt6_qcheckbox_create_with_text(void* text); +VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked); +VQT6_API int vqt6_qcheckbox_is_checked(void* cb); +VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text); +VQT6_API void* vqt6_qcheckbox_text(void* cb); +VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate); +VQT6_API int vqt6_qcheckbox_is_tristate(void* cb); + +VQT6_API void* vqt6_qradiobutton_create(void); +VQT6_API void* vqt6_qradiobutton_create_with_text(void* text); +VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked); +VQT6_API int vqt6_qradiobutton_is_checked(void* rb); +VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text); +VQT6_API void* vqt6_qradiobutton_text(void* rb); + +// ============================================================ +// QComboBox +// ============================================================ +VQT6_API void* vqt6_qcombobox_create(void); +VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent); +VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text); +VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items); +VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text); +VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index); +VQT6_API void vqt6_qcombobox_clear(void* cb); +VQT6_API int vqt6_qcombobox_count(void* cb); +VQT6_API int vqt6_qcombobox_current_index(void* cb); +VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index); +VQT6_API void* vqt6_qcombobox_current_text(void* cb); +VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index); +VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable); +VQT6_API int vqt6_qcombobox_is_editable(void* cb); + +// ============================================================ +// QListWidget +// ============================================================ +VQT6_API void* vqt6_qlistwidget_create(void); +VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text); +VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items); +VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text); +VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row); +VQT6_API void vqt6_qlistwidget_clear(void* lw); +VQT6_API int vqt6_qlistwidget_count(void* lw); +VQT6_API int vqt6_qlistwidget_current_row(void* lw); +VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw); +VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row); +VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text); + +// ============================================================ +// QProgressBar +// ============================================================ +VQT6_API void* vqt6_qprogressbar_create(void); +VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent); +VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value); +VQT6_API int vqt6_qprogressbar_value(void* pb); +VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min); +VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max); +VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max); +VQT6_API int vqt6_qprogressbar_minimum(void* pb); +VQT6_API int vqt6_qprogressbar_maximum(void* pb); +VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible); +VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format); +VQT6_API void vqt6_qprogressbar_reset(void* pb); + +// ============================================================ +// QSlider +// ============================================================ +VQT6_API void* vqt6_qslider_create(void); +VQT6_API void* vqt6_qslider_create_with_orientation(int orientation); +VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent); +VQT6_API void vqt6_qslider_set_value(void* s, int value); +VQT6_API int vqt6_qslider_value(void* s); +VQT6_API void vqt6_qslider_set_minimum(void* s, int min); +VQT6_API void vqt6_qslider_set_maximum(void* s, int max); +VQT6_API void vqt6_qslider_set_range(void* s, int min, int max); +VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation); +VQT6_API int vqt6_qslider_orientation(void* s); +VQT6_API void vqt6_qslider_set_single_step(void* s, int step); +VQT6_API void vqt6_qslider_set_page_step(void* s, int step); + +// ============================================================ +// QSpinBox +// ============================================================ +VQT6_API void* vqt6_qspinbox_create(void); +VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent); +VQT6_API int vqt6_qspinbox_value(void* sb); +VQT6_API void vqt6_qspinbox_set_value(void* sb, int value); +VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min); +VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max); +VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max); +VQT6_API int vqt6_qspinbox_minimum(void* sb); +VQT6_API int vqt6_qspinbox_maximum(void* sb); +VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step); +VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix); +VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix); +VQT6_API void* vqt6_qspinbox_prefix(void* sb); +VQT6_API void* vqt6_qspinbox_suffix(void* sb); + +// ============================================================ +// Layouts +// ============================================================ +VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget); +VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget); +VQT6_API int vqt6_qlayout_count(void* layout); +VQT6_API void* vqt6_qlayout_item_at(void* layout, int index); +VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom); +VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing); +VQT6_API int vqt6_qlayout_spacing(void* layout); +VQT6_API void vqt6_qlayout_invalidate(void* layout); + +VQT6_API void* vqt6_qhboxlayout_create(void); +VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qvboxlayout_create(void); +VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qgridlayout_create(void); +VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col); +VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span); + +VQT6_API void* vqt6_qformlayout_create(void); +VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field); +VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field); + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +VQT6_API void* vqt6_qstackedwidget_create(void); +VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w); +VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w); +VQT6_API int vqt6_qstackedwidget_count(void* sw); +VQT6_API int vqt6_qstackedwidget_current_index(void* sw); +VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index); +VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw); +VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index); + +VQT6_API void* vqt6_qtabwidget_create(void); +VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label); +VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label); +VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index); +VQT6_API int vqt6_qtabwidget_count(void* tw); +VQT6_API int vqt6_qtabwidget_current_index(void* tw); +VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index); +VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index); +VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text); +VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable); +VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw); + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +VQT6_API void* vqt6_qmenubar_create(void); +VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent); +VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title); +VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu); +VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action); +VQT6_API void vqt6_qmenubar_clear(void* mb); + +VQT6_API void* vqt6_qmenu_create(void); +VQT6_API void* vqt6_qmenu_create_with_title(void* title); +VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent); +VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title); +VQT6_API void vqt6_qmenu_add_action(void* menu, void* action); +VQT6_API void vqt6_qmenu_add_separator(void* menu); +VQT6_API void vqt6_qmenu_clear(void* menu); +VQT6_API void vqt6_qmenu_set_title(void* menu, void* title); +VQT6_API void* vqt6_qmenu_title(void* menu); +VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text); + +VQT6_API void* vqt6_qaction_create(void); +VQT6_API void* vqt6_qaction_create_with_text(void* text); +VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qaction_set_text(void* action, void* text); +VQT6_API void* vqt6_qaction_text(void* action); +VQT6_API void vqt6_qaction_set_icon(void* action, void* icon); +VQT6_API void* vqt6_qaction_icon(void* action); +VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence); +VQT6_API void* vqt6_qaction_shortcut(void* action); +VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable); +VQT6_API int vqt6_qaction_is_checkable(void* action); +VQT6_API void vqt6_qaction_set_checked(void* action, int checked); +VQT6_API int vqt6_qaction_is_checked(void* action); +VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled); +VQT6_API int vqt6_qaction_is_enabled(void* action); +VQT6_API void vqt6_qaction_trigger(void* action); + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +VQT6_API void* vqt6_qstatusbar_create(void); +VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent); +VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms); +VQT6_API void vqt6_qstatusbar_clear_message(void* sb); +VQT6_API void* vqt6_qstatusbar_current_message(void* sb); +VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch); +VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch); + +VQT6_API void* vqt6_qtoolbar_create(void); +VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent); +VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w); +VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action); +VQT6_API void vqt6_qtoolbar_add_separator(void* tb); +VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h); +VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation); +VQT6_API int vqt6_qtoolbar_orientation(void* tb); + +// ============================================================ +// QMessageBox +// ============================================================ +VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons); +VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text); +VQT6_API void vqt6_qmessagebox_about_qt(void* parent); + +// ============================================================ +// QFileDialog +// ============================================================ +VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir); +VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_WIDGETS_H diff --git a/vqt6/_qtcore.vp b/vqt6/_qtcore.vp new file mode 100644 index 0000000..ddb7035 --- /dev/null +++ b/vqt6/_qtcore.vp @@ -0,0 +1,157 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtcore.py — QtCore 的 t.State FFI 声明 +# +# 所有函数都是 C 桥接层 (libvqt6_bridge.a) 的 extern "C" 函数 +# 命名规范: vqt6__ +# ============================================================ + +# ============================================================ +# QString — UTF-16 字符串 +# ============================================================ +# 创建 QString(从 UTF-8 C 字符串) +def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass + +# 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0) +# buf 需足够大(建议 4 * qstring.length() + 1) +def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass + +# 释放 QString +def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass + +# 获取 QString 字符数 +def vqt6_qstring_length(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 是否为空 +def vqt6_qstring_is_empty(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 比较 +def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.State: pass + +# QString 拼接(返回新 QString) +def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QByteArray — 字节数组 +# ============================================================ +def vqt6_qbytearray_create(data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass +def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass + + +# ============================================================ +# QObject — 所有 Qt 对象的基类 +# ============================================================ +# 注意: Qt 对象的内存由 C++ 管理,Viper 端不应直接 free +def vqt6_qobject_delete(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_delete_later(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_set_object_name(obj: QtObjectPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qobject_object_name(obj: QtObjectPtr) -> QtStringPtr | t.State: pass +def vqt6_qobject_set_parent(child: QtObjectPtr, parent: QtObjectPtr) -> t.State: pass +def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass + +# 信号/槽连接 (简化版: 函数指针形式) +# typedef void (*vqt6_callback_t)(void* user_data); +# vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理 +# 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表 +def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +# 事件过滤器 +def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass +def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QCoreApplication — 事件循环基类 +# ============================================================ +def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_exit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_process_events(app: QtCoreAppPtr, flags: t.CInt) -> t.State: pass +def vqt6_qcoreapp_post_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.State: pass +def vqt6_qcoreapp_send_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_organization_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_organization_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qcoreapp_application_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_application_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QTimer — 定时器 +# ============================================================ +def vqt6_qtimer_create() -> QtTimerPtr | t.State: pass +def vqt6_qtimer_create_with_parent(parent: QtObjectPtr) -> QtTimerPtr | t.State: pass +def vqt6_qtimer_start(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_stop(timer: QtTimerPtr) -> t.State: pass +def vqt6_qtimer_set_interval(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_interval(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_is_active(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_set_single_shot(timer: QtTimerPtr, single_shot: t.CInt) -> t.State: pass +def vqt6_qtimer_is_single_shot(timer: QtTimerPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QVariant — 通用数据容器 +# ============================================================ +def vqt6_qvariant_create_int(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_double(value: t.CDouble) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_bool(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_string(s: QtStringPtr) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_to_int(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_double(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qvariant_to_bool(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_string(v: QtVariantPtr) -> QtStringPtr | t.State: pass +def vqt6_qvariant_type_id(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_is_valid(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_free(v: QtVariantPtr) -> t.State: pass + + +# ============================================================ +# QEvent — 事件基类 +# ============================================================ +def vqt6_qevent_type(event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qevent_accept(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_ignore(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_is_accepted(event: QtEventPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 字符串列表 (QStringList / QList) +# ============================================================ +def vqt6_qstringlist_create() -> QtStringListPtr | t.State: pass +def vqt6_qstringlist_append(list: QtStringListPtr, str: QtStringPtr) -> t.State: pass +def vqt6_qstringlist_size(list: QtStringListPtr) -> t.CInt | t.State: pass +def vqt6_qstringlist_at(list: QtStringListPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qstringlist_free(list: QtStringListPtr) -> t.State: pass + + +# ============================================================ +# 字节数组列表 (QList) +# ============================================================ +def vqt6_qbytearraylist_create() -> QtByteArrayListPtr | t.State: pass +def vqt6_qbytearraylist_append(list: QtByteArrayListPtr, qba: QtByteArrayPtr) -> t.State: pass +def vqt6_qbytearraylist_size(list: QtByteArrayListPtr) -> t.CInt | t.State: pass +def vqt6_qbytearraylist_at(list: QtByteArrayListPtr, index: t.CInt) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearraylist_free(list: QtByteArrayListPtr) -> t.State: pass + + +# ============================================================ +# 全局回调注册表 +# ============================================================ +# 用于从 C++ 端回调 Viper 代码 +# Viper 注册一个 slot 函数(用整数 ID 标识),C++ 在触发信号时通过 ID 查找 +# typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +def vqt6_register_slot(slot_id: t.CInt, user_data: t.CVoid | t.CPtr) -> t.State: pass +def vqt6_unregister_slot(slot_id: t.CInt) -> t.State: pass +def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用 diff --git a/vqt6/_qtgui.vp b/vqt6/_qtgui.vp new file mode 100644 index 0000000..80f0094 --- /dev/null +++ b/vqt6/_qtgui.vp @@ -0,0 +1,237 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtgui.py — QtGui 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QColor — 颜色 +# ============================================================ +def vqt6_qcolor_create_rgb(r: t.CInt, g: t.CInt, b: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_rgba(r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_name(name: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_hex(hex_str: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_red(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_green(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_blue(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_alpha(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_set_red(c: QtColorPtr, r: t.CInt) -> t.State: pass +def vqt6_qcolor_set_green(c: QtColorPtr, g: t.CInt) -> t.State: pass +def vqt6_qcolor_set_blue(c: QtColorPtr, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_alpha(c: QtColorPtr, a: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgb(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgba(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> t.State: pass +def vqt6_qcolor_name(c: QtColorPtr) -> QtStringPtr | t.State: pass +def vqt6_qcolor_is_valid(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_free(c: QtColorPtr) -> t.State: pass + + +# ============================================================ +# QFont — 字体 +# ============================================================ +def vqt6_qfont_create() -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family(family: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family_size(family: QtStringPtr, point_size: t.CInt) -> QtFontPtr | t.State: pass +def vqt6_qfont_set_family(font: QtFontPtr, family: QtStringPtr) -> t.State: pass +def vqt6_qfont_family(font: QtFontPtr) -> QtStringPtr | t.State: pass +def vqt6_qfont_set_point_size(font: QtFontPtr, point_size: t.CInt) -> t.State: pass +def vqt6_qfont_point_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_pixel_size(font: QtFontPtr, pixel_size: t.CInt) -> t.State: pass +def vqt6_qfont_pixel_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_bold(font: QtFontPtr, bold: t.CInt) -> t.State: pass +def vqt6_qfont_bold(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_italic(font: QtFontPtr, italic: t.CInt) -> t.State: pass +def vqt6_qfont_italic(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_underline(font: QtFontPtr, underline: t.CInt) -> t.State: pass +def vqt6_qfont_underline(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_strike_out(font: QtFontPtr, strike_out: t.CInt) -> t.State: pass +def vqt6_qfont_strike_out(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_weight(font: QtFontPtr, weight: t.CInt) -> t.State: pass +def vqt6_qfont_weight(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_free(font: QtFontPtr) -> t.State: pass + + +# ============================================================ +# QFontMetrics — 字体度量 +# ============================================================ +def vqt6_qfontmetrics_create(font: QtFontPtr) -> QtFontMetricsPtr | t.State: pass +def vqt6_qfontmetrics_width(fm: QtFontMetricsPtr, text: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_height(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_ascent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_descent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_free(fm: QtFontMetricsPtr) -> t.State: pass + + +# ============================================================ +# QPixmap — 像素图 +# ============================================================ +def vqt6_qpixmap_create() -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_create_with_size(w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_load(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_load_from_data(pm: QtPixmapPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CInt | t.State: pass +def vqt6_qpixmap_save(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_width(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_height(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_is_null(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_scaled(pm: QtPixmapPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_fill(pm: QtPixmapPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpixmap_free(pm: QtPixmapPtr) -> t.State: pass + + +# ============================================================ +# QImage — 图像 +# ============================================================ +def vqt6_qimage_create() -> QtImagePtr | t.State: pass +def vqt6_qimage_create_with_size(w: t.CInt, h: t.CInt, format: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_load(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_save(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_width(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_height(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_format(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_is_null(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_fill(img: QtImagePtr, color: QtColorPtr) -> t.State: pass +def vqt6_qimage_scaled(img: QtImagePtr, w: t.CInt, h: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_free(img: QtImagePtr) -> t.State: pass + + +# ============================================================ +# QPainter — 绘画器 +# ============================================================ +def vqt6_qpainter_create() -> QtPainterPtr | t.State: pass +def vqt6_qpainter_begin(p: QtPainterPtr, device: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_end(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_is_active(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_set_pen(p: QtPainterPtr, pen: QtPenPtr) -> t.State: pass +def vqt6_qpainter_set_brush(p: QtPainterPtr, brush: QtBrushPtr) -> t.State: pass +def vqt6_qpainter_set_font(p: QtPainterPtr, font: QtFontPtr) -> t.State: pass +def vqt6_qpainter_pen(p: QtPainterPtr) -> QtPenPtr | t.State: pass +def vqt6_qpainter_brush(p: QtPainterPtr) -> QtBrushPtr | t.State: pass +def vqt6_qpainter_font(p: QtPainterPtr) -> QtFontPtr | t.State: pass +def vqt6_qpainter_set_opacity(p: QtPainterPtr, opacity: t.CDouble) -> t.State: pass +def vqt6_qpainter_opacity(p: QtPainterPtr) -> t.CDouble | t.State: pass + +# 绘图原语 +def vqt6_qpainter_draw_line(p: QtPainterPtr, x1: t.CInt, y1: t.CInt, x2: t.CInt, y2: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_fill_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, color: QtColorPtr) -> t.State: pass +def vqt6_qpainter_draw_ellipse(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_arc(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_chord(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_pie(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polygon(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polyline(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_point(p: QtPainterPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_points(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_text(p: QtPainterPtr, x: t.CInt, y: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_text_in_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, flags: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qpainter_draw_image(p: QtPainterPtr, x: t.CInt, y: t.CInt, image: QtImagePtr) -> t.State: pass +def vqt6_qpainter_draw_tiled_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass + +# 变换 +def vqt6_qpainter_translate(p: QtPainterPtr, dx: t.CInt, dy: t.CInt) -> t.State: pass +def vqt6_qpainter_rotate(p: QtPainterPtr, angle: t.CDouble) -> t.State: pass +def vqt6_qpainter_scale(p: QtPainterPtr, sx: t.CDouble, sy: t.CDouble) -> t.State: pass +def vqt6_qpainter_reset_transform(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_save(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_restore(p: QtPainterPtr) -> t.State: pass + +def vqt6_qpainter_free(p: QtPainterPtr) -> t.State: pass + + +# ============================================================ +# QPen — 画笔 +# ============================================================ +def vqt6_qpen_create() -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color(color: QtColorPtr) -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color_width(color: QtColorPtr, width: t.CInt) -> QtPenPtr | t.State: pass +def vqt6_qpen_set_color(pen: QtPenPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpen_color(pen: QtPenPtr) -> QtColorPtr | t.State: pass +def vqt6_qpen_set_width(pen: QtPenPtr, width: t.CInt) -> t.State: pass +def vqt6_qpen_width(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_set_style(pen: QtPenPtr, style: t.CInt) -> t.State: pass +def vqt6_qpen_style(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_free(pen: QtPenPtr) -> t.State: pass + + +# ============================================================ +# QBrush — 画刷 +# ============================================================ +def vqt6_qbrush_create() -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_color(color: QtColorPtr) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_style(style: t.CInt) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_set_color(brush: QtBrushPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qbrush_color(brush: QtBrushPtr) -> QtColorPtr | t.State: pass +def vqt6_qbrush_set_style(brush: QtBrushPtr, style: t.CInt) -> t.State: pass +def vqt6_qbrush_style(brush: QtBrushPtr) -> t.CInt | t.State: pass +def vqt6_qbrush_free(brush: QtBrushPtr) -> t.State: pass + + +# ============================================================ +# QIcon — 图标 +# ============================================================ +def vqt6_qicon_create() -> QtIconPtr | t.State: pass +def vqt6_qicon_create_with_file(file_name: QtStringPtr) -> QtIconPtr | t.State: pass +def vqt6_qicon_add_file(icon: QtIconPtr, file_name: QtStringPtr) -> t.State: pass +def vqt6_qicon_add_pixmap(icon: QtIconPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qicon_is_null(icon: QtIconPtr) -> t.CInt | t.State: pass +def vqt6_qicon_pixmap(icon: QtIconPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qicon_free(icon: QtIconPtr) -> t.State: pass + + +# ============================================================ +# QCursor — 鼠标光标 +# ============================================================ +def vqt6_qcursor_create() -> QtCursorPtr | t.State: pass +def vqt6_qcursor_create_with_shape(shape: t.CInt) -> QtCursorPtr | t.State: pass +def vqt6_qcursor_pos(x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qcursor_set_pos(x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qcursor_set_shape(cursor: QtCursorPtr, shape: t.CInt) -> t.State: pass +def vqt6_qcursor_shape(cursor: QtCursorPtr) -> t.CInt | t.State: pass +def vqt6_qcursor_free(cursor: QtCursorPtr) -> t.State: pass + + +# ============================================================ +# QKeyEvent — 键盘事件 +# ============================================================ +def vqt6_qkeyevent_create(type: t.CInt, key: t.CInt, modifiers: t.CInt, text: QtStringPtr) -> QtKeyEventPtr | t.State: pass +def vqt6_qkeyevent_key(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_text(event: QtKeyEventPtr) -> QtStringPtr | t.State: pass +def vqt6_qkeyevent_modifiers(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_is_auto_repeat(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_free(event: QtKeyEventPtr) -> t.State: pass + + +# ============================================================ +# QMouseEvent — 鼠标事件 +# ============================================================ +def vqt6_qmouseevent_create(type: t.CInt, local_pos: QtObjectPtr, button: t.CInt, buttons: t.CInt, modifiers: t.CInt) -> QtMouseEventPtr | t.State: pass +def vqt6_qmouseevent_button(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_buttons(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_modifiers(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_free(event: QtMouseEventPtr) -> t.State: pass + + +# ============================================================ +# QResizeEvent / QPaintEvent / QCloseEvent +# ============================================================ +def vqt6_qresizeevent_create(width: t.CInt, height: t.CInt, old_width: t.CInt, old_height: t.CInt) -> QtResizeEventPtr | t.State: pass +def vqt6_qresizeevent_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_old_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_free(event: QtResizeEventPtr) -> t.State: pass + +def vqt6_qpaintevent_create(rect_x: t.CInt, rect_y: t.CInt, rect_w: t.CInt, rect_h: t.CInt) -> QtPaintEventPtr | t.State: pass +def vqt6_qpaintevent_rect(event: QtPaintEventPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qpaintevent_free(event: QtPaintEventPtr) -> t.State: pass + +def vqt6_qcloseevent_create() -> QtCloseEventPtr | t.State: pass +def vqt6_qcloseevent_is_accepted(event: QtCloseEventPtr) -> t.CInt | t.State: pass +def vqt6_qcloseevent_accept(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_ignore(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_free(event: QtCloseEventPtr) -> t.State: pass diff --git a/vqt6/_qtnetwork.vp b/vqt6/_qtnetwork.vp new file mode 100644 index 0000000..6859d8b --- /dev/null +++ b/vqt6/_qtnetwork.vp @@ -0,0 +1,184 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtnetwork.py — QtNetwork 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QHostAddress — IP 地址 +# ============================================================ +def vqt6_qhostaddress_create() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_ipv4(ipv4: t.CUInt32T) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_string(address: QtStringPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_host() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_broadcast() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_any_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_to_string(addr: QtHostAddressPtr) -> QtStringPtr | t.State: pass +def vqt6_qhostaddress_to_ipv4(addr: QtHostAddressPtr) -> t.CUInt32T | t.State: pass +def vqt6_qhostaddress_is_null(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_loopback(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_broadcast(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_protocol(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_free(addr: QtHostAddressPtr) -> t.State: pass + + +# ============================================================ +# QAbstractSocket — TCP/UDP 套接字基类 +# ============================================================ +# 套接字状态 +QT_SOCKET_UNCONNECTED_STATE: t.CDefine = 0 +QT_SOCKET_HOST_LOOKUP_STATE: t.CDefine = 1 +QT_SOCKET_CONNECTING_STATE: t.CDefine = 2 +QT_SOCKET_CONNECTED_STATE: t.CDefine = 3 +QT_SOCKET_BOUND_STATE: t.CDefine = 4 +QT_SOCKET_LISTENING_STATE: t.CDefine = 5 +QT_SOCKET_CLOSING_STATE: t.CDefine = 6 + +# 套接字类型 +QT_SOCKET_TCP: t.CDefine = 0 +QT_SOCKET_UDP: t.CDefine = 1 + +# 套接字错误 +QT_SOCKET_NO_ERROR: t.CDefine = 0 + +# 通用方法 +def vqt6_qabstractsocket_state(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error_string(socket: QtAbstractSocketPtr) -> QtStringPtr | t.State: pass +def vqt6_qabstractsocket_connect_to_host(socket: QtAbstractSocketPtr, host_name: QtStringPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_connect_to_host_with_addr(socket: QtAbstractSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_disconnect_from_host(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_wait_for_connected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_ready_read(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_bytes_written(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_disconnected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_valid(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_open(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_flush(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_close(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_abort(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_read(socket: QtAbstractSocketPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_read_all(socket: QtAbstractSocketPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qabstractsocket_write(socket: QtAbstractSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_available(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_to_write(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_peer_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_peer_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass +def vqt6_qabstractsocket_local_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_local_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass + + +# ============================================================ +# QTcpSocket — TCP 套接字 +# ============================================================ +def vqt6_qtcpsocket_create() -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_create_with_parent(parent: QtObjectPtr) -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_connect_to_host(socket: QtTcpSocketPtr, host_name: QtStringPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_connect_to_host_with_addr(socket: QtTcpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_set_socket_descriptor(socket: QtTcpSocketPtr, socket_descriptor: t.CInt) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_socket_descriptor(socket: QtTcpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_set_proxy(socket: QtTcpSocketPtr, proxy_type: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_abort(socket: QtTcpSocketPtr) -> t.State: pass + + +# ============================================================ +# QUdpSocket — UDP 套接字 +# ============================================================ +def vqt6_qudpsocket_create() -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_create_with_parent(parent: QtObjectPtr) -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_bind(socket: QtUdpSocketPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_bind_with_addr(socket: QtUdpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_close(socket: QtUdpSocketPtr) -> t.State: pass +def vqt6_qudpsocket_write_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_read_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, max_size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T | t.CPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_has_pending_datagrams(socket: QtUdpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_pending_datagram_size(socket: QtUdpSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_join_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_leave_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QNetworkRequest — 网络请求 +# ============================================================ +def vqt6_qnetworkrequest_create() -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_create_with_url(url: QtStringPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_set_url(req: QtNetworkRequestPtr, url: QtStringPtr) -> t.State: pass +def vqt6_qnetworkrequest_url(req: QtNetworkRequestPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkrequest_set_header(req: QtNetworkRequestPtr, header_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_header(req: QtNetworkRequestPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_set_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass +def vqt6_qnetworkrequest_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkrequest_set_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_free(req: QtNetworkRequestPtr) -> t.State: pass + + +# ============================================================ +# QNetworkAccessManager — HTTP 客户端管理器 +# ============================================================ +def vqt6_qnetworkaccessmanager_create() -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_create_with_parent(parent: QtObjectPtr) -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_get(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_post(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_put(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_delete_resource(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_head(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_set_cookie_store(nam: QtNetworkAccessManagerPtr, store: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QNetworkReply — 网络响应 +# ============================================================ +def vqt6_qnetworkreply_url(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_request(reply: QtNetworkReplyPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkreply_error(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_error_string(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_is_finished(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_is_running(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_abort(reply: QtNetworkReplyPtr) -> t.State: pass +def vqt6_qnetworkreply_read(reply: QtNetworkReplyPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_read_all(reply: QtNetworkReplyPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_bytes_available(reply: QtNetworkReplyPtr) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_header(reply: QtNetworkReplyPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_attribute(reply: QtNetworkReplyPtr, attribute_code: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_attribute_int(reply: QtNetworkReplyPtr, attribute_code: t.CInt, default_value: t.CInt) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_set_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass + + +# ============================================================ +# 套接字类型枚举 +# ============================================================ +# 套接字类型 +QT_ABSTRACT_SOCKET_TCP: t.CDefine = 0 +QT_ABSTRACT_SOCKET_UDP: t.CDefine = 1 + +# 网络层协议 +QT_NETWORK_IPV4_PROTOCOL: t.CDefine = 0 +QT_NETWORK_IPV6_PROTOCOL: t.CDefine = 1 +QT_NETWORK_ANY_IP_PROTOCOL: t.CDefine = 2 + +# 主机地址特殊情况 +QT_HOST_ADDRESS_LOCAL_HOST: t.CDefine = 0x00000000 +QT_HOST_ADDRESS_LOCAL_HOST_IPV6: t.CDefine = 0x00000001 +QT_HOST_ADDRESS_BROADCAST: t.CDefine = 0x00000002 +QT_HOST_ADDRESS_ANY_IPV4: t.CDefine = 0x00000004 +QT_HOST_ADDRESS_ANY_IPV6: t.CDefine = 0x00000005 + + +# ============================================================ +# 已知端口常量 +# ============================================================ +QT_PORT_FTP: t.CDefine = 21 +QT_PORT_SSH: t.CDefine = 22 +QT_PORT_TELNET: t.CDefine = 23 +QT_PORT_SMTP: t.CDefine = 25 +QT_PORT_DNS: t.CDefine = 53 +QT_PORT_HTTP: t.CDefine = 80 +QT_PORT_POP3: t.CDefine = 110 +QT_PORT_IMAP: t.CDefine = 143 +QT_PORT_HTTPS: t.CDefine = 443 +QT_PORT_SMB: t.CDefine = 445 diff --git a/vqt6/_qtwidgets.vp b/vqt6/_qtwidgets.vp new file mode 100644 index 0000000..025d026 --- /dev/null +++ b/vqt6/_qtwidgets.vp @@ -0,0 +1,478 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtwidgets.py — QtWidgets 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QApplication — GUI 应用入口 +# ============================================================ +# argc/argv 通过单独的 buffer 数组传入(Viper 中 C 数组使用指针+长度) +def vqt6_qapplication_create(argc: t.CInt, argv: t.CPtr | t.CPtr) -> QtAppPtr | t.State: pass +def vqt6_qapplication_instance() -> QtAppPtr | t.State: pass +def vqt6_qapplication_exec(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_quit(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_exit(app: QtAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qapplication_process_events(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_desktop_width(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_desktop_height(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_set_quit_on_last_window_closed(app: QtAppPtr, quit: t.CInt) -> t.State: pass +def vqt6_qapplication_quit_on_last_window_closed(app: QtAppPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QWidget — 所有窗口的基类 +# ============================================================ +def vqt6_qwidget_create() -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_create_with_parent(parent: QtWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_show(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_hide(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_close(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_is_visible(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_visible(widget: QtWidgetPtr, visible: t.CInt) -> t.State: pass + +# 几何 +def vqt6_qwidget_set_geometry(widget: QtWidgetPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_geometry(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_resize(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_move(widget: QtWidgetPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qwidget_pos(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_width(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_height(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_x(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_y(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 文本与标题 +def vqt6_qwidget_set_window_title(widget: QtWidgetPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qwidget_window_title(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qwidget_set_text(widget: QtWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qwidget_text(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 启用 +def vqt6_qwidget_set_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qwidget_is_enabled(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 父对象 +def vqt6_qwidget_set_parent(widget: QtWidgetPtr, parent: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_parent_widget(widget: QtWidgetPtr) -> QtWidgetPtr | t.State: pass + +# 焦点 +def vqt6_qwidget_set_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_clear_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_has_focus(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_focus_policy(widget: QtWidgetPtr, policy: t.CInt) -> t.State: pass + +# 更新 +def vqt6_qwidget_update(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_repaint(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_set_update_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass + +# 窗口标志 +def vqt6_qwidget_set_window_flags(widget: QtWidgetPtr, flags: t.CInt) -> t.State: pass +def vqt6_qwidget_window_flags(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 鼠标光标 +def vqt6_qwidget_set_cursor(widget: QtWidgetPtr, cursor: QtCursorPtr) -> t.State: pass +def vqt6_qwidget_cursor(widget: QtWidgetPtr) -> QtCursorPtr | t.State: pass +def vqt6_qwidget_unset_cursor(widget: QtWidgetPtr) -> t.State: pass + +# 工具提示 +def vqt6_qwidget_set_tool_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_tool_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 状态栏提示 +def vqt6_qwidget_set_status_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_status_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 最小/最大尺寸 +def vqt6_qwidget_set_minimum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_maximum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_fixed_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_minimum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_maximum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass + + +# ============================================================ +# QDialog — 对话框 +# ============================================================ +def vqt6_qdialog_create() -> QtDialogPtr | t.State: pass +def vqt6_qdialog_create_with_parent(parent: QtWidgetPtr) -> QtDialogPtr | t.State: pass +def vqt6_qdialog_exec(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_done(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_accept(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_reject(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_set_result(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_result(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_set_modal(dialog: QtDialogPtr, modal: t.CInt) -> t.State: pass +def vqt6_qdialog_is_modal(dialog: QtDialogPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMainWindow — 主窗口 +# ============================================================ +def vqt6_qmainwindow_create() -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_create_with_parent(parent: QtWidgetPtr) -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_set_central_widget(mw: QtMainWindowPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qmainwindow_central_widget(mw: QtMainWindowPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qmainwindow_menu_bar(mw: QtMainWindowPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmainwindow_set_menu_bar(mw: QtMainWindowPtr, menubar: QtMenuBarPtr) -> t.State: pass +def vqt6_qmainwindow_status_bar(mw: QtMainWindowPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qmainwindow_set_status_bar(mw: QtMainWindowPtr, statusbar: QtStatusBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar(mw: QtMainWindowPtr, toolbar: QtToolBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar_break(mw: QtMainWindowPtr) -> t.State: pass + + +# ============================================================ +# QLabel — 标签 +# ============================================================ +def vqt6_qlabel_create() -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text(text: QtStringPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_set_text(label: QtLabelPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlabel_text(label: QtLabelPtr) -> QtStringPtr | t.State: pass +def vqt6_qlabel_set_alignment(label: QtLabelPtr, alignment: t.CInt) -> t.State: pass +def vqt6_qlabel_alignment(label: QtLabelPtr) -> t.CInt | t.State: pass +def vqt6_qlabel_set_pixmap(label: QtLabelPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qlabel_pixmap(label: QtLabelPtr) -> QtPixmapPtr | t.State: pass +def vqt6_qlabel_set_indent(label: QtLabelPtr, indent: t.CInt) -> t.State: pass +def vqt6_qlabel_set_margin(label: QtLabelPtr, margin: t.CInt) -> t.State: pass +def vqt6_qlabel_set_word_wrap(label: QtLabelPtr, wrap: t.CInt) -> t.State: pass +def vqt6_qlabel_word_wrap(label: QtLabelPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QPushButton — 按钮 +# ============================================================ +def vqt6_qpushbutton_create() -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text(text: QtStringPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_set_text(btn: QtPushButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qpushbutton_text(btn: QtPushButtonPtr) -> QtStringPtr | t.State: pass +def vqt6_qpushbutton_set_icon(btn: QtPushButtonPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qpushbutton_icon(btn: QtPushButtonPtr) -> QtIconPtr | t.State: pass +def vqt6_qpushbutton_set_default(btn: QtPushButtonPtr, is_default: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_default(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_flat(btn: QtPushButtonPtr, flat: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_flat(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checkable(btn: QtPushButtonPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checkable(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checked(btn: QtPushButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checked(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_click(btn: QtPushButtonPtr) -> t.State: pass + + +# ============================================================ +# QLineEdit — 单行输入框 +# ============================================================ +def vqt6_qlineedit_create() -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text(text: QtStringPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_placeholder_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_placeholder_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_set_max_length(le: QtLineEditPtr, max: t.CInt) -> t.State: pass +def vqt6_qlineedit_max_length(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_read_only(le: QtLineEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qlineedit_is_read_only(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_echo_mode(le: QtLineEditPtr, mode: t.CInt) -> t.State: pass +def vqt6_qlineedit_echo_mode(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_select_all(le: QtLineEditPtr) -> t.State: pass +def vqt6_qlineedit_clear(le: QtLineEditPtr) -> t.State: pass + + +# ============================================================ +# QTextEdit / QPlainTextEdit — 多行文本编辑器 +# ============================================================ +def vqt6_qtextedit_create() -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_create_with_parent(parent: QtWidgetPtr) -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_to_plain_text(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_set_plain_text(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_set_html(te: QtTextEditPtr, html: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_to_html(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_append(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_clear(te: QtTextEditPtr) -> t.State: pass +def vqt6_qtextedit_set_read_only(te: QtTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qtextedit_is_read_only(te: QtTextEditPtr) -> t.CInt | t.State: pass + +def vqt6_qplaintextedit_create() -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_create_with_parent(parent: QtWidgetPtr) -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_to_plain_text(pte: QtPlainTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qplaintextedit_set_plain_text(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_append(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_clear(pte: QtPlainTextEditPtr) -> t.State: pass +def vqt6_qplaintextedit_set_read_only(pte: QtPlainTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qplaintextedit_line_count(pte: QtPlainTextEditPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QCheckBox / QRadioButton — 复选/单选 +# ============================================================ +def vqt6_qcheckbox_create() -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text(text: QtStringPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_set_checked(cb: QtCheckBoxPtr, checked: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_checked(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcheckbox_set_text(cb: QtCheckBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcheckbox_text(cb: QtCheckBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcheckbox_set_tristate(cb: QtCheckBoxPtr, tristate: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_tristate(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass + +def vqt6_qradiobutton_create() -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text(text: QtStringPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_set_checked(rb: QtRadioButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qradiobutton_is_checked(rb: QtRadioButtonPtr) -> t.CInt | t.State: pass +def vqt6_qradiobutton_set_text(rb: QtRadioButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qradiobutton_text(rb: QtRadioButtonPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QComboBox — 下拉框 +# ============================================================ +def vqt6_qcombobox_create() -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_create_with_parent(parent: QtWidgetPtr) -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_add_item(cb: QtComboBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_add_items(cb: QtComboBoxPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qcombobox_insert_item(cb: QtComboBoxPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_remove_item(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_clear(cb: QtComboBoxPtr) -> t.State: pass +def vqt6_qcombobox_count(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_current_index(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_set_current_index(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_current_text(cb: QtComboBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_item_text(cb: QtComboBoxPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_set_editable(cb: QtComboBoxPtr, editable: t.CInt) -> t.State: pass +def vqt6_qcombobox_is_editable(cb: QtComboBoxPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QListWidget — 列表控件 +# ============================================================ +def vqt6_qlistwidget_create() -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_create_with_parent(parent: QtWidgetPtr) -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_add_item(lw: QtListWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_add_items(lw: QtListWidgetPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qlistwidget_insert_item(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_remove_item_widget(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_take_item(lw: QtListWidgetPtr, row: t.CInt) -> QtListWidgetItemPtr | t.State: pass +def vqt6_qlistwidget_clear(lw: QtListWidgetPtr) -> t.State: pass +def vqt6_qlistwidget_count(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_current_row(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_set_current_row(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_current_item_text(lw: QtListWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_item_text(lw: QtListWidgetPtr, row: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_set_item_text(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QProgressBar — 进度条 +# ============================================================ +def vqt6_qprogressbar_create() -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_create_with_parent(parent: QtWidgetPtr) -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_set_value(pb: QtProgressBarPtr, value: t.CInt) -> t.State: pass +def vqt6_qprogressbar_value(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_minimum(pb: QtProgressBarPtr, min: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_maximum(pb: QtProgressBarPtr, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_range(pb: QtProgressBarPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_minimum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_maximum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_text_visible(pb: QtProgressBarPtr, visible: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_format(pb: QtProgressBarPtr, format: QtStringPtr) -> t.State: pass +def vqt6_qprogressbar_reset(pb: QtProgressBarPtr) -> t.State: pass + + +# ============================================================ +# QSlider — 滑块 +# ============================================================ +def vqt6_qslider_create() -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation(orientation: t.CInt) -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation_parent(orientation: t.CInt, parent: QtWidgetPtr) -> QtSliderPtr | t.State: pass +def vqt6_qslider_set_value(s: QtSliderPtr, value: t.CInt) -> t.State: pass +def vqt6_qslider_value(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_minimum(s: QtSliderPtr, min: t.CInt) -> t.State: pass +def vqt6_qslider_set_maximum(s: QtSliderPtr, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_range(s: QtSliderPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_orientation(s: QtSliderPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qslider_orientation(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_single_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass +def vqt6_qslider_set_page_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass + + +# ============================================================ +# QSpinBox — 数字输入框 +# ============================================================ +def vqt6_qspinbox_create() -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_create_with_parent(parent: QtWidgetPtr) -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_value(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_value(sb: QtSpinBoxPtr, value: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_minimum(sb: QtSpinBoxPtr, min: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_maximum(sb: QtSpinBoxPtr, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_range(sb: QtSpinBoxPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_minimum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_maximum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_single_step(sb: QtSpinBoxPtr, step: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_prefix(sb: QtSpinBoxPtr, prefix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_set_suffix(sb: QtSpinBoxPtr, suffix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_prefix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qspinbox_suffix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# 布局 - QLayout / QBoxLayout / QGridLayout / QFormLayout +# ============================================================ +def vqt6_qlayout_add_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_remove_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_count(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_item_at(layout: QtLayoutPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass +def vqt6_qlayout_set_contents_margins(layout: QtLayoutPtr, left: t.CInt, top: t.CInt, right: t.CInt, bottom: t.CInt) -> t.State: pass +def vqt6_qlayout_set_spacing(layout: QtLayoutPtr, spacing: t.CInt) -> t.State: pass +def vqt6_qlayout_spacing(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_invalidate(layout: QtLayoutPtr) -> t.State: pass + +# QHBoxLayout +def vqt6_qhboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qhboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qhboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QVBoxLayout +def vqt6_qvboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qvboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qvboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QGridLayout +def vqt6_qgridlayout_create() -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_create_with_parent(parent: QtWidgetPtr) -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_add_widget(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt) -> t.State: pass +def vqt6_qgridlayout_add_widget_with_span(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt, row_span: t.CInt, col_span: t.CInt) -> t.State: pass + +# QFormLayout +def vqt6_qformlayout_create() -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_create_with_parent(parent: QtWidgetPtr) -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_add_row(fl: QtFormLayoutPtr, label: QtStringPtr, field: QtWidgetPtr) -> t.State: pass +def vqt6_qformlayout_add_row_widget_pair(fl: QtFormLayoutPtr, label: QtWidgetPtr, field: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QStackedWidget / QTabWidget +# ============================================================ +def vqt6_qstackedwidget_create() -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_create_with_parent(parent: QtWidgetPtr) -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_add_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_remove_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.State: pass +def vqt6_qstackedwidget_count(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_current_index(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_set_current_index(sw: QtStackedWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qstackedwidget_current_widget(sw: QtStackedWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qstackedwidget_widget(sw: QtStackedWidgetPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass + +def vqt6_qtabwidget_create() -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_create_with_parent(parent: QtWidgetPtr) -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_add_tab(tw: QtTabWidgetPtr, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_insert_tab(tw: QtTabWidgetPtr, index: t.CInt, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_remove_tab(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_count(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_current_index(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_set_current_index(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tab_text(tw: QtTabWidgetPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qtabwidget_set_tab_text(tw: QtTabWidgetPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qtabwidget_set_tabs_closable(tw: QtTabWidgetPtr, closable: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tabs_closable(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMenuBar / QMenu / QAction +# ============================================================ +def vqt6_qmenubar_create() -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_create_with_parent(parent: QtWidgetPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_add_menu(mb: QtMenuBarPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenubar_add_menu_with_menu(mb: QtMenuBarPtr, menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenubar_add_action(mb: QtMenuBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenubar_clear(mb: QtMenuBarPtr) -> t.State: pass + +def vqt6_qmenu_create() -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title(title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title_parent(title: QtStringPtr, parent: QtWidgetPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_menu(menu: QtMenuPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_action(menu: QtMenuPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenu_add_separator(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_clear(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_set_title(menu: QtMenuPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qmenu_title(menu: QtMenuPtr) -> QtStringPtr | t.State: pass +def vqt6_qmenu_add_action_with_text(menu: QtMenuPtr, text: QtStringPtr) -> QtActionPtr | t.State: pass + +def vqt6_qaction_create() -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text(text: QtStringPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_set_text(action: QtActionPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qaction_text(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_icon(action: QtActionPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qaction_icon(action: QtActionPtr) -> QtIconPtr | t.State: pass +def vqt6_qaction_set_shortcut(action: QtActionPtr, key_sequence: QtStringPtr) -> t.State: pass +def vqt6_qaction_shortcut(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_checkable(action: QtActionPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qaction_is_checkable(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_checked(action: QtActionPtr, checked: t.CInt) -> t.State: pass +def vqt6_qaction_is_checked(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_enabled(action: QtActionPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qaction_is_enabled(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_trigger(action: QtActionPtr) -> t.State: pass + + +# ============================================================ +# QStatusBar / QToolBar +# ============================================================ +def vqt6_qstatusbar_create() -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_create_with_parent(parent: QtWidgetPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_show_message(sb: QtStatusBarPtr, message: QtStringPtr, timeout_ms: t.CInt) -> t.State: pass +def vqt6_qstatusbar_clear_message(sb: QtStatusBarPtr) -> t.State: pass +def vqt6_qstatusbar_current_message(sb: QtStatusBarPtr) -> QtStringPtr | t.State: pass +def vqt6_qstatusbar_add_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qstatusbar_add_permanent_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass + +def vqt6_qtoolbar_create() -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_create_with_parent(parent: QtWidgetPtr) -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_add_widget(tb: QtToolBarPtr, w: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qtoolbar_add_action(tb: QtToolBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qtoolbar_add_separator(tb: QtToolBarPtr) -> t.State: pass +def vqt6_qtoolbar_set_icon_size(tb: QtToolBarPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qtoolbar_set_orientation(tb: QtToolBarPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qtoolbar_orientation(tb: QtToolBarPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMessageBox — 消息对话框(静态方法) +# ============================================================ +def vqt6_qmessagebox_information(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_warning(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_critical(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_question(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_about(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qmessagebox_about_qt(parent: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QFileDialog — 文件选择对话框(静态方法) +# ============================================================ +def vqt6_qfiledialog_get_open_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_save_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_existing_directory(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_open_file_names(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringListPtr | t.State: pass + + +# ============================================================ +# QColorDialog / QFontDialog / QInputDialog — 各种对话框 +# ============================================================ +def vqt6_qcolordialog_get_color(initial: QtColorPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qfontdialog_get_font(initial: QtFontPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qinputdialog_get_text(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, echo_mode: t.CInt, text: QtStringPtr, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass +def vqt6_qinputdialog_get_int(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CInt, min_val: t.CInt, max_val: t.CInt, step: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qinputdialog_get_double(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CDouble, min_val: t.CDouble, max_val: t.CDouble, decimals: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qinputdialog_get_item(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, items: QtStringListPtr, current: t.CInt, editable: t.CInt, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass diff --git a/vqt6/_types.vp b/vqt6/_types.vp new file mode 100644 index 0000000..86d1fe5 --- /dev/null +++ b/vqt6/_types.vp @@ -0,0 +1,186 @@ +import t +from stdint import * + +# ============================================================ +# vqt6/_types.py — 公共类型定义 +# +# Qt6 C++ 类在 Viper 端都是不透明指针 (void*) +# 不暴露 C++ 类的内部布局,只暴露指针 +# ============================================================ + +# 不透明指针 typedef(Qt6 C++ 类的 Viper 端表示) +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # void* 通用不透明指针 +QtStringPtr: t.CTypedef = t.CVoid | t.CPtr # QString* +QtByteArrayPtr: t.CTypedef = t.CVoid | t.CPtr # QByteArray* +QtVariantPtr: t.CTypedef = t.CVoid | t.CPtr # QVariant* +QtObjectListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtStringListPtr: t.CTypedef = t.CVoid | t.CPtr # QStringList* +QtByteArrayListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtEventPtr: t.CTypedef = t.CVoid | t.CPtr # QEvent* + +# QtCore +QtCoreAppPtr: t.CTypedef = t.CVoid | t.CPtr # QCoreApplication* +QtTimerPtr: t.CTypedef = t.CVoid | t.CPtr # QTimer* +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # QObject* +QtThreadPtr: t.CTypedef = t.CVoid | t.CPtr # QThread* +QtMutexPtr: t.CTypedef = t.CVoid | t.CPtr # QMutex* +QtWaitConditionPtr: t.CTypedef = t.CVoid | t.CPtr # QWaitCondition* + +# QtGui +QtColorPtr: t.CTypedef = t.CVoid | t.CPtr # QColor* +QtFontPtr: t.CTypedef = t.CVoid | t.CPtr # QFont* +QtFontMetricsPtr: t.CTypedef = t.CVoid | t.CPtr # QFontMetrics* +QtPixmapPtr: t.CTypedef = t.CVoid | t.CPtr # QPixmap* +QtImagePtr: t.CTypedef = t.CVoid | t.CPtr # QImage* +QtPainterPtr: t.CTypedef = t.CVoid | t.CPtr # QPainter* +QtPenPtr: t.CTypedef = t.CVoid | t.CPtr # QPen* +QtBrushPtr: t.CTypedef = t.CVoid | t.CPtr # QBrush* +QtIconPtr: t.CTypedef = t.CVoid | t.CPtr # QIcon* +QtKeyEventPtr: t.CTypedef = t.CVoid | t.CPtr # QKeyEvent* +QtMouseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QMouseEvent* +QtResizeEventPtr: t.CTypedef = t.CVoid | t.CPtr # QResizeEvent* +QtPaintEventPtr: t.CTypedef = t.CVoid | t.CPtr # QPaintEvent* +QtCloseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QCloseEvent* +QtCursorPtr: t.CTypedef = t.CVoid | t.CPtr # QCursor* + +# QtWidgets +QtAppPtr: t.CTypedef = t.CVoid | t.CPtr # QApplication* +QtWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QWidget* +QtDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QDialog* +QtMainWindowPtr: t.CTypedef = t.CVoid | t.CPtr # QMainWindow* +QtLabelPtr: t.CTypedef = t.CVoid | t.CPtr # QLabel* +QtPushButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QPushButton* +QtLineEditPtr: t.CTypedef = t.CVoid | t.CPtr # QLineEdit* +QtTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QTextEdit* +QtPlainTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QPlainTextEdit* +QtCheckBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QCheckBox* +QtRadioButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QRadioButton* +QtComboBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QComboBox* +QtListWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidget* +QtListWidgetItemPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidgetItem* +QtProgressBarPtr: t.CTypedef = t.CVoid | t.CPtr # QProgressBar* +QtSliderPtr: t.CTypedef = t.CVoid | t.CPtr # QSlider* +QtSpinBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QSpinBox* +QtLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QLayout* +QtBoxLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QHBoxLayout / QVBoxLayout* +QtGridLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QGridLayout* +QtFormLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QFormLayout* +QtStackedWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QStackedWidget* +QtTabWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QTabWidget* +QtMenuBarPtr: t.CTypedef = t.CVoid | t.CPtr # QMenuBar* +QtMenuPtr: t.CTypedef = t.CVoid | t.CPtr # QMenu* +QtActionPtr: t.CTypedef = t.CVoid | t.CPtr # QAction* +QtStatusBarPtr: t.CTypedef = t.CVoid | t.CPtr # QStatusBar* +QtToolBarPtr: t.CTypedef = t.CVoid | t.CPtr # QToolBar* +QtMessageBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QMessageBox* +QtFileDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFileDialog* +QtColorDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QColorDialog* +QtFontDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFontDialog* +QtInputDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QInputDialog* + +# QtNetwork +QtTcpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QTcpSocket* +QtUdpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QUdpSocket* +QtHostAddressPtr: t.CTypedef = t.CVoid | t.CPtr # QHostAddress* +QtAbstractSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QAbstractSocket* +QtNetworkAccessManagerPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkAccessManager* +QtNetworkReplyPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkReply* +QtNetworkRequestPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkRequest* + +# ============================================================ +# Qt 通用常量(C++ 枚举值的 C 兼容定义) +# ============================================================ + +# Qt 键盘按键 (Qt::Key) +QT_KEY_ESCAPE: t.CDefine = 0x01000000 +QT_KEY_TAB: t.CDefine = 0x01000001 +QT_KEY_BACKTAB: t.CDefine = 0x01000002 +QT_KEY_BACKSPACE: t.CDefine = 0x01000003 +QT_KEY_RETURN: t.CDefine = 0x01000004 +QT_KEY_ENTER: t.CDefine = 0x01000005 +QT_KEY_INSERT: t.CDefine = 0x01000006 +QT_KEY_DELETE: t.CDefine = 0x01000007 +QT_KEY_PAUSE: t.CDefine = 0x01000008 +QT_KEY_PRINT: t.CDefine = 0x01000009 +QT_KEY_HOME: t.CDefine = 0x01000010 +QT_KEY_END: t.CDefine = 0x01000011 +QT_KEY_LEFT: t.CDefine = 0x01000012 +QT_KEY_UP: t.CDefine = 0x01000013 +QT_KEY_RIGHT: t.CDefine = 0x01000014 +QT_KEY_DOWN: t.CDefine = 0x01000015 +QT_KEY_PAGEUP: t.CDefine = 0x01000016 +QT_KEY_PAGEDOWN: t.CDefine = 0x01000017 +QT_KEY_SHIFT: t.CDefine = 0x01000020 +QT_KEY_CONTROL: t.CDefine = 0x01000021 +QT_KEY_META: t.CDefine = 0x01000022 +QT_KEY_ALT: t.CDefine = 0x01000023 +QT_KEY_F1: t.CDefine = 0x01000030 +QT_KEY_F2: t.CDefine = 0x01000031 +QT_KEY_F12: t.CDefine = 0x0100003b +QT_KEY_SPACE: t.CDefine = 0x20 +QT_KEY_A: t.CDefine = 0x41 +QT_KEY_Z: t.CDefine = 0x5a +QT_KEY_0: t.CDefine = 0x30 +QT_KEY_9: t.CDefine = 0x39 + +# Qt 鼠标按键 (Qt::MouseButton) +QT_NO_BUTTON: t.CDefine = 0x00000000 +QT_LEFT_BUTTON: t.CDefine = 0x00000001 +QT_RIGHT_BUTTON: t.CDefine = 0x00000002 +QT_MID_BUTTON: t.CDefine = 0x00000004 + +# Qt::AlignmentFlag +QT_ALIGN_LEFT: t.CDefine = 0x0001 +QT_ALIGN_RIGHT: t.CDefine = 0x0002 +QT_ALIGN_HCENTER: t.CDefine = 0x0004 +QT_ALIGN_TOP: t.CDefine = 0x0020 +QT_ALIGN_BOTTOM: t.CDefine = 0x0040 +QT_ALIGN_VCENTER: t.CDefine = 0x0080 +QT_ALIGN_CENTER: t.CDefine = QT_ALIGN_HCENTER | QT_ALIGN_VCENTER + +# Qt::Orientation +QT_HORIZONTAL: t.CDefine = 0x1 +QT_VERTICAL: t.CDefine = 0x2 + +# Qt 焦点 +QT_NO_FOCUS: t.CDefine = 0x00 +QT_TAB_FOCUS: t.CDefine = 0x01 +QT_CLICK_FOCUS: t.CDefine = 0x02 +QT_STRONG_FOCUS: t.CDefine = QT_TAB_FOCUS | QT_CLICK_FOCUS +QT_WHEEL_FOCUS: t.CDefine = 0x04 +QT_ALL_FOCUS: t.CDefine = QT_STRONG_FOCUS | QT_WHEEL_FOCUS + +# Qt::WindowFlag +QT_WINDOW: t.CDefine = 0x00000001 +QT_DIALOG: t.CDefine = 0x00000002 | QT_WINDOW +QT_SHEET: t.CDefine = 0x00000004 | QT_WINDOW +QT_DRAWER: t.CDefine = QT_SHEET | 0x00000008 +QT_POPUP: t.CDefine = 0x00000008 | QT_WINDOW +QT_TOOL: t.CDefine = 0x0000000a | QT_WINDOW +QT_TOOLTIP: t.CDefine = 0x0000000c | QT_WINDOW +QT_SPLASH_SCREEN: t.CDefine = 0x0000000e | QT_WINDOW + +QT_WINDOW_TITLE: t.CDefine = 0x00000001 +QT_WINDOW_SYSTEM_MENU: t.CDefine = 0x00000002 +QT_WINDOW_MIN_MAX_BUTTONS: t.CDefine = 0x00000004 +QT_WINDOW_CLOSE_BUTTON: t.CDefine = 0x08000000 +QT_WINDOW_CONTEXT_HELP_BUTTON: t.CDefine = 0x00000008 + +# QMessageBox 标准按钮 +QT_OK: t.CDefine = 0x00000400 +QT_CANCEL: t.CDefine = 0x00400000 +QT_YES: t.CDefine = 0x00004000 +QT_NO: t.CDefine = 0x00010000 +QT_CLOSE: t.CDefine = 0x00200000 + +# 事件类型 +QT_EVENT_NONE: t.CDefine = 0 +QT_EVENT_KEY: t.CDefine = 6 +QT_EVENT_MOUSE_BUTTON_PRESS: t.CDefine = 2 +QT_EVENT_MOUSE_BUTTON_RELEASE: t.CDefine = 3 +QT_EVENT_MOUSE_MOVE: t.CDefine = 5 +QT_EVENT_PAINT: t.CDefine = 12 +QT_EVENT_RESIZE: t.CDefine = 14 +QT_EVENT_CLOSE: t.CDefine = 19 +QT_EVENT_SHOW: t.CDefine = 17 +QT_EVENT_HIDE: t.CDefine = 18 diff --git a/vrandom.vp b/vrandom.vp new file mode 100644 index 0000000..ecfa119 --- /dev/null +++ b/vrandom.vp @@ -0,0 +1,379 @@ +# vrandom - Hardware Random Number Generation Library +# Implemented using inline assembly based on x86 RDRAND / RDSEED instructions +import t, c +import vipermath + + +# Retry limit (RDRAND usually doesn't need retries, RDSEED might) +RDRAND_RETRY_LIMIT: t.CDefine = 10 +RDSEED_RETRY_LIMIT: t.CDefine = 100 + + +# ============================================================ +# RDRAND - Hardware random numbers (output from a pseudo-random number generator) +# ============================================================ + +def rdrand16() -> t.CUInt16T: + val: t.CUInt32T = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return t.CUInt16T(val) + + +def rdrand32() -> t.CUInt32T: + val: t.CUInt32T = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +def rdrand64() -> t.CUInt64T: + val: t.CUInt64T = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +# ============================================================ +# RDSEED - Hardware random seeds (direct output from entropy source) +# ============================================================ + +def rdseed16() -> t.CUInt16T: + val: t.CUInt32T = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return t.CUInt16T(val) + + +def rdseed32() -> t.CUInt32T: + val: t.CUInt32T = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +def rdseed64() -> t.CUInt64T: + val: t.CUInt64T = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +# ============================================================ +# Step version (with success flag, matching GCC builtin interface) +# Returns success flag: 1 on success, 0 on failure; random value written to *p +# ============================================================ + +def rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = t.CUInt16T(val) + return t.CInt(ok) + + +def rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +def rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt: + val: t.CUInt64T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +def rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = t.CUInt16T(val) + return t.CInt(ok) + + +def rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +def rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt: + val: t.CUInt64T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +# ============================================================ +# Convenient interface with retry (automatically retries until it succeeds or reaches the limit) +# ============================================================ + +def random_u16() -> t.CUInt16T: + r: t.CUInt16T = 0 + i: t.CInt = 0 + while i < RDRAND_RETRY_LIMIT: + if rdrand16_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def random_u32() -> t.CUInt32T: + r: t.CUInt32T = 0 + i: t.CInt = 0 + while i < RDRAND_RETRY_LIMIT: + if rdrand32_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def random_u64() -> t.CUInt64T: + r: t.CUInt64T = 0 + i: t.CInt = 0 + while i < RDRAND_RETRY_LIMIT: + if rdrand64_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def seed_u16() -> t.CUInt16T: + r: t.CUInt16T = 0 + i: t.CInt = 0 + while i < RDSEED_RETRY_LIMIT: + if rdseed16_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def seed_u32() -> t.CUInt32T: + r: t.CUInt32T = 0 + i: t.CInt = 0 + while i < RDSEED_RETRY_LIMIT: + if rdseed32_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def seed_u64() -> t.CUInt64T: + r: t.CUInt64T = 0 + i: t.CInt = 0 + while i < RDSEED_RETRY_LIMIT: + if rdseed64_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +# ============================================================ +# Python random standard library function implementations +# Default types: t.CUInt64T (u64), t.CDouble (f64), t.CInt (i32) +# ============================================================ + +# ---------- ONE, Random integers ---------- + +def randint(a: t.CInt, b: t.CInt) -> t.CInt: + return t.CInt(a + t.CInt(random_u64() % t.CUInt64T(b - a + 1))) + + +def randrange(start: t.CInt, stop: t.CInt, step: t.CInt = 1) -> t.CInt: + width: t.CInt = 0 + if step > 0: + width = (stop - start + step - 1) // step + else: + width = (start - stop - step - 1) // (-step) + return t.CInt(start + t.CInt(random_u64() % t.CUInt64T(width)) * step) + + +def getrandbits(k: t.CInt) -> t.CUInt64T: + r: t.CUInt64T = rdrand64() + if k >= 64: + return r + mask: t.CUInt64T = (t.CUInt64T(1) << k) - t.CUInt64T(1) + return r & mask + + +# ---------- TWO, Random floating-point numbers ---------- + +def random() -> t.CDouble: + return t.CDouble(rdrand64() >> 11) * (t.CDouble(1.0) / t.CDouble(9007199254740992.0)) + + +def uniform(a: t.CDouble, b: t.CDouble) -> t.CDouble: + return a + (b - a) * random() + + +def triangular(low: t.CDouble, high: t.CDouble, mode: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + c: t.CDouble = (mode - low) / (high - low) + if u > c: + u = t.CDouble(1.0) - u + c = t.CDouble(1.0) - c + tmp: t.CDouble = low + low = high + high = tmp + return low + (high - low) * vipermath.sqrt(u * c) + + +def betavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: + y: t.CDouble = gammavariate(alpha, t.CDouble(1.0)) + if y != t.CDouble(0.0): + return y / (y + gammavariate(beta, t.CDouble(1.0))) + return t.CDouble(0.0) + + +def expovariate(lambd: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return -vipermath.log(t.CDouble(1.0) - u) / lambd + + +def gammavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: + u: t.CDouble = t.CDouble(0.0) + d: t.CDouble = t.CDouble(0.0) + c: t.CDouble = t.CDouble(0.0) + x: t.CDouble = t.CDouble(0.0) + v: t.CDouble = t.CDouble(0.0) + if alpha <= t.CDouble(0.0) or beta <= t.CDouble(0.0): + return t.CDouble(0.0) + if alpha < t.CDouble(1.0): + u = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return gammavariate(alpha + t.CDouble(1.0), beta) * vipermath.pow(u, t.CDouble(1.0) / alpha) + d = alpha - t.CDouble(1.0) / t.CDouble(3.0) + c = t.CDouble(1.0) / vipermath.sqrt(t.CDouble(9.0) * d) + while 1: + x = gauss(t.CDouble(0.0), t.CDouble(1.0)) + v = t.CDouble(1.0) + c * x + if v > t.CDouble(0.0): + v = v * v * v + u = random() + if u < t.CDouble(1.0) - t.CDouble(0.0331) * x * x * x * x: + return d * v * beta + if vipermath.log(u) < t.CDouble(0.5) * x * x + d * (t.CDouble(1.0) - v + vipermath.log(v)): + return d * v * beta + + +def gauss(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: + u1: t.CDouble = random() + u2: t.CDouble = random() + if u1 < t.CDouble(1e-300): + u1 = t.CDouble(1e-300) + z0: t.CDouble = vipermath.sqrt(t.CDouble(-2.0) * vipermath.log(u1)) * vipermath.cos(t.CDouble(2.0) * vipermath.U_M_PI * u2) + return mu + sigma * z0 + + +def normalvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: + NV_MAGICCONST: t.CDouble = t.CDouble(1.7155277699214135) + u1: t.CDouble = t.CDouble(0.0) + u2: t.CDouble = t.CDouble(0.0) + z: t.CDouble = t.CDouble(0.0) + zz: t.CDouble = t.CDouble(0.0) + while 1: + u1 = random() + u2 = random() + if u2 < t.CDouble(1e-300): + continue + z = NV_MAGICCONST * (u1 - t.CDouble(0.5)) / u2 + zz = z * z / t.CDouble(4.0) + if zz <= t.CDouble(0.0) - vipermath.log(u2): + break + return mu + z * sigma + + +def lognormvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: + return vipermath.exp(gauss(mu, sigma)) + + +def vonmisesvariate(mu: t.CDouble, kappa: t.CDouble) -> t.CDouble: + if kappa <= t.CDouble(1e-6): + return vipermath.U_M_PI * t.CDouble(2.0) * random() + s: t.CDouble = t.CDouble(0.5) / kappa + r: t.CDouble = s + vipermath.sqrt(t.CDouble(1.0) + s * s) + u1: t.CDouble = t.CDouble(0.0) + u2: t.CDouble = t.CDouble(0.0) + u3: t.CDouble = t.CDouble(0.0) + z: t.CDouble = t.CDouble(0.0) + d: t.CDouble = t.CDouble(0.0) + q: t.CDouble = t.CDouble(0.0) + f: t.CDouble = t.CDouble(0.0) + theta: t.CDouble = t.CDouble(0.0) + two_pi: t.CDouble = vipermath.U_M_PI * t.CDouble(2.0) + while 1: + u1 = random() + z = vipermath.cos(vipermath.U_M_PI * u1) + d = t.CDouble(1.0) / (r + z) + u2 = random() + if u2 < t.CDouble(1.0) - d * d: + break + if u2 < (t.CDouble(1.0) - z) * vipermath.exp(kappa * (z - t.CDouble(1.0)) - d * kappa * r): + break + q = t.CDouble(1.0) / r + f = (q + z) / (t.CDouble(1.0) + q * z) + u3 = random() + if u3 > t.CDouble(0.5): + theta = mu + vipermath.acos(f) + else: + theta = mu - vipermath.acos(f) + while theta < t.CDouble(0.0): + theta += two_pi + while theta >= two_pi: + theta -= two_pi + return theta + + +def paretovariate(alpha: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return t.CDouble(1.0) / vipermath.pow(t.CDouble(1.0) - u, t.CDouble(1.0) / alpha) + + +def weibullvariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return alpha * vipermath.pow(t.CDouble(-1.0) * vipermath.log(t.CDouble(1.0) - u), t.CDouble(1.0) / beta) diff --git a/vthreading.vp b/vthreading.vp new file mode 100644 index 0000000..12a1b4c --- /dev/null +++ b/vthreading.vp @@ -0,0 +1,102 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32process import CreateThread, GetExitCodeThread, GetCurrentThreadId, TlsAlloc, TlsFree, TlsGetValue, TlsSetValue +from w32.win32sync import WaitForSingleObject + +# All lock classes are imported, and users can also import them as needed. +from lock import Lock +from event import Event +from condition import Condition +from rwlock import RWLock + + +class Thread: + """Thread class, wraps Windows CreateThread. + + Thread callback signature: def thread_func(arg: t.CPtr) -> t.CPtr + Note: Windows API limits the return value to DWORD (32-bit), so 64-bit pointers will be truncated. + If you need to return a 64-bit result, pass it via the arg parameter struct. + + Usage: + def worker(arg: t.CPtr) -> t.CPtr: + # thread logic + return NULL + + t: Thread = Thread(worker, arg_ptr) + t.start() + t.join() + """ + handle: HANDLE + thread_id: ULONG + target: VOIDPTR + arg: VOIDPTR + started: BOOL + + def __init__(self, target: VOIDPTR, arg: VOIDPTR = NULL): + self.handle = NULL + self.thread_id = 0 + self.target = target + self.arg = arg + self.started = FALSE + + def start(self): + if self.started: + return + self.handle = CreateThread(NULL, 0, self.target, self.arg, 0, c.Addr(self.thread_id)) + self.started = TRUE + + def join(self, timeout_ms: ULONG = INFINITE) -> BOOL: + if not self.started: + return FALSE + result: ULONG = WaitForSingleObject(self.handle, timeout_ms) + return result == WAIT_OBJECT_0 + + def is_alive(self) -> BOOL: + if not self.started: + return FALSE + result: ULONG = WaitForSingleObject(self.handle, 0) + return result == WAIT_TIMEOUT + + def get_exit_code(self) -> ULONG: + code: ULONG = 0 + GetExitCodeThread(self.handle, c.Addr(code)) + return code + + def close(self): + if self.handle != NULL: + CloseHandle(self.handle) + self.handle = NULL + + +class local: + """TLS (Thread Local Storage) encapsulation. + + Usage: + tls: local = local() + tls.set(value_ptr) + val: t.CPtr = tls.get() + """ + index: ULONG + + def __init__(self): + self.index = TlsAlloc() + + def get(self) -> VOIDPTR: + return TlsGetValue(self.index) + + def set(self, value: VOIDPTR) -> BOOL: + return TlsSetValue(self.index, value) + + def free(self) -> BOOL: + return TlsFree(self.index) + + +def get_current_thread_id() -> ULONG: + """Get current thread ID""" + return GetCurrentThreadId() + + +def sleep_ms(ms: ULONG): + """Make the current thread sleep for a specified number of milliseconds""" + Sleep(ms) diff --git a/w32/fileio.vp b/w32/fileio.vp new file mode 100644 index 0000000..61b1ac9 --- /dev/null +++ b/w32/fileio.vp @@ -0,0 +1,389 @@ +import t, c +from stdint import * +import stdio +import w32.win32base +import w32.win32file + + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 + + +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 + +INVALID_SET_FILE_POINTER: t.CDefine = -1 + +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + + def __init__(self, filename: str, mode: ULONG, share: ULONG = SHARE_READ): + self.closed = True + self.can_read = False + self.can_write = False + self.is_append = False + self._share_mode = share + + access: ULONG = 0 + disposition: ULONG = w32.win32file.OPEN_EXISTING + + if mode == MODE.R: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + elif mode == MODE.W: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_write = True + elif mode == MODE.A: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_write = True + self.is_append = True + elif mode == MODE.RP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + self.can_write = True + elif mode == MODE.WP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_read = True + self.can_write = True + elif mode == MODE.AP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_read = True + self.can_write = True + self.is_append = True + elif mode == MODE.X: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_write = True + elif mode == MODE.XP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_read = True + self.can_write = True + else: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + + self.handle = w32.win32file.CreateFileA( + filename, access, self._share_mode, + None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None + ) + + if self.handle == w32.win32base.INVALID_HANDLE_VALUE: + self.closed = True + return + + self.closed = False + + if self.is_append: + self.seek(0, SEEK_END) + + def __enter__(self) -> 'File' | t.CPtr: + return self + + def __exit__(self): + self.close() + + def read(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), None) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_read) + + def write(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + bytes_written: ULONG = 0 + result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), None) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_written) + + def write_str(self, s: str) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + length: ULONG = 0 + p: bytes = s + while c.Deref(p) != 0: + length += 1 + p += 1 + return self.write(s, length) + + def seek(self, offset: LONG, origin: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + result: LONG = w32.win32file.SetFilePointer(self.handle, offset, None, origin) + if result == -1: return FRESULT.ERR_IO + return result + + def tell(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + return self.seek(0, SEEK_CUR) + + def close(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32base.CloseHandle(self.handle) + self.closed = True + return FRESULT.OK + + def flush(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32file.FlushFileBuffers(self.handle) + return FRESULT.OK + + def size(self) -> LONGLONG: + if self.closed: return -1 + li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER() + result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li))) + if result == 0: return -1 + return li.QuadPart + + def readline(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + total: ULONG = 0 + bytes_read: ULONG = 0 + ch: t.CInt = 0 + while total < max_count - 1: + bytes_read = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), None) + if result == 0 or bytes_read == 0: break + ch = c.Deref(buf + total) + total += 1 + if ch == 10: break + if total < max_count: + buf[total] = 0 + return LONG(total) + + def read_all(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + file_size: LONGLONG = self.size() + if file_size < 0: return FRESULT.ERR_IO + to_read: ULONG = 0 + if file_size < max_count - 1: + to_read = ULONG(file_size) + else: + to_read = max_count - 1 + self.seek(0, SEEK_SET) + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None) + if result == 0: return FRESULT.ERR_IO + if bytes_read < max_count: + buf[bytes_read] = 0 + return LONG(bytes_read) + + +class FileW: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + + def __init__(self, filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ): + self.closed = True + self.can_read = False + self.can_write = False + self.is_append = False + self._share_mode = share + + access: ULONG = 0 + disposition: ULONG = w32.win32file.OPEN_EXISTING + + if mode == MODE.R: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + elif mode == MODE.W: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_write = True + elif mode == MODE.A: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_write = True + self.is_append = True + elif mode == MODE.RP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + self.can_write = True + elif mode == MODE.WP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_read = True + self.can_write = True + elif mode == MODE.AP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_read = True + self.can_write = True + self.is_append = True + elif mode == MODE.X: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_write = True + elif mode == MODE.XP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_read = True + self.can_write = True + else: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + + self.handle = w32.win32file.CreateFileW( + filename, access, self._share_mode, + None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None + ) + + if self.handle == w32.win32base.INVALID_HANDLE_VALUE: + self.closed = True + return + + self.closed = False + + if self.is_append: + self.seek(0, SEEK_END) + + def __enter__(self) -> 'FileW' | t.CPtr: + return self + + def __exit__(self): + self.close() + + def read(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), None) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_read) + + def write(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + bytes_written: ULONG = 0 + result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), None) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_written) + + def write_str(self, s: str) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + length: ULONG = 0 + p: bytes = s + while c.Deref(p) != 0: + length += 1 + p += 1 + return self.write(s, length) + + def seek(self, offset: LONG, origin: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + result: LONG = w32.win32file.SetFilePointer(self.handle, offset, None, origin) + if result == -1: return FRESULT.ERR_IO + return result + + def tell(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + return self.seek(0, SEEK_CUR) + + def close(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32base.CloseHandle(self.handle) + self.closed = True + return FRESULT.OK + + def flush(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32file.FlushFileBuffers(self.handle) + return FRESULT.OK + + def size(self) -> LONGLONG: + if self.closed: return -1 + li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER() + result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li))) + if result == 0: return -1 + return li.QuadPart + + def readline(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + total: ULONG = 0 + bytes_read: ULONG = 0 + ch: t.CInt = 0 + while total < max_count - 1: + bytes_read = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), None) + if result == 0 or bytes_read == 0: break + ch = c.Deref(buf + total) + total += 1 + if ch == 10: break + if total < max_count: + buf[total] = 0 + return LONG(total) + + def read_all(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + file_size: LONGLONG = self.size() + if file_size < 0: return FRESULT.ERR_IO + to_read: ULONG = 0 + if file_size < max_count - 1: + to_read = ULONG(file_size) + else: + to_read = max_count - 1 + self.seek(0, SEEK_SET) + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None) + if result == 0: return FRESULT.ERR_IO + if bytes_read < max_count: + buf[bytes_read] = 0 + return LONG(bytes_read) + + +def open(filename: str, mode: ULONG, share: ULONG = SHARE_READ) -> File | t.CPtr: + return File(filename, mode, share) + +def openw(filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr: + return FileW(filename, mode, share) diff --git a/w32/win32base.vp b/w32/win32base.vp new file mode 100644 index 0000000..aba48d3 --- /dev/null +++ b/w32/win32base.vp @@ -0,0 +1,80 @@ +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr + +INVALID_HANDLE_VALUE: t.CDefine = -1 +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES(): + nLength: DWORD + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL + +class OVERLAPPED(): + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: DWORD + OffsetHigh: DWORD + hEvent: HANDLE + +class FILETIME(): + dwLowDateTime: DWORD + dwHighDateTime: DWORD + +class SYSTEMTIME(): + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD + +class GUID(): + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR + +class LARGE_INTEGER(): + QuadPart: LONGLONG + +class ULARGE_INTEGER(): + QuadPart: ULONGLONG + +extern def GetLastError() -> ULONG +extern def SetLastError(dwErrCode: ULONG) +extern def CloseHandle(hObject: HANDLE) -> BOOL +extern def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR +extern def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE +extern def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE +extern def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE +extern def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE +extern def FreeLibrary(hLibModule: HANDLE) -> BOOL +extern def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) +extern def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) +extern def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL +extern def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL +extern def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL +extern def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL +extern def Sleep(dwMilliseconds: ULONG) +extern def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG +extern def GetTickCount() -> ULONG +extern def GetTickCount64() -> ULONGLONG +extern def GetCommandLineA() -> CHARPTR diff --git a/w32/win32console.vp b/w32/win32console.vp new file mode 100644 index 0000000..b7a7113 --- /dev/null +++ b/w32/win32console.vp @@ -0,0 +1,111 @@ +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 + +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 + +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 + +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD(): + X: SHORT + Y: SHORT + +class SMALL_RECT(): + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT + +class CONSOLE_SCREEN_BUFFER_INFO(): + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD + +class CONSOLE_CURSOR_INFO(): + dwSize: DWORD + bVisible: BOOL + +class CHAR_INFO(): + UnicodeChar: WCHAR + Attributes: WORD + +class KEY_EVENT_RECORD(): + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: DWORD + +class MOUSE_EVENT_RECORD(): + dwMousePosition: COORD + dwButtonState: DWORD + dwControlKeyState: DWORD + dwEventFlags: DWORD + +class WINDOW_BUFFER_SIZE_RECORD(): + dwSize: COORD + +class INPUT_RECORD(): + EventType: WORD + Event: KEY_EVENT_RECORD + +extern def SetConsoleOutputCP(codepage: UINT) -> BOOL +extern def SetConsoleCP(codepage: UINT) -> BOOL +extern def GetConsoleCP() -> UINT +extern def GetConsoleOutputCP() -> UINT +extern def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL +extern def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL +extern def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL +extern def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL +extern def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL +extern def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL +extern def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL +extern def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL +extern def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL +extern def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL +extern def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL +extern def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL +extern def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL +extern def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL +extern def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL +extern def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL +extern def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL +extern def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL +extern def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL +extern def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL +extern def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL +extern def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG +extern def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG +extern def AllocConsole() -> BOOL +extern def FreeConsole() -> BOOL +extern def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL +extern def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL diff --git a/w32/win32file.vp b/w32/win32file.vp new file mode 100644 index 0000000..4fcbfb0 --- /dev/null +++ b/w32/win32file.vp @@ -0,0 +1,143 @@ +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 + +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 + +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 + +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 + +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 + +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 + +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) + +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION(): + dwFileAttributes: DWORD + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: DWORD + nFileSizeHigh: DWORD + nFileSizeLow: DWORD + nNumberOfLinks: DWORD + nFileIndexHigh: DWORD + nFileIndexLow: DWORD + +class WIN32_FIND_DATAA(): + dwFileAttributes: DWORD + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: DWORD + nFileSizeLow: DWORD + dwReserved0: DWORD + dwReserved1: DWORD + cFileName: t.CArray[t.CChar, 260] + cAlternateFileName: t.CArray[t.CChar, 14] + +class WIN32_FIND_DATAW(): + dwFileAttributes: DWORD + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: DWORD + nFileSizeLow: DWORD + dwReserved0: DWORD + dwReserved1: DWORD + cFileName: t.CArray[t.CUInt16T, 260] + cAlternateFileName: t.CArray[t.CUInt16T, 14] + +extern def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE +extern def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE +extern def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL +extern def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL +extern def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG +extern def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL +extern def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG +extern def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL +extern def SetEndOfFile(hFile: HANDLE) -> BOOL +extern def FlushFileBuffers(hFile: HANDLE) -> BOOL +extern def GetFileType(hFile: HANDLE) -> ULONG +extern def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG +extern def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG +extern def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL +extern def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL +extern def DeleteFileA(lpFileName: LPCSTR) -> BOOL +extern def DeleteFileW(lpFileName: LPCWSTR) -> BOOL +extern def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL +extern def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL +extern def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL +extern def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL +extern def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL +extern def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL +extern def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL +extern def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL +extern def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL +extern def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL +extern def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE +extern def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE +extern def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL +extern def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL +extern def FindClose(hFindFile: HANDLE) -> BOOL +extern def GetStdHandle(nStdHandle: ULONG) -> HANDLE +extern def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL +extern def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL +extern def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL +extern def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL +extern def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG +extern def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG +extern def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT +extern def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT +extern def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG +extern def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG +extern def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL +extern def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL +extern def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG +extern def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG + +HANDLE_FLAG_INHERIT: t.CDefine = 0x00000001 +HANDLE_FLAG_PROTECT_FROM_CLOSE: t.CDefine = 0x00000002 + +extern def CreatePipe(hReadPipe: HANDLE | t.CPtr, hWritePipe: HANDLE | t.CPtr, lpPipeAttributes: SECURITY_ATTRIBUTES | t.CPtr, nSize: ULONG) -> BOOL +extern def SetHandleInformation(hObject: HANDLE, dwMask: ULONG, dwFlags: ULONG) -> BOOL +extern def DuplicateHandle(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, hTargetProcessHandle: HANDLE, lpTargetHandle: HANDLE | t.CPtr, dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwOptions: ULONG) -> BOOL + +DUPLICATE_SAME_ACCESS: t.CDefine = 0x00000002 diff --git a/w32/win32memory.vp b/w32/win32memory.vp new file mode 100644 index 0000000..ebeb811 --- /dev/null +++ b/w32/win32memory.vp @@ -0,0 +1,64 @@ +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 + +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 + +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION(): + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: DWORD + RegionSize: t.CSizeT + State: DWORD + Protect: DWORD + Type: DWORD + +extern def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR +extern def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL +extern def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL +extern def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT +extern def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL +extern def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL +extern def GetProcessHeap() -> HANDLE +extern def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE +extern def HeapDestroy(hHeap: HANDLE) -> BOOL +extern def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR +extern def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR +extern def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL +extern def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT +extern def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL +extern def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT +extern def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR +extern def GlobalFree(hMem: VOIDPTR) -> VOIDPTR +extern def GlobalLock(hMem: VOIDPTR) -> VOIDPTR +extern def GlobalUnlock(hMem: VOIDPTR) -> BOOL +extern def GlobalSize(hMem: VOIDPTR) -> t.CSizeT +extern def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR +extern def LocalFree(hMem: VOIDPTR) -> VOIDPTR diff --git a/w32/win32process.vp b/w32/win32process.vp new file mode 100644 index 0000000..89ed3e3 --- /dev/null +++ b/w32/win32process.vp @@ -0,0 +1,112 @@ +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF + +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF + +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 + +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 + +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 + +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 + +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA(): + cb: DWORD + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: DWORD + dwY: DWORD + dwXSize: DWORD + dwYSize: DWORD + dwXCountChars: DWORD + dwYCountChars: DWORD + dwFillAttribute: DWORD + dwFlags: DWORD + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE + +class STARTUPINFOW(): + cb: DWORD + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: DWORD + dwY: DWORD + dwXSize: DWORD + dwYSize: DWORD + dwXCountChars: DWORD + dwYCountChars: DWORD + dwFillAttribute: DWORD + dwFlags: DWORD + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE + +class PROCESS_INFORMATION(): + hProcess: HANDLE + hThread: HANDLE + dwProcessId: DWORD + dwThreadId: DWORD + +extern def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL +extern def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL +extern def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL +extern def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL +extern def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL +extern def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE +extern def GetCurrentProcess() -> HANDLE +extern def GetCurrentProcessId() -> ULONG +extern def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE +extern def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE +extern def SuspendThread(hThread: HANDLE) -> ULONG +extern def ResumeThread(hThread: HANDLE) -> ULONG +extern def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL +extern def GetCurrentThread() -> HANDLE +extern def GetCurrentThreadId() -> ULONG +extern def GetThreadId(hThread: HANDLE) -> ULONG +extern def GetProcessId(hProcess: HANDLE) -> ULONG +extern def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL +extern def GetThreadPriority(hThread: HANDLE) -> INT +extern def ExitProcess(uExitCode: UINT) -> VOID +extern def ExitThread(dwExitCode: ULONG) -> VOID +extern def TlsAlloc() -> ULONG +extern def TlsFree(dwTlsIndex: ULONG) -> BOOL +extern def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR +extern def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL diff --git a/w32/win32sync.vp b/w32/win32sync.vp new file mode 100644 index 0000000..a054423 --- /dev/null +++ b/w32/win32sync.vp @@ -0,0 +1,65 @@ +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION(): + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +extern def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL +extern def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG +extern def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL +extern def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE +extern def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE +extern def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE +extern def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE +extern def ReleaseMutex(hMutex: HANDLE) -> BOOL +extern def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE +extern def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE +extern def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE +extern def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE +extern def SetEvent(hEvent: HANDLE) -> BOOL +extern def ResetEvent(hEvent: HANDLE) -> BOOL +extern def PulseEvent(hEvent: HANDLE) -> BOOL +extern def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE +extern def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE +extern def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE +extern def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE +extern def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL +extern def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG +extern def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG +extern def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG +extern def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG +extern def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID +extern def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID +extern def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID +extern def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID +extern def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID + +# 条件变量 (Condition Variables) - Vista+ +CONDITION_VARIABLE_LOCKMODE_SHARED: t.CDefine = 0x1 + +extern def InitializeConditionVariable(ConditionVariable: VOIDPTR) -> VOID +extern def SleepConditionVariableCS(ConditionVariable: VOIDPTR, CriticalSection: CRITICAL_SECTION | t.CPtr, dwMilliseconds: ULONG) -> BOOL +extern def SleepConditionVariableSRW(ConditionVariable: VOIDPTR, SRWLock: VOIDPTR, dwMilliseconds: ULONG, Flags: ULONG) -> BOOL +extern def WakeConditionVariable(ConditionVariable: VOIDPTR) -> VOID +extern def WakeAllConditionVariable(ConditionVariable: VOIDPTR) -> VOID + +# 一次性初始化 (One-Time Initialization) - Vista+ +INIT_ONCE_STATIC_INIT: t.CDefine = 0x00000001 +INIT_ONCE_CHECK_ONLY: t.CDefine = 0x00000002 +INIT_ONCE_ASYNC: t.CDefine = 0x00000004 +INIT_ONCE_INIT_FAILED: t.CDefine = 0x00000008 + +class INIT_ONCE: + Ptr: t.CPtr + +extern def InitOnceExecuteOnce(InitOnce: INIT_ONCE | t.CPtr, InitFn: VOIDPTR, Parameter: VOIDPTR, Context: VOIDPTR | t.CPtr) -> BOOL diff --git a/w32/winsock2.vp b/w32/winsock2.vp new file mode 100644 index 0000000..990b248 --- /dev/null +++ b/w32/winsock2.vp @@ -0,0 +1,104 @@ +import t, c +from stdint import * +from w32.win32base import * + + +# ============================================================ +# w32/winsock2.py — WinSock2 API 声明 (ws2_32.dll) +# ============================================================ + +# 版本常量 +WINSOCK_VERSION: t.CDefine = 0x0202 # 2.2 + +# 地址族 +AF_INET: t.CDefine = 2 +AF_INET6: t.CDefine = 23 + +# 套接字类型 +SOCK_STREAM: t.CDefine = 1 # TCP +SOCK_DGRAM: t.CDefine = 2 # UDP +SOCK_RAW: t.CDefine = 3 # 原始套接字 + +# 协议 +IPPROTO_TCP: t.CDefine = 6 +IPPROTO_UDP: t.CDefine = 17 + +# 选项级别 +SOL_SOCKET: t.CDefine = 0xFFFF # WinSock2 值 +SO_RCVTIMEO: t.CDefine = 0x1006 # WinSock2 值 +SO_SNDTIMEO: t.CDefine = 0x1005 # WinSock2 值 +SO_REUSEADDR: t.CDefine = 0x0004 # WinSock2 值 + +# 特殊值 +INADDR_ANY: t.CDefine = 0 +SOCKET_ERROR: t.CDefine = -1 +INVALID_SOCKET: t.CDefine = 0xFFFFFFFF # WinSock2: ~0 + +# 发送/接收标志 +MSG_NOSIGNAL: t.CDefine = 0 # Windows 不支持,设为 0 + +# 关闭方式 +SD_SEND: t.CDefine = 1 +SD_RECV: t.CDefine = 0 +SD_BOTH: t.CDefine = 2 + + +# ============================================================ +# 结构体 +# ============================================================ +# struct sockaddr_in — 16 字节 +class WSASocketAddr: + family: u16 # sin_family + port: u16 # sin_port + addr: u32 # sin_addr.s_addr + zero: u64 # sin_zero + + +# struct WSADATA — 400 字节 +class WSAData: + wVersion: WORD # @ 0 + wHighVersion: WORD # @ 2 + szDescription: BYTE # @ 4 (257 bytes + padding) + szSystemStatus: BYTE # @ 261 (129 bytes + padding) + iMaxSockets: u16 # @ 390 + iMaxUdpDg: u16 # @ 392 + lpVendorInfo: CHARPTR # @ 394 (实际上指针是 8 字节对齐) + + +# struct hostent — 自然对齐: h_name(8) + h_aliases(8) + h_addrtype(2) + h_length(2) + auto-pad(4) + h_addr_list(8) = 32 +class WSAHostEnt: + h_name: CHARPTR + h_aliases: CHARPTR + h_addrtype: SHORT + h_length: SHORT + h_addr_list: CHARPTR + + +# struct timeval +class WinTimeVal: + tv_sec: LONG # 秒 + tv_usec: LONG # 微秒 + + +# ============================================================ +# WinSock2 API 函数 +# ============================================================ + +extern def WSAStartup(wVersionRequested: WORD, lpWSAData: WSAData | t.CPtr) -> INT +extern def WSACleanup() -> INT +extern def WSAGetLastError() -> INT + +extern def socket(family: INT, type: INT, protocol: INT) -> u64 +extern def closesocket(s: u64) -> INT +extern def connect(s: u64, name: WSASocketAddr | t.CPtr, namelen: INT) -> INT +extern def send(s: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT +extern def recv(s: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT +extern def bind(s: u64, name: WSASocketAddr | t.CPtr, namelen: INT) -> INT +extern def listen(s: u64, backlog: INT) -> INT +extern def accept(s: u64, addr: WSASocketAddr | t.CPtr, addrlen: INT | t.CPtr) -> u64 +extern def setsockopt(s: u64, level: INT, optname: INT, optval: t.CVoid | t.CPtr, optlen: INT) -> INT +extern def shutdown(s: u64, how: INT) -> INT +extern def gethostbyname(name: t.CChar | t.CConst | t.CPtr) -> WSAHostEnt | t.CPtr +extern def ntohs(netshort: u16) -> u16 +extern def htons(hostshort: u16) -> u16 +extern def inet_addr(cp: t.CChar | t.CConst | t.CPtr) -> u32 \ No newline at end of file diff --git a/zlib/__init__.vp b/zlib/__init__.vp new file mode 100644 index 0000000..829b69e --- /dev/null +++ b/zlib/__init__.vp @@ -0,0 +1 @@ +from .pyzlib import * diff --git a/zlib/pyzlib.vp b/zlib/pyzlib.vp new file mode 100644 index 0000000..6eb1ca9 --- /dev/null +++ b/zlib/pyzlib.vp @@ -0,0 +1,697 @@ +# from string import memset, memcpy +# from stdio import malloc, free, calloc, realloc +from stdint import * +import zlib.zdeflate as zdeflate +import zlib.zinflate as zinflate +import zlib.zchecksum as zchecksum +import zlib.zdef as zdef +import zlib.zhuff as zhuff +import stdlib +import string +import memhub +import t, c + + +# ============================================================ +# Constants - matching Python zlib module names and values +# ============================================================ + +# Compression levels +Z_NO_COMPRESSION: t.CDefine = 0 +Z_BEST_SPEED: t.CDefine = 1 +Z_BEST_COMPRESSION: t.CDefine = 9 +Z_DEFAULT_COMPRESSION: t.CDefine = (-1) + +# Compression methods +DEFLATED: t.CDefine = 8 + +# Flush modes +Z_NO_FLUSH: t.CDefine = 0 +Z_PARTIAL_FLUSH: t.CDefine = 1 +Z_SYNC_FLUSH: t.CDefine = 2 +Z_FULL_FLUSH: t.CDefine = 3 +Z_FINISH: t.CDefine = 4 +Z_BLOCK: t.CDefine = 5 +Z_TREES: t.CDefine = 6 + +# Strategies +Z_DEFAULT_STRATEGY: t.CDefine = 0 +Z_FILTERED: t.CDefine = 1 +Z_HUFFMAN_ONLY: t.CDefine = 2 +Z_RLE: t.CDefine = 3 +Z_FIXED: t.CDefine = 4 + +# Return codes +Z_OK: t.CDefine = 0 +Z_STREAM_END: t.CDefine = 1 +Z_NEED_DICT: t.CDefine = 2 +Z_ERRNO: t.CDefine = (-1) +Z_STREAM_ERROR: t.CDefine = (-2) +Z_DATA_ERROR: t.CDefine = (-3) +Z_MEM_ERROR: t.CDefine = (-4) +Z_BUF_ERROR: t.CDefine = (-5) +Z_VERSION_ERROR: t.CDefine = (-6) + +# Window / Buffer constants +MAX_WBITS: t.CDefine = 15 +DEF_BUF_SIZE: t.CDefine = 16384 +DEF_MEM_LEVEL: t.CDefine = 8 + +# Version +ZLIB_VERSION: t.CDefine = "1.3.2" + +pyzlib_error_msg: t.CArray[t.CChar, 512] = "" +pyzlib_error_code_val: t.CInt = 0 + +# ============================================================ +# Structures +# ============================================================ +@t.Object +class Compress: + pool: memhub.MemManager | t.CPtr + stream: VOIDPTR + is_initialized: t.CInt + is_finished: t.CInt + level: t.CInt + method: t.CInt + wbits: t.CInt + memLevel: t.CInt + strategy: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + last_pos: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + header_written: t.CInt + + def compress(self, + data: BYTEPTR, data_len: t.CSizeT, + out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if self.is_finished: + set_error(Z_STREAM_ERROR, "compress object already finished") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if data_len == 0: + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p, 0, 1) + return p + while self.input_buf_len + data_len > self.input_buf_cap: + self.input_buf_cap *= 2 + if self.pool == None: + new_buf: BYTEPTR = BYTEPTR(stdlib.realloc(self.input_buf, self.input_buf_cap)) + else: + new_buf: BYTEPTR = BYTEPTR(self.pool.alloc(self.input_buf_cap)) + if new_buf: + string.memcpy(new_buf, self.input_buf, self.input_buf_len) + self.pool.free(self.input_buf) + if not new_buf: + set_error(Z_MEM_ERROR, "out of memory") + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p2: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p2, 0, 1) + return p2 + self.input_buf = new_buf + string.memcpy(self.input_buf + self.input_buf_len, data, data_len) + self.input_buf_len += data_len + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p3: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p3, 0, 1) + return p3 + + def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + if mode == Z_FINISH: + if not self.header_written: + self.header_written = 1 + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, 1) + s.compress_block(input_data, input_len, 1) + s.is_finished = 1 + if s.wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + self.is_finished = 1 + total: t.CSizeT = s.writer.total() + if self.pool == None: + result: BYTEPTR = BYTEPTR(stdlib.malloc(total)) + else: + result: BYTEPTR = BYTEPTR(self.pool.alloc(total)) + if result: string.memcpy(result, s.writer.buf, total) + c.Set(c.Deref(out_len), total) + if self.pool == None: + stdlib.free(self.input_buf) + else: + self.pool.free(self.input_buf) + self.input_buf = None + self.input_buf_len = 0 + self.input_buf_cap = 0 + return result + elif mode == Z_SYNC_FLUSH or mode == Z_FULL_FLUSH: + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len > 0: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, s.adler) + s.compress_block(input_data, input_len, 0) + self.input_buf_len = 0 + s.writer.write_bits(0, 1) + s.writer.write_bits(0, 2) + s.writer.align() + prev_pos: t.CSizeT = self.last_pos + total: t.CSizeT = s.writer.total() + delta: t.CSizeT = total - prev_pos + self.last_pos = s.writer.byte_pos + if delta == 0: + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p4: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p4, 0, 1) + return p4 + + if self.pool == None: + result: BYTEPTR = BYTEPTR(stdlib.malloc(delta)) + else: + result: BYTEPTR = BYTEPTR(self.pool.alloc(delta)) + if result: string.memcpy(result, s.writer.buf + prev_pos, delta) + c.Set(c.Deref(out_len), delta) + return result + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p5: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p5, 0, 1) + return p5 + + def copy(self) -> Compress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if self.pool == None: + copy_obj: Compress | t.CPtr = stdlib.calloc(1, Compress.__sizeof__()) + else: + copy_obj: Compress | t.CPtr = self.pool.alloc(Compress.__sizeof__()) + string.memset(copy_obj, 0, Compress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.pool = self.pool + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + copy_obj.stream = s.copy() + if not copy_obj.stream: + if self.pool == None: + stdlib.free(copy_obj) + else: + self.pool.free(copy_obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.is_initialized = 1 + copy_obj.is_finished = self.is_finished + copy_obj.level = self.level + copy_obj.method = self.method + copy_obj.wbits = self.wbits + copy_obj.memLevel = self.memLevel + copy_obj.strategy = self.strategy + copy_obj.last_pos = self.last_pos + copy_obj.header_written = self.header_written + if self.input_buf and self.input_buf_len > 0: + if self.pool == None: + copy_obj.input_buf = BYTEPTR(stdlib.calloc(1, self.input_buf_cap)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(self.input_buf_cap)) + string.memset(copy_obj.input_buf, 0, self.input_buf_cap) + if copy_obj.input_buf: + string.memcpy(copy_obj.input_buf, self.input_buf, self.input_buf_len) + copy_obj.input_buf_cap = self.input_buf_cap + copy_obj.input_buf_len = self.input_buf_len + else: + if self.pool == None: + copy_obj.input_buf = BYTEPTR(stdlib.calloc(1, 256)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(256)) + string.memset(copy_obj.input_buf, 0, 256) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.pool, self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + return copy_obj + + def delete(self): + if self.is_initialized and self.stream: + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + s.destroy() + if self.pool == None: + stdlib.free(self.zdict) + stdlib.free(self.input_buf) + stdlib.free(self) + else: + self.pool.free(self.zdict) + self.pool.free(self.input_buf) + self.pool.free(self) + + def __del__(self): + self.delete() + + +@t.Object +class Decompress: + pool: memhub.MemManager | t.CPtr + stream: VOIDPTR + is_initialized: t.CInt + eof: t.CInt + wbits: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + _unused_data: BYTEPTR + _unused_data_len: t.CSizeT + _unused_data_cap: t.CSizeT + _unconsumed_tail: BYTEPTR + _unconsumed_tail_len: t.CSizeT + _unconsumed_tail_cap: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + + def decompress(self, data: BYTEPTR, data_len: t.CSizeT, + max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if self.eof: + if data and data_len > 0: + append_bytes(self.pool, c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), data, data_len) + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p6: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p6, 0, 1) + return p6 + self._unconsumed_tail_len = 0 + if data and data_len > 0: + append_bytes(self.pool, c.Addr(self.input_buf), c.Addr(self.input_buf_len), + c.Addr(self.input_buf_cap), data, data_len) + if self.input_buf_len == 0: + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p7: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p7, 0, 1) + return p7 + s: zinflate.zinflate_stream | t.CPtr = zinflate.zinflate_create(self.pool, self.wbits) + if not s: + set_error(Z_MEM_ERROR, "out of memory") + return None + if self.zdict and self.zdict_len > 0: + s.set_dictionary(self.zdict, self.zdict_len) + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(self.input_buf, self.input_buf_len, + max_length, c.Addr(out), out_len) + if err != 0: + s.destroy() + set_error(Z_DATA_ERROR, "decompression failed") + return None + if s.is_finished: + self.eof = 1 + if s.input_pos < s.input_len: + append_bytes(self.pool, c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), + s.input_data + s.input_pos, + s.input_len - s.input_pos) + self.input_buf_len = 0 + else: + consumed: t.CSizeT = s.input_pos + if consumed < self.input_buf_len: + remaining: t.CSizeT = self.input_buf_len - consumed + string.memmove(self.input_buf, self.input_buf + consumed, remaining) + self.input_buf_len = remaining + else: + self.input_buf_len = 0 + s.destroy() + return out + + def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(stdlib.calloc(1, 1)) + else: + p8: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p8, 0, 1) + return p8 + + def copy(self) -> Decompress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if self.pool == None: + copy_obj: Decompress | t.CPtr = stdlib.calloc(1, Decompress.__sizeof__()) + else: + copy_obj: Decompress | t.CPtr = self.pool.alloc(Decompress.__sizeof__()) + string.memset(copy_obj, 0, Decompress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.pool = self.pool + copy_obj.is_initialized = 1 + copy_obj.eof = self.eof + copy_obj.wbits = self.wbits + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.pool, self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + if self._unused_data and self._unused_data_len > 0: + copy_obj._unused_data = clone_bytes(self.pool, self._unused_data, self._unused_data_len) + copy_obj._unused_data_len = self._unused_data_len + copy_obj._unused_data_cap = self._unused_data_len + if self._unconsumed_tail and self._unconsumed_tail_len > 0: + copy_obj._unconsumed_tail = clone_bytes(self.pool, self._unconsumed_tail, self._unconsumed_tail_len) + copy_obj._unconsumed_tail_len = self._unconsumed_tail_len + copy_obj._unconsumed_tail_cap = self._unconsumed_tail_len + if self.input_buf and self.input_buf_len > 0: + copy_obj.input_buf = clone_bytes(self.pool, self.input_buf, self.input_buf_len) + copy_obj.input_buf_len = self.input_buf_len + copy_obj.input_buf_cap = self.input_buf_cap + else: + if self.pool == None: + copy_obj.input_buf = BYTEPTR(stdlib.calloc(1, 256)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(256)) + string.memset(copy_obj.input_buf, 0, 256) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + return copy_obj + + def delete(self): + if self.pool == None: + stdlib.free(self.zdict) + stdlib.free(self._unused_data) + stdlib.free(self._unconsumed_tail) + stdlib.free(self.input_buf) + stdlib.free(self) + else: + self.pool.free(self.zdict) + self.pool.free(self._unused_data) + self.pool.free(self._unconsumed_tail) + self.pool.free(self.input_buf) + self.pool.free(self) + + def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unused_data_len) + return self._unused_data + + def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unconsumed_tail_len) + return self._unconsumed_tail + +# def eof(self) -> t.CInt: +# # if not obj: return 0 +# return self.eof + + + +def set_error(code: int, msg: str): + global pyzlib_error_code_val, pyzlib_error_msg + pyzlib_error_code_val = code + if msg: + string.strncpy(pyzlib_error_msg, msg, pyzlib_error_msg.__sizeof__() - 1) + pyzlib_error_msg[pyzlib_error_msg.__sizeof__() - 1] = '\0' + else: + pyzlib_error_msg[0] = '\0' + +def clone_bytes(pool: memhub.MemManager | t.CPtr, src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if not src or length == 0: return None + if pool == None: + dst: BYTEPTR = BYTEPTR(stdlib.malloc(length)) + else: + dst: BYTEPTR = BYTEPTR(pool.alloc(length)) + if dst: string.memcpy(dst, src, length) + return dst + +def append_bytes(pool: memhub.MemManager | t.CPtr, buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, + data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: + if not data or data_len == 0: return 0 + needed: t.CSizeT = c.Deref(length) + data_len + if needed > c.Deref(cap): + new_cap: t.CSizeT = c.Deref(cap) * 2 + if new_cap < needed: new_cap = needed + if pool == None: + new_buf: BYTEPTR = BYTEPTR(stdlib.realloc(c.Deref(buf), new_cap)) + else: + new_buf: BYTEPTR = BYTEPTR(pool.alloc(new_cap)) + if new_buf: + string.memcpy(new_buf, c.Deref(buf), c.Deref(length)) + pool.free(c.Deref(buf)) + if not new_buf: return -1 + c.Set(c.Deref(buf), new_buf) + c.Set(c.Deref(cap), new_cap) + string.memcpy(c.Deref(buf) + c.Deref(length), data, data_len) + c.Set(c.Deref(length), c.Deref(length) + data_len) + return 0 + + +def shrink_to_fit(pool: memhub.MemManager | t.CPtr, buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if length == 0: + if pool == None: + stdlib.free(buf) + return BYTEPTR(stdlib.calloc(1, 1)) + else: + pool.free(buf) + p: BYTEPTR = BYTEPTR(pool.alloc(1)) + string.memset(p, 0, 1) + return p + if pool == None: + result: BYTEPTR = BYTEPTR(stdlib.realloc(buf, length)) + return result if result else buf + else: + result: BYTEPTR = BYTEPTR(pool.alloc(length)) + if result: + string.memcpy(result, buf, length) + pool.free(buf) + return result + return buf + + +def runtime_version() -> str: + return ZLIB_VERSION + +def get_error() -> str: + return pyzlib_error_msg + +def get_error_code() -> t.CInt: + return pyzlib_error_code_val + +def clear_error(): + global pyzlib_error_msg, pyzlib_error_code_val + pyzlib_error_msg[0] = '\0' + pyzlib_error_code_val = 0 + +def compress(pool: memhub.MemManager | t.CPtr, data: BYTEPTR, data_len: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: + actual_wbits = -MAX_WBITS + raw_result: UINT8PTR = zdeflate.zdeflate_one_shot(pool, data, data_len, level, actual_wbits, out_len) + if not raw_result: + set_error(Z_DATA_ERROR, "compression failed") + return None + if wbits > MAX_WBITS: + gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8 + if pool == None: + gzip_buf: BYTEPTR = BYTEPTR(stdlib.malloc(gzip_len)) + else: + gzip_buf: BYTEPTR = BYTEPTR(pool.alloc(gzip_len)) + if not gzip_buf: + if pool == None: + stdlib.free(raw_result) + else: + pool.free(raw_result) + set_error(Z_MEM_ERROR, "out of memory") + return None + pos: t.CSizeT = 0 + gzip_buf[pos + 0] = 0x1F + gzip_buf[pos + 1] = 0x8B + gzip_buf[pos + 2] = 0x08 + gzip_buf[pos + 3] = 0x00 + gzip_buf[pos + 4] = 0x00 + gzip_buf[pos + 5] = 0x00 + gzip_buf[pos + 6] = 0x00 + gzip_buf[pos + 7] = 0x00 + gzip_buf[pos + 8] = 0x00 + gzip_buf[pos + 9] = 0xFF + pos += 10 + + string.memcpy(gzip_buf + pos, raw_result, c.Deref(out_len)) + pos += c.Deref(out_len) + if pool == None: + stdlib.free(raw_result) + else: + pool.free(raw_result) + + crc: t.CUInt32T = zchecksum.zchecksum_crc32(data, data_len, 0) + gzip_buf[pos + 0] = (crc) & 0xFF + gzip_buf[pos + 1] = (crc >> 8) & 0xFF + gzip_buf[pos + 2] = (crc >> 16) & 0xFF + gzip_buf[pos + 3] = (crc >> 24) & 0xFF + gzip_buf[pos + 4] = (data_len) & 0xFF + gzip_buf[pos + 5] = (data_len >> 8) & 0xFF + gzip_buf[pos + 6] = (data_len >> 16) & 0xFF + gzip_buf[pos + 7] = (data_len >> 24) & 0xFF + pos += 8 + c.Set(c.Deref(out_len), pos) + return shrink_to_fit(pool, gzip_buf, pos) + return shrink_to_fit(pool, raw_result, c.Deref(out_len)) + + +def decompress(pool: memhub.MemManager | t.CPtr, data: BYTEPTR, data_len: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + result: UINT8PTR = zinflate.zinflate_one_shot(pool, data, data_len, wbits, bufsize, out_len) + if not result: + set_error(Z_DATA_ERROR, "decompression failed") + return None + return shrink_to_fit(pool, result, c.Deref(out_len)) + +def compressobj(pool: memhub.MemManager | t.CPtr, level: t.CInt, method: t.CInt, wbits: t.CInt, + memLevel: t.CInt, strategy: t.CInt, + zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: + if pool == None: + obj: Compress | t.CPtr = stdlib.calloc(1, Compress.__sizeof__()) + else: + obj: Compress | t.CPtr = pool.alloc(Compress.__sizeof__()) + string.memset(obj, 0, Compress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.pool = pool + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + s: zdeflate.zdeflate_stream | t.CPtr = zdeflate.zdeflate_create(pool, level, actual_wbits, memLevel, strategy) + if not s: + if pool == None: + stdlib.free(obj) + else: + pool.free(obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.stream = s + obj.is_initialized = 1 + obj.level = level + obj.method = method + obj.wbits = wbits + obj.memLevel = memLevel + obj.strategy = strategy + if pool == None: + obj.input_buf = BYTEPTR(stdlib.calloc(1, 256)) + else: + obj.input_buf = BYTEPTR(pool.alloc(256)) + string.memset(obj.input_buf, 0, 256) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + obj.header_written = 0 + if zdict and zdict_len > 0: + s.set_dictionary(zdict, zdict_len) + obj.zdict = clone_bytes(pool, zdict, zdict_len) + obj.zdict_len = zdict_len + return obj + + +def decompressobj(pool: memhub.MemManager | t.CPtr, wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: + if pool == None: + obj: Decompress | t.CPtr = stdlib.calloc(1, Decompress.__sizeof__()) + else: + obj: Decompress | t.CPtr = pool.alloc(Decompress.__sizeof__()) + string.memset(obj, 0, Decompress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.pool = pool + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + obj.stream = None + obj.is_initialized = 1 + obj.wbits = actual_wbits + if zdict and zdict_len > 0: + obj.zdict = clone_bytes(pool, zdict, zdict_len) + obj.zdict_len = zdict_len + if pool == None: + obj.input_buf = BYTEPTR(stdlib.calloc(1, 256)) + else: + obj.input_buf = BYTEPTR(pool.alloc(256)) + string.memset(obj.input_buf, 0, 256) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + return obj + +def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_adler32(data, length, UINT32(value)) + +def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_crc32(data, length, UINT32(value)) diff --git a/zlib/zchecksum.vp b/zlib/zchecksum.vp new file mode 100644 index 0000000..d46246f --- /dev/null +++ b/zlib/zchecksum.vp @@ -0,0 +1,89 @@ +from stdint import * +import t, c + + +def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: + a: t.CUInt32T = (init >> 0) & 0xFFFF + b: t.CUInt32T = (init >> 16) & 0xFFFF + if not data or length == 0: + return init + i: t.CSizeT + for i in range(length): + a = (a + data[i]) % 65521 + b = (b + a) % 65521 + return (b << 16) | a + +crc32_table: t.CArray[t.CUInt32T, 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBBBD6, 0xACBCCB40, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7D49, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDede9EC5, 0x47D7897F, 0x30D0B8E9, + 0xBDDA8B1C, 0xCADD8B8A, 0x53D3903A, 0x24D4C2AC, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] + +def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: + crc: t.CUInt32T = init ^ 0xFFFFFFFF + if not data or length == 0: return init + i: t.CSizeT + for i in range(length): + crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8) + return crc ^ 0xFFFFFFFF diff --git a/zlib/zdef.vp b/zlib/zdef.vp new file mode 100644 index 0000000..90c2b79 --- /dev/null +++ b/zlib/zdef.vp @@ -0,0 +1,287 @@ +from stdint import * +import string +import stdlib +import memhub +import t, c + + +# ============================================================ +# DEFLATE / zlib constants +# ============================================================ +ZDEFLATE_WINDOW_BITS: t.CDefine = 15 +ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) +ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) + +ZDEFLATE_MIN_MATCH: t.CDefine = 3 +ZDEFLATE_MAX_MATCH: t.CDefine = 258 + +ZDEFLATE_HASH_BITS: t.CDefine = 15 +ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) +ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) + +ZDEFLATE_MAX_CODES: t.CDefine = 288 +ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 +ZDEFLATE_MAX_BITS: t.CDefine = 15 +ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 + +ZDEFLATE_LIT_COUNT: t.CDefine = 286 +ZDEFLATE_DIST_COUNT: t.CDefine = 30 + +ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 +ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 + +# ============================================================ +# Length / Distance extra bits tables (RFC 1951) +# ============================================================ +zdeflate_len_extra_bits: t.CArray[t.CInt, 29] = [ + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4, + 5, 5, 5, 5, + 0 +] + +zdeflate_len_base: t.CArray[t.CInt, 29] = [ + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, + 19, 23, 27, 31, + 35, 43, 51, 59, + 67, 83, 99, 115, + 131, 163, 195, 227, + 258 +] + +zdeflate_dist_extra_bits: t.CArray[t.CInt, 30] = [ + 0, 0, 0, 0, + 1, 1, + 2, 2, + 3, 3, + 4, 4, + 5, 5, + 6, 6, + 7, 7, + 8, 8, + 9, 9, + 10, 10, + 11, 11, + 12, 12, + 13, 13 +] + +zdeflate_dist_base: t.CArray[t.CInt, 30] = [ + 1, 2, 3, 4, + 5, 7, + 9, 13, + 17, 25, + 33, 49, + 65, 97, + 129, 193, + 257, 385, + 513, 769, + 1025, 1537, + 2049, 3073, + 4097, 6145, + 8193, 12289, + 16385, 24577 +] + +zdeflate_codelen_order: t.CArray[int, 19] = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +] + +# ============================================================ +# Bit writer - writes bits LSB first into a byte buffer +# ============================================================ +@t.Object +class zbit_writer: + pool: memhub.MemManager | t.CPtr + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def __init__(self, pool: memhub.MemManager | t.CPtr): + self.pool = pool + self.cap = 4096 + if pool == None: + self.buf = BYTEPTR(stdlib.malloc(self.cap)) + else: + self.buf = BYTEPTR(pool.alloc(self.cap)) + string.memset(self.buf, 0, self.cap) + self.byte_pos = 0 + self.bit_pos = 0 + + def ensure(self, need: t.CSizeT): + while self.byte_pos + need + 4 >= self.cap: + new_cap: t.CSizeT = self.cap * 2 + if self.pool == None: + new_buf: BYTE | t.CPtr = BYTEPTR(stdlib.realloc(self.buf, new_cap)) + else: + new_buf: BYTE | t.CPtr = BYTEPTR(self.pool.alloc(new_cap)) + if new_buf: + string.memcpy(new_buf, self.buf, self.byte_pos + (self.bit_pos + 7) / 8) + self.pool.free(self.buf) + if not new_buf: return + string.memset(new_buf + self.cap, 0, new_cap - self.cap) + self.buf = new_buf + self.cap = new_cap + + def write_bits(self, value: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits): + if value & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def write_bits_rev(self, code: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits - 1, -1, -1): + if code & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.write_bits(1 if final else 0, 1) + self.write_bits(0, 2) + self.align() + + pos: t.CSizeT = 0 + while pos < length: + block_length: t.CSizeT = length - pos + if block_length > 65535: + block_length = 65535 + n: t.CUInt16T = t.CUInt16T(block_length) + ncomp: t.CUInt16T = ~n + self.write_bits(n, 16) + self.write_bits(ncomp, 16) + + self.ensure(block_length) + i: t.CSizeT = 0 + for i in range(block_length): + self.buf[self.byte_pos] = data[pos + i] + self.byte_pos += 1 + pos += block_length + if pos < length: + self.write_bits(0, 1) + self.write_bits(0, 2) + self.align() + + def write_zlib_header(self, wbits: t.CInt, level: t.CInt): + cinfo: t.CInt = wbits - 8 + if cinfo < 1: cinfo = 1 + if cinfo > 7: cinfo = 7 + cmf: t.CUnsignedChar = t.CUnsignedChar((cinfo << 4) | 8) + + flevel: t.CInt = 0 + if level >= 5: flevel = 3 + elif level >= 3: flevel = 1 + + flg: t.CUnsignedChar = t.CUnsignedChar(flevel << 6) + flg |= t.CUnsignedChar(31 - (cmf * 256 + flg) % 31) + + self.buf[self.byte_pos + 0] = cmf + self.buf[self.byte_pos + 1] = flg + self.byte_pos += 2 + + + def write_gzip_header(self): + self.buf[self.byte_pos + 0] = 0x1F + self.buf[self.byte_pos + 1] = 0x8B + self.buf[self.byte_pos + 2] = 0x08 + self.buf[self.byte_pos + 3] = 0x00 + self.buf[self.byte_pos + 4] = 0x00 + self.buf[self.byte_pos + 5] = 0x00 + self.buf[self.byte_pos + 6] = 0x00 + self.buf[self.byte_pos + 7] = 0x00 + self.buf[self.byte_pos + 8] = 0x00 + self.buf[self.byte_pos + 9] = 0xFF + self.byte_pos += 10 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + + def total(self) -> t.CSizeT: + return self.byte_pos + (1 if (self.bit_pos > 0) else 0) + + def free(self): + if self.pool == None: + stdlib.free(self.buf) + else: + self.pool.free(self.buf) + self.buf = None + self.cap = 0 + self.byte_pos = 0 + self.bit_pos = 0 + + def __del__(self): + self.free() + +# ============================================================ +# Bit reader - reads bits LSB first from a byte buffer +# ============================================================ +@t.Object +class zbit_reader: + buf: BYTE | t.CPtr + length: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def init(self, buf: BYTE | t.CPtr, length: t.CSizeT): + self.buf = buf + self.length = length + self.byte_pos = 0 + self.bit_pos = 0 + + def read_bits(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def read_bits_rev(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits - 1, 0, -1): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + +# ============================================================ +# Memory allocation helper for bare metal +# Can be replaced with custom allocator +# ============================================================ +def zdef_alloc(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> VOIDPTR: + if pool == None: return stdlib.malloc(n) + return pool.alloc(n) +def zdef_free(pool: memhub.MemManager | t.CPtr, p: VOIDPTR): + if pool == None: + stdlib.free(p) + return + pool.free(p) diff --git a/zlib/zdeflate.vp b/zlib/zdeflate.vp new file mode 100644 index 0000000..e79efda --- /dev/null +++ b/zlib/zdeflate.vp @@ -0,0 +1,434 @@ +from stdint import * +import zlib.zchecksum as zchecksum +import zlib.zhuff as zhuff +import zlib.zdef as zdef +import string +import memhub +import t, c + + +@t.Object +class zdeflate_stream: + pool: memhub.MemManager | t.CPtr + writer: zdef.zbit_writer + window: BYTE | t.CPtr + window_pos: t.CInt + window_size: t.CInt + hash_head: t.CInt | t.CPtr + hash_prev: t.CInt | t.CPtr + level: t.CInt + strategy: t.CInt + wbits: t.CInt + is_finished: t.CInt + adler: t.CUInt32T + + def find_match(self, data: BYTE | t.CPtr, data_len: t.CSizeT, + pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: + if pos + 2 >= data_len: return 0 + h: t.CUnsignedInt = zdeflate_hash(data + pos) + chain: t.CInt = self.hash_head[h] + best_len: t.CInt = zdef.ZDEFLATE_MIN_MATCH - 1 + c.Set(c.Deref(best_dist), 0) + max_chain: t.CInt = 128 if (self.level >= 5) else (32 if (self.level >= 2) else 4) + limit: t.CInt = (1 << self.wbits) if (self.wbits > 0) else zdef.ZDEFLATE_WINDOW_SIZE + if limit > zdef.ZDEFLATE_WINDOW_SIZE: + limit = zdef.ZDEFLATE_WINDOW_SIZE + attempts: t.CInt = 0 + while chain >= 0 and attempts < max_chain: + dist: t.CInt = t.CInt(pos) - chain + if dist <= 0 or dist > limit: break + match_len: t.CInt = 0 + max_len: t.CInt = t.CInt(data_len - pos) + if max_len > zdef.ZDEFLATE_MAX_MATCH: + max_len = zdef.ZDEFLATE_MAX_MATCH + while match_len < max_len and data[pos + match_len] == data[chain + match_len]: + match_len += 1 + if match_len > best_len: + best_len = match_len + c.Set(c.Deref(best_dist), dist) + if best_len >= zdef.ZDEFLATE_MAX_MATCH: break + chain = self.hash_prev[chain & zdef.ZDEFLATE_WINDOW_MASK] + if chain <= t.CInt(pos) - limit: break + attempts += 1 + return best_len if (best_len >= zdef.ZDEFLATE_MIN_MATCH) else 0 + + def update_hash(self, data: BYTE | t.CPtr, pos: t.CSizeT): + if pos + 2 < pos: return + h: t.CUnsignedInt = zdeflate_hash(data + pos) + self.hash_prev[pos & zdef.ZDEFLATE_WINDOW_MASK] = self.hash_head[h] + self.hash_head[h] = t.CInt(pos) + + def write_fixed_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(1, 2) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for i in range(match_len): + self.update_hash(data, pos + i) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + def encode_block_data(self, data: UINT8PTR, length: t.CSizeT, + lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr): + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for j in range(match_len): + self.update_hash(data, pos + j) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + + def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_freqs: t.CArray[t.CInt, 288] + dist_freqs: t.CArray[t.CInt, 32] + zdeflate_count_freqs(lit_freqs, dist_freqs, self, data, length) + hlit: t.CInt = 286 + while hlit > 257 and lit_freqs[hlit - 1] == 0: hlit -= 1 + hdist: t.CInt = 30 + while hdist > 1 and dist_freqs[hdist - 1] == 0: hdist -= 1 + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_codes(lit_freqs, hlit, zdef.ZDEFLATE_MAX_BITS) + dist_tree.build_codes(dist_freqs, hdist, zdef.ZDEFLATE_MAX_BITS) + all_lengths: t.CArray[t.CInt, 288 + 32] + for i in range(hlit): all_lengths[i] = lit_tree.codes[i].bits + for i in range(hdist): all_lengths[hlit + i] = dist_tree.codes[i].bits + total_lengths: t.CInt = hlit + hdist + cl_freqs: t.CArray[t.CInt, 19] + zdeflate_count_cl_freqs(all_lengths, total_lengths, cl_freqs) + cl_tree = zhuff.zhuff_tree() + cl_tree.build_codes(cl_freqs, 19, 7) + hclen: int = 19 + while hclen > 4 and cl_tree.codes[zdef.zdeflate_codelen_order[hclen - 1]].bits == 0: hclen -= 1 + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(2, 2) + self.writer.write_bits(hlit - 257, 5) + self.writer.write_bits(hdist - 1, 5) + self.writer.write_bits(hclen - 4, 4) + for j in range(hclen): + self.writer.write_bits(cl_tree.codes[zdef.zdeflate_codelen_order[j]].bits, 3) + zdeflate_write_cl_encoded(all_lengths, total_lengths, c.Addr(self.writer), c.Addr(cl_tree)) + self.encode_block_data(data, length, c.Addr(lit_tree), c.Addr(dist_tree)) + + def compress_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + if self.level == 0: + self.write_stored_block(data, length, final) + elif self.strategy == 4 or length < 128: + self.write_fixed_block(data, length, final) + else: + self.write_dynamic_block(data, length, final) + + def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.writer.stored_block(data, length, final) + + def compress(self, data: UINT8PTR, length: t.CSizeT, + out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if self.is_finished: return -2 + if not data or length == 0: + c.Set(c.Deref(out), None) + c.Set(c.Deref(out_len), 0) + return 0 + self.adler = zchecksum.zchecksum_adler32(data, length, self.adler) + string.memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.memset(self.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + self.compress_block(data, length, 0) + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, c.Deref(out_len)))) + if not c.Deref(out): return -4 + string.memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def flush(self, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if mode == 4: + if not self.is_finished: + if self.level == 0: + self.writer.write_bits(1, 1) + self.writer.write_bits(0, 2) + self.writer.align() + else: + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + self.writer.write_bits(1, 1) + self.writer.write_bits(1, 2) + lit_tree.encode_symbol(256, c.Addr(self.writer)) + self.is_finished = 1 + if self.wbits >= 0: + self.writer.align() + adler: t.CUInt32T = self.adler + self.writer.buf[self.writer.byte_pos + 0] = (adler >> 24) & 0xFF + self.writer.buf[self.writer.byte_pos + 1] = (adler >> 16) & 0xFF + self.writer.buf[self.writer.byte_pos + 2] = (adler >> 8) & 0xFF + self.writer.buf[self.writer.byte_pos + 3] = (adler >> 0) & 0xFF + self.writer.byte_pos += 4 + elif mode == 2 or mode == 3: + self.writer.write_bits(0, 1) + self.writer.write_bits(0, 2) + self.writer.align() + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, c.Deref(out_len)))) + if not c.Deref(out): return -4 + string.memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + string.memcpy(self.window, dict, use) + self.window_size = t.CInt(use) + self.window_pos = t.CInt(use) + self.adler = zchecksum.zchecksum_adler32(dict, length, self.adler) + return 0 + + def copy(self) -> zdeflate_stream | t.CPtr: + z: zdeflate_stream | t.CPtr = zdef.zdef_alloc(self.pool, zdeflate_stream.__sizeof__()) + if not z: return None + string.memcpy(z, self, zdeflate_stream.__sizeof__()) + z.writer.buf = BYTEPTR(zdef.zdef_alloc(self.pool, self.writer.cap)) + if not z.writer.buf: + zdef.zdef_free(self.pool, z) + return None + string.memcpy(z.writer.buf, self.writer.buf, self.writer.cap) + z.window = BYTEPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE)) + z.hash_head = INTPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + z.hash_prev = INTPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not z.window or not z.hash_head or not z.hash_prev: + if z.writer.buf: zdef.zdef_free(self.pool, z.writer.buf) + zdef.zdef_free(self.pool, z) + return None + string.memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + string.memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.memcpy(z.hash_prev, self.hash_prev, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + return z + + def destroy(self): + if self.writer.buf: zdef.zdef_free(self.pool, self.writer.buf) + if self.window: zdef.zdef_free(self.pool, self.window) + if self.hash_head: zdef.zdef_free(self.pool, self.hash_head) + if self.hash_prev: zdef.zdef_free(self.pool, self.hash_prev) + zdef.zdef_free(self.pool, self) + + + + +def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, + s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT): + string.memset(lit_freqs, 0, 288 * int.__sizeof__()) + string.memset(dist_freqs, 0, 32 * int.__sizeof__()) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if s.level > 0 and pos + 2 < length: + match_len = zdeflate_stream.find_match(s, data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_freqs[len_sym] += 1 + dist_freqs[zdeflate_dist_to_symbol(best_dist)] += 1 + for i in range(match_len): + zdeflate_stream.update_hash(s, data, pos + i) + pos += match_len + else: + lit_freqs[data[pos]] += 1 + zdeflate_stream.update_hash(s, data, pos) + pos += 1 + lit_freqs[256] = 1 + + + +def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: + return (t.CUnsignedInt(p[0]) ^ (t.CUnsignedInt(p[1]) << 5) ^ (t.CUnsignedInt(p[2]) << 10)) & zdef.ZDEFLATE_HASH_MASK + + +def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: + for i in range(29): + if length <= zdef.zdeflate_len_base[i] + (1 << zdef.zdeflate_len_extra_bits[i]) - 1: + return 257 + i + return 285 + +def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: + for i in range(30): + if dist <= zdef.zdeflate_dist_base[i] + (1 << zdef.zdeflate_dist_extra_bits[i]) - 1: + return i + return 29 + +def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR): + string.memset(cl_freqs, 0, 19 * int.__sizeof__()) + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_freqs[18] += 1 + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_freqs[17] += 1 + run -= count + else: + cl_freqs[0] += 1 + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_freqs[all_lengths[i]] += 1 + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_freqs[16] += 1 + run -= count + i += run + +def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, + w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr): + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_tree.encode_symbol(18, w) + w.write_bits(count - 11, 7) + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_tree.encode_symbol(17, w) + w.write_bits(count - 3, 3) + run -= count + else: + cl_tree.encode_symbol(0, w) + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_tree.encode_symbol(all_lengths[i], w) + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_tree.encode_symbol(16, w) + w.write_bits(count - 3, 2) + run -= count + i += run + + + +def zdeflate_create(pool: memhub.MemManager | t.CPtr, level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: + n: t.CSizeT = zdeflate_stream.__sizeof__() + s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(pool, n) + if not s: return None + string.memset(s, 0, zdeflate_stream.__sizeof__()) + s.pool = pool + s.writer = zdef.zbit_writer(pool) + s.window = BYTEPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE)) + s.hash_head = INTPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + s.hash_prev = INTPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not s.window or not s.hash_head or not s.hash_prev: + s.destroy() + return None + string.memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + s.level = level + s.wbits = wbits + s.strategy = strategy + s.is_finished = 0 + s.adler = 1 + if wbits > 0: + s.writer.write_zlib_header(wbits, level) + elif wbits == 0: + s.writer.write_zlib_header(15, level) + return s + + +def zdeflate_one_shot(pool: memhub.MemManager | t.CPtr, data: UINT8PTR, length: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zdeflate_stream | t.CPtr = zdeflate_create(pool, level, wbits, 8, 0) + if not s: return None + + string.memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + + s.adler = zchecksum.zchecksum_adler32(data, length, 1) + + if length == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.compress_block(data, length, 1) + + s.is_finished = 1 + + if wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + c.Set(c.Deref(out_len), s.writer.total()) + result: UINT8PTR = UINT8PTR(zdef.zdef_alloc(pool, c.Deref(out_len))) + if result: string.memcpy(result, s.writer.buf, c.Deref(out_len)) + s.destroy() + return result diff --git a/zlib/zhuff.vp b/zlib/zhuff.vp new file mode 100644 index 0000000..4707510 --- /dev/null +++ b/zlib/zhuff.vp @@ -0,0 +1,357 @@ +#include +from stdint import * +import zlib.zdef as zdef +import string +import memhub +import t, c + + +ZHUFF_MAX_CODES: t.CDefine = 288 +ZHUFF_MAX_BITS: t.CDefine = 15 + +class zhuff_code: + code: UINT + bits: t.CInt + +@t.Object +class zhuff_tree: + pool: memhub.MemManager | t.CPtr + codes: t.CArray[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + + def __init__(self): + self.pool = None + + def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt): + lengths: t.CArray[t.CInt, ZHUFF_MAX_CODES] + bl_count: t.CArray[t.CInt, ZHUFF_MAX_BITS + 1] + next_code: t.CArray[UINT, ZHUFF_MAX_BITS + 1] + self.count = count + self.max_bits = max_bits + self.build_code_lengths(lengths, freqs, count, max_bits) + string.memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_lit_tree(self): + lengths: t.CArray[t.CInt, 288] + bl_count: t.CArray[t.CInt, 16] + next_code: t.CArray[t.CUnsignedInt, 16] + self.get_fixed_lit_lengths(lengths) + string.memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(288): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 9 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 288 + self.max_bits = 9 + for i in range(288): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_dist_tree(self): + lengths: t.CArray[t.CInt, 32] + bl_count: t.CArray[t.CInt, 16] + next_code: t.CArray[t.CUnsignedInt, 16] + self.get_fixed_dist_lengths(lengths) + string.memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(32): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 5 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 32 + self.max_bits = 5 + for i in range(32): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def encode_symbol(self, symbol: int, writer: zdef.zbit_writer | t.CPtr): + if symbol < 0 or symbol >= self.count: + return + if self.codes[symbol].bits == 0: + return + writer.write_bits_rev(self.codes[symbol].code, self.codes[symbol].bits) + + + def build_code_lengths(self, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt): + bl_count: t.CArray[t.CInt, ZHUFF_MAX_BITS + 2] + sort_count: t.CInt = 0 + string.memset(bl_count, 0, bl_count.__sizeof__()) + string.memset(lengths, 0, int.__sizeof__() * count) + for i in range(count): + if freqs[i] > 0: + sort_count += 1 + if sort_count == 0: return + if sort_count == 1: + for i in range(count): + if freqs[i] > 0: + lengths[i] = 1 + return + items: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__())) + item_freqs: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__())) + idx: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + items[idx] = i + item_freqs[idx] = freqs[i] + idx += 1 + for i in range(sort_count): + key_item: t.CInt = items[i] + key_freq: t.CInt = item_freqs[i] + j: t.CInt = i - 1 + while j >= 0 and item_freqs[j] > key_freq: + items[j + 1] = items[j] + item_freqs[j + 1] = item_freqs[j] + j -= 1 + items[j + 1] = key_item + item_freqs[j + 1] = key_freq + parent: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count * 2) * int.__sizeof__())) + for i in range(sort_count * 2): + parent[i] = -1 + heap: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count + 1) * int.__sizeof__())) + heap_size: t.CInt = 0 + for i in range(sort_count): + heap[heap_size] = i + heap_size += 1 + pos: t.CInt = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if item_freqs[heap[par]] > item_freqs[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + combined_freq: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count * 2) * int.__sizeof__())) + for i in range(sort_count): + combined_freq[i] = item_freqs[i] + internal: t.CInt = sort_count + while heap_size > 1: + a: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos: t.CInt = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + b: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + if internal >= sort_count * 2 - 1: break + combined_freq[internal] = combined_freq[a] + combined_freq[b] + parent[a] = internal + parent[b] = internal + heap[heap_size] = internal + heap_size += 1 + pos = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if combined_freq[heap[par]] > combined_freq[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + internal += 1 + for i in range(sort_count): + node: t.CInt = i + length: t.CInt = 0 + while parent[node] >= 0: + length += 1 + node = parent[node] + lengths[items[i]] = length + string.memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + overflow: t.CInt = 0 + for i in range(count): + if lengths[i] > max_bits: + overflow += 1 + bl_count[lengths[i]] -= 1 + lengths[i] = max_bits + bl_count[max_bits] += 1 + while overflow > 0: + bits: t.CInt = max_bits - 1 + while bits > 0 and bl_count[bits] == 0: + bits -= 1 + if bits == 0: break + bl_count[bits] -= 1 + bl_count[bits + 1] += 2 + bl_count[max_bits] -= 1 + overflow -= 2 + sorted_items: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__())) + si: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + sorted_items[si] = i + si += 1 + for i in range(si - 1): + for j in range(i + 1, si): + if lengths[sorted_items[i]] < lengths[sorted_items[j]]: + tmp: t.CInt = sorted_items[i] + sorted_items[i] = sorted_items[j] + sorted_items[j] = tmp + sidx: t.CInt = 0 + for bits in range(max_bits, 1, -1): + n: t.CInt = bl_count[bits] + while n > 0 and sidx < si: + lengths[sorted_items[sidx]] = bits + sidx += 1 + n -= 1 + zdef.zdef_free(self.pool, sorted_items) + zdef.zdef_free(self.pool, heap) + zdef.zdef_free(self.pool, parent) + zdef.zdef_free(self.pool, combined_freq) + zdef.zdef_free(self.pool, item_freqs) + zdef.zdef_free(self.pool, items) + + def get_fixed_lit_lengths(self, lengths: INTPTR): + for i in range( 0, 143 + 1): lengths[i] = 8 + for i in range(143 + 1, 255 + 1): lengths[i] = 9 + for i in range(255 + 1, 279 + 1): lengths[i] = 7 + for i in range(279 + 1, 287 + 1): lengths[i] = 8 + + def get_fixed_dist_lengths(self, lengths: INTPTR): + for i in range(32): + lengths[i] = 5 + + def build_tree_from_lengths(self, lengths: INTPTR, count: t.CInt, max_bits: t.CInt): + bl_count: t.CArray[t.CInt, 16] + next_code: t.CArray[t.CUnsignedInt, 16] + + string.memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + + code: UINT = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + + self.count = count + self.max_bits = max_bits + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + +class zhuff_decode_node: + children: t.CArray[t.CInt, 2] + symbol: t.CInt + + +@t.Object +class zhuff_decode_tree: + pool: memhub.MemManager | t.CPtr + nodes: t.CArray[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + + def __init__(self): + self.pool = None + + def build_decode_tree(self, ht: zhuff_tree | t.CPtr): + self.node_count = 1 + self.root = 0 + self.nodes[0].children[0] = -1 + self.nodes[0].children[1] = -1 + self.nodes[0].symbol = -1 + for i in range(ht.count): + if ht.codes[i].bits == 0: continue + node: int = 0 + for bit in range(ht.codes[i].bits - 1, -1, -1): + dir: t.CInt = (ht.codes[i].code >> bit) & 1 + if bit > 0: + # Internal node: traverse or create + if self.nodes[node].children[dir] == -1: + new_node: int = self.node_count + self.node_count += 1 + self.nodes[new_node].children[0] = -1 + self.nodes[new_node].children[1] = -1 + self.nodes[new_node].symbol = -1 + self.nodes[node].children[dir] = new_node + node = self.nodes[node].children[dir] + else: + # Leaf: bit 0 - set symbol on the child + if self.nodes[node].children[dir] == -1: + leaf: int = self.node_count + self.node_count += 1 + self.nodes[leaf].children[0] = -1 + self.nodes[leaf].children[1] = -1 + self.nodes[leaf].symbol = i + self.nodes[node].children[dir] = leaf + else: + self.nodes[self.nodes[node].children[dir]].symbol = i + + def decode_symbol(self, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: + node: int = self.root + while self.nodes[node].symbol == -1: + bit: t.CUnsignedInt + if reader.read_bits(1, c.Addr(bit)) != 0: return -1 + dir: t.CInt = t.CInt(bit) + if self.nodes[node].children[dir] == -1: return -1 + node = self.nodes[node].children[dir] + return self.nodes[node].symbol diff --git a/zlib/zinflate.vp b/zlib/zinflate.vp new file mode 100644 index 0000000..18cc5b4 --- /dev/null +++ b/zlib/zinflate.vp @@ -0,0 +1,456 @@ +from stdint import * +import zlib.zchecksum as zchecksum +import zlib.zdef as zdef +import zlib.zhuff as zhuff +import string +import memhub +import t, c + + +@t.Object +class zinflate_stream: + pool: memhub.MemManager | t.CPtr + reader: zdef.zbit_reader + + window: BYTEPTR + window_pos: t.CInt + window_size: t.CInt + + wbits: t.CInt + is_finished: t.CInt + is_initialized: t.CInt + + header_parsed: t.CInt + is_gzip: t.CInt + + adler: t.CUInt32T + crc: t.CUInt32T + + output: BYTEPTR + output_len: t.CSizeT + output_cap: t.CSizeT + + input_data: t.CConst | BYTEPTR + input_len: t.CSizeT + input_pos: t.CSizeT + + max_length: t.CSizeT + + def __init__(self): + pass + + def output_byte(self, byte: BYTE): + if self.max_length > 0 and self.output_len >= self.max_length: return + + if self.output_len >= self.output_cap: + new_cap: t.CSizeT = self.output_cap * 2 + if new_cap < 256: new_cap = 256 + new_buf: BYTEPTR = BYTEPTR(zdef.zdef_alloc(self.pool, new_cap)) + if not new_buf: return + string.memcpy(new_buf, self.output, self.output_len) + zdef.zdef_free(self.pool, self.output) + self.output = new_buf + self.output_cap = new_cap + self.output[self.output_len] = byte + self.output_len += 1 + self.window[self.window_pos & (zdef.ZDEFLATE_WINDOW_SIZE - 1)] = byte + self.window_pos += 1 + + + def parse_header(self) -> t.CInt: + if self.header_parsed: return 0 + if self.wbits < 0: + self.header_parsed = 1 + self.is_gzip = 0 + return 0 + if self.input_pos + 2 > self.input_len: return -3 + b0: BYTE = self.input_data[self.input_pos] + b1: BYTE = self.input_data[self.input_pos + 1] + if b0 == 0x1F and b1 == 0x8B: + self.is_gzip = 1 + if self.input_pos + 10 > self.input_len: return -3 + self.input_pos += 10 + flg: BYTE = self.input_data[self.input_pos - 6] + if flg & 0x04: + if self.input_pos + 2 > self.input_len: return -3 + xlen: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + self.input_pos += 2 + xlen + if flg & 0x08: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x10: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x02: + self.input_pos += 2 + if self.input_pos > self.input_len: return -3 + else: + self.is_gzip = 0 + if (b0 * 256 + b1) % 31 != 0: return -3 + cm: t.CInt = b0 & 0x0F + if cm != 8: return -3 + self.input_pos += 2 + self.header_parsed = 1 + return 0 + + + def read_bits_from_input(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.input_pos >= self.input_len: return -3 + if self.input_data[self.input_pos] & (UINT(1) << (self.reader.bit_pos)): + val |= (UINT(1) << i) + self.reader.bit_pos += 1 + if self.reader.bit_pos == 8: + self.reader.bit_pos = 0 + self.input_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + + def read_huffman(self, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: + node: int = dt.root + while dt.nodes[node].symbol == -1: + bit: UINT + if self.read_bits_from_input(1, c.Addr(bit)) != 0: return -1 + dir: int = t.CInt(bit) + if dt.nodes[node].children[dir] == -1: return -3 + node = dt.nodes[node].children[dir] + return dt.nodes[node].symbol + + def inflate_block_stored(self) -> t.CInt: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 > self.input_len: return -3 + length: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + nlen: UINT = self.input_data[self.input_pos + 2] | (self.input_data[self.input_pos + 3] << 8) + self.input_pos += 4 + if (length ^ nlen) != 0xFFFF: return -3 + if self.input_pos + length > self.input_len: return -3 + i: t.CUnsignedInt + for i in range(length): + self.output_byte(self.input_data[self.input_pos]) + self.input_pos += 1 + return 0 + + + def inflate_block_fixed(self) -> t.CInt: + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + + lit_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(self.pool, zhuff.zhuff_decode_tree.__sizeof__()) + dist_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(self.pool, zhuff.zhuff_decode_tree.__sizeof__()) + if not lit_dt or not dist_dt: + if lit_dt: zdef.zdef_free(self.pool, lit_dt) + if dist_dt: zdef.zdef_free(self.pool, dist_dt) + return -4 + string.memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + string.memset(dist_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + result: t.CInt = 0 + while True: + if self.max_length > 0 and self.output_len >= self.max_length: break + + sym: t.CInt = self.read_huffman(lit_dt) + if sym < 0: + result = -3 + break + if sym == 256: break + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: + result = -3 + break + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + length += extra_val + + dist_sym: t.CInt = self.read_huffman(dist_dt) + if dist_sym < 0 or dist_sym >= 30: + result = -3 + break + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + dist += extra_val + + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: break + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + zdef.zdef_free(self.pool, lit_dt) + zdef.zdef_free(self.pool, dist_dt) + return result + + + def inflate_block_dynamic(self) -> t.CInt: + hlit_val: UINT + hdist_val: UINT + hclen_val: UINT + if self.read_bits_from_input(5, c.Addr(hlit_val)) != 0: return -3 + if self.read_bits_from_input(5, c.Addr(hdist_val)) != 0: return -3 + if self.read_bits_from_input(4, c.Addr(hclen_val)) != 0: return -3 + + hlit: t.CInt = t.CInt(hlit_val) + 257 + hdist: t.CInt = t.CInt(hdist_val) + 1 + hclen: t.CInt = t.CInt(hclen_val) + 4 + + cl_lengths: t.CArray[t.CInt, 19] + string.memset(cl_lengths, 0, cl_lengths.__sizeof__()) + for i in range(hclen): + len_val: UINT + if self.read_bits_from_input(3, c.Addr(len_val)) != 0: return -3 + cl_lengths[zdef.zdeflate_codelen_order[i]] = t.CInt(len_val) + + cl_tree = zhuff.zhuff_tree() + cl_tree.build_tree_from_lengths(cl_lengths, 19, 7) + + cl_dt = zhuff.zhuff_decode_tree() + cl_dt.build_decode_tree(c.Addr(cl_tree)) + + total: t.CInt = hlit + hdist + all_lengths: t.CInt | t.CPtr = zdef.zdef_alloc(self.pool, total * int.__sizeof__()) + if not all_lengths: return -4 + + idx: t.CInt = 0 + while idx < total: + sym: t.CInt = self.read_huffman(c.Addr(cl_dt)) + if sym < 0 or sym > 18: + zdef.zdef_free(self.pool, all_lengths) + return -3 + if sym < 16: + all_lengths[idx] = sym + idx += 1 + elif sym == 16: + rep: UINT + if self.read_bits_from_input(2, c.Addr(rep)) != 0: + zdef.zdef_free(self.pool, all_lengths) + return -3 + rep += 3 + if idx == 0 or idx + rep > total: + zdef.zdef_free(self.pool, all_lengths) + return -3 + prev: t.CInt = all_lengths[idx - 1] + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = prev + idx += 1 + elif sym == 17: + rep: t.CUnsignedInt + if self.read_bits_from_input(3, c.Addr(rep)) != 0: + zdef.zdef_free(self.pool, all_lengths) + return -3 + rep += 3 + if idx + rep > total: + zdef.zdef_free(self.pool, all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + else: + rep: t.CUnsignedInt + if self.read_bits_from_input(7, c.Addr(rep)) != 0: + zdef.zdef_free(self.pool, all_lengths) + return -3 + rep += 11 + if idx + rep > total: + zdef.zdef_free(self.pool, all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + + lit_lengths: t.CArray[t.CInt, 288] + string.memset(lit_lengths, 0, lit_lengths.__sizeof__()) + for i in range(hlit): + lit_lengths[i] = all_lengths[i] + lit_tree.build_tree_from_lengths(lit_lengths, hlit, zdef.ZDEFLATE_MAX_BITS) + + dist_lengths: t.CArray[t.CInt, 32] + string.memset(dist_lengths, 0, dist_lengths.__sizeof__()) + for i in range(hdist): + dist_lengths[i] = all_lengths[hlit + i] + dist_tree.build_tree_from_lengths(dist_lengths, hdist, zdef.ZDEFLATE_MAX_BITS) + + zdef.zdef_free(self.pool, all_lengths) + + lit_dt = zhuff.zhuff_decode_tree() + dist_dt = zhuff.zhuff_decode_tree() + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + while True: + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + sym: t.CInt = self.read_huffman(c.Addr(lit_dt)) + if sym < 0: return -3 + if sym == 256: return 0 + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: return -3 + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + length += extra_val + dist_sym: t.CInt = self.read_huffman(c.Addr(dist_dt)) + if dist_sym < 0 or dist_sym >= 30: return -3 + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + dist += extra_val + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + def inflate_stream(self) -> t.CInt: + err: t.CInt = self.parse_header() + if err != 0: return err + while not self.is_finished: + bfinal_val: UINT + btype_val: UINT + if self.read_bits_from_input(1, c.Addr(bfinal_val)) != 0: return -3 + if self.read_bits_from_input(2, c.Addr(btype_val)) != 0: return -3 + bfinal: t.CInt = t.CInt(bfinal_val) + btype: t.CInt = t.CInt(btype_val) + if btype == 0: + err = self.inflate_block_stored() + elif btype == 1: + err = self.inflate_block_fixed() + elif btype == 2: + err = self.inflate_block_dynamic() + else: + return -3 + if err != 0: return err + if bfinal: self.is_finished = 1 + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + if self.is_gzip: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 8 <= self.input_len: + self.crc = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 0) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 24)) + self.input_pos += 8 + elif self.wbits >= 0: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 <= self.input_len: + self.adler = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 24) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 0)) + self.input_pos += 4 + return 0 + + def decompress(self, data: UINT8PTR, length: t.CSizeT, + max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if not self.is_initialized: return -2 + self.input_data = data + self.input_len = length + self.input_pos = 0 + self.reader.bit_pos = 0 + self.output_len = 0 + self.max_length = max_length + err: t.CInt = self.inflate_stream() + if err != 0: return err + c.Set(c.Deref(out_len), self.output_len) + if self.output_len == 0: + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, 1))) + else: + dst: UINT8PTR = UINT8PTR(zdef.zdef_alloc(self.pool, self.output_len)) + c.Set(c.Deref(out), dst) + if dst: + string.memcpy(dst, self.output, self.output_len) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + string.memcpy(self.window, dict, use) + self.window_pos = t.CInt(use) + return 0 + + def copy(self) -> zinflate_stream | t.CPtr: + z: zinflate_stream | t.CPtr = zdef.zdef_alloc(self.pool, zinflate_stream.__sizeof__()) + if not z: return None + string.memcpy(z, self, zinflate_stream.__sizeof__()) + z.window = BYTEPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE)) + z.output = BYTEPTR(zdef.zdef_alloc(self.pool, self.output_cap)) + if not z.window or not z.output: + zinflate_stream.destroy(z) + return None + string.memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + string.memcpy(z.output, self.output, self.output_cap) + return z + + def destroy(self): + if not self: return + if self.window: zdef.zdef_free(self.pool, self.window) + if self.output: zdef.zdef_free(self.pool, self.output) + zdef.zdef_free(self.pool, self) + + +def zinflate_one_shot(pool: memhub.MemManager | t.CPtr, data: UINT8PTR, length: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zinflate_stream | t.CPtr = zinflate_create(pool, wbits) + if not s: return None + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(data, length, 0, c.Addr(out), out_len) + s.destroy() + if err != 0: return None + return out + + +def zinflate_create(pool: memhub.MemManager | t.CPtr, wbits: t.CInt) -> zinflate_stream | t.CPtr: + s: zinflate_stream | t.CPtr = zdef.zdef_alloc(pool, zinflate_stream.__sizeof__()) + if not s: return None + string.memset(s, 0, zinflate_stream.__sizeof__()) + s.pool = pool + s.wbits = wbits + s.is_initialized = 1 + s.adler = 1 + s.window = BYTEPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE)) + s.output = BYTEPTR(zdef.zdef_alloc(pool, 256)) + s.output_cap = 256 + s.output_len = 0 + s.max_length = 0 + if not s.window or not s.output: + s.destroy() + return None + return s