从 TransPyC 主项目中分离 VRTE

This commit is contained in:
TermiNexus committed 2026-08-17 11:01:35 +08:00
commit 14ff9d109f
121 files changed
+41596

No files matched your search

+425
View File
@@ -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
+271
View File
@@ -0,0 +1,271 @@
import t, c
import memhub
import string
import json
from stdint import *
# Variant type tags (consistent with _variant.py)
VARIANT_NONE: t.CDefine = 0 # Untyped / null value
VARIANT_INT: t.CDefine = 1 # int (i64)
VARIANT_FLOAT: t.CDefine = 2 # float (f32)
VARIANT_DOUBLE: t.CDefine = 3 # double (f64)
VARIANT_STR: t.CDefine = 4 # str (i8*)
VARIANT_DICT: t.CDefine = 5 # dict*
VARIANT_LIST: t.CDefine = 6 # list*
VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32)
VARIANT_PTR: t.CDefine = 8 # Custom pointer type
# Variant structure size: vtype(i32, 4 bytes) + padding(4 bytes) + ptr(i8*, 8 bytes) = 16 bytes
_VARIANT_SIZE: t.CDefine = 16
class dict:
"""Heap-allocated dynamic dictionary container based on mbuddy allocator.
Key type is fixed to str (i8*), values are stored as Variant (type tag + untyped pointer).
Supports nested dict/list structures and JSON serialization.
Usage:
mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size)
d: dict = dict(mb)
d.set_int("x", 42)
p: t.CPtr = d["x"]
v: int = c.Deref(p)
# Nested dict
inner: dict = dict(mb)
inner.set_int("a", 1)
d.set_dict("sub", inner)
sub: dict = c.Deref(d["sub"])
av: int = c.Deref(sub["a"])
"""
__keys__: t.CPtr
__values__: t.CPtr
__count__: t.CSizeT = 0
__capacity__: t.CSizeT = 8
__mbuddy__: memhub.MemBuddy | t.CPtr
__iter_index__: t.CSizeT = 0
def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr:
# Heap allocation for dict object
return mb.alloc(dict.__sizeof__())
def __init__(self, mb: memhub.MemBuddy | t.CPtr):
self.__mbuddy__ = mb
self.__keys__ = mb.alloc(self.__capacity__ * 8)
self.__values__ = mb.alloc(self.__capacity__ * _VARIANT_SIZE)
def __len__(self) -> t.CSizeT:
return self.__count__
def _find(self, key: str) -> t.CSizeT:
"""Find index of target key; returns __count__ if not found"""
for i in range(self.__count__):
key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + i * 8)
if string.strcmp(key_ptr[0], key) == 0: return i
return self.__count__
def __getitem__(self, key: str) -> t.CPtr:
"""Return untyped pointer to value. Use c.Deref to resolve the actual value.
Example: p: t.CPtr = d["x"]; v: int = c.Deref(p)"""
idx: t.CSizeT = self._find(key)
if idx >= self.__count__: return None
# Variant.ptr is located at offset 8 within Variant structure
val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8)
return val_ptr[0]
def __setitem__(self, key: str, val: t.CNeedPtr):
"""Store value as VARIANT_PTR. Address is automatically resolved via t.CNeedPtr.
Note: Lifecycle of the data pointed to by val is managed by caller.
Use typed methods such as set_int / set_str for persistent storage."""
self._set_variant_raw(key, VARIANT_PTR, val)
def _set_variant_raw(self, key: str, vtype: t.CInt, ptr: t.CPtr):
"""Internal method: store Variant entry (vtype + ptr). No automatic address resolution."""
idx: t.CSizeT = self._find(key)
if idx < self.__count__:
# Update existing key
vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE)
vtype_ptr[0] = vtype
val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8)
val_ptr[0] = ptr
return
if self.__count__ >= self.__capacity__:
new_cap: t.CSizeT = self.__capacity__ * 2
new_keys: t.CPtr = self.__mbuddy__.alloc(new_cap * 8)
new_values: t.CPtr = self.__mbuddy__.alloc(new_cap * _VARIANT_SIZE)
if new_keys is None or new_values is None: return
string.memcpy(new_keys, self.__keys__, self.__count__ * 8)
string.memcpy(new_values, self.__values__, self.__count__ * _VARIANT_SIZE)
self.__keys__ = new_keys
self.__values__ = new_values
self.__capacity__ = new_cap
key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + self.__count__ * 8)
key_ptr[0] = key
vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE)
vtype_ptr[0] = vtype
val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE + 8)
val_ptr[0] = ptr
self.__count__ += 1
# ============================================================
# Typed setters — allocate persistent storage inside __mbuddy__
# ============================================================
def set_int(self, key: str, val: int):
"""Store integer value (VARIANT_INT). Value is copied to persistent storage within __mbuddy__."""
storage: t.CPtr = self.__mbuddy__.alloc(8)
int_ptr: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
int_ptr[0] = val
self._set_variant_raw(key, VARIANT_INT, storage)
def set_str(self, key: str, val: str):
"""Store string value (VARIANT_STR). Raw string pointer is stored directly."""
self._set_variant_raw(key, VARIANT_STR, val)
def set_float(self, key: str, val: float):
"""Store float value (VARIANT_FLOAT). Value is copied to persistent storage within __mbuddy__."""
storage: t.CPtr = self.__mbuddy__.alloc(8)
float_ptr: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
float_ptr[0] = val
self._set_variant_raw(key, VARIANT_FLOAT, storage)
def set_double(self, key: str, val: t.CDouble):
"""Store double value (VARIANT_DOUBLE). Value is copied to persistent storage within __mbuddy__."""
storage: t.CPtr = self.__mbuddy__.alloc(8)
dbl_ptr: t.CDouble | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
dbl_ptr[0] = val
self._set_variant_raw(key, VARIANT_DOUBLE, storage)
def set_dict(self, key: str, val: dict | t.CPtr):
"""Store nested dictionary pointer (VARIANT_DICT)."""
self._set_variant_raw(key, VARIANT_DICT, val)
def set_list(self, key: str, val: t.CPtr):
"""Store nested list pointer (VARIANT_LIST)."""
self._set_variant_raw(key, VARIANT_LIST, val)
def set_bool(self, key: str, val: t.CInt):
"""Store boolean value (VARIANT_BOOL). Value is copied to persistent storage within __mbuddy__."""
storage: t.CPtr = self.__mbuddy__.alloc(8)
bool_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
bool_ptr[0] = val
self._set_variant_raw(key, VARIANT_BOOL, storage)
# ============================================================
# Query methods
# ============================================================
def get_vtype(self, key: str) -> t.CInt:
"""Return Variant type tag associated with specified key."""
idx: t.CSizeT = self._find(key)
if idx >= self.__count__:
return VARIANT_NONE
vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE, t.CPtr)
return vtype_ptr[0]
def get(self, key: str, default: t.CPtr) -> t.CPtr:
"""Return value pointer; return default pointer if key does not exist."""
idx: t.CSizeT = self._find(key)
if idx >= self.__count__:
return default
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8, t.CPtr)
return val_ptr[0]
def contains(self, key: str) -> t.CInt:
"""Check whether target key exists."""
idx: t.CSizeT = self._find(key)
if idx < self.__count__:
return 1
return 0
def __iter__(self) -> dict | t.CPtr:
self.__iter_index__ = 0
return self
def __next__(self) -> str:
if self.__iter_index__ >= self.__count__:
raise StopIteration
idx: t.CSizeT = self.__iter_index__
self.__iter_index__ = idx + 1
key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + idx * 8, t.CPtr)
return key_ptr[0]
# ============================================================
# JSON utilities: serialization / deserialization via includes/json library
# ============================================================
def to_json(self, pool: memhub.MemManager | t.CPtr) -> json.JsonValue | t.CPtr:
"""Convert dict instance to JsonValue object (JSON_OBJECT).
Automatically select corresponding JSON value type according to Variant tag."""
obj: json.JsonValue | t.CPtr = json.object(pool)
i: t.CSizeT = 0
while i < self.__count__:
key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + i * 8, t.CPtr)
vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE, t.CPtr)
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE + 8, t.CPtr)
vt: t.CInt = vtype_ptr[0]
vp: t.CPtr = val_ptr[0]
jv: json.JsonValue | t.CPtr = json.null(pool)
if jv != None:
if vt == VARIANT_INT:
jv.vtype = 2 # JSON_INT
ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.int_val = ip[0]
elif vt == VARIANT_STR:
jv.vtype = 4 # JSON_STRING
jv.str_val = vp
elif vt == VARIANT_BOOL:
jv.vtype = 1 # JSON_BOOL
bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.bool_val = bp[0]
elif vt == VARIANT_FLOAT:
jv.vtype = 3 # JSON_FLOAT
fp: float | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.float_val = fp[0]
elif vt == VARIANT_PTR:
# Fallback: treat raw pointer as integer
jv.vtype = 2 # JSON_INT
ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.int_val = ip[0]
json.object_set(pool, obj, key_ptr[0], jv)
i += 1
return obj
def from_json(self, pool: memhub.MemManager | t.CPtr, root: json.JsonValue | t.CPtr):
"""Populate dict from JsonValue object.
Extract values and store them as matching Variant types based on JSON type tag."""
if root == None:
return
if root.vtype != 6: # JSON_OBJECT
return
cur: json.JsonValue | t.CPtr = root.child
while cur != None:
if cur.key != None:
if cur.vtype == 2: # JSON_INT
storage: t.CPtr = self.__mbuddy__.alloc(8)
ip: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
ip[0] = cur.int_val
self._set_variant_raw(cur.key, VARIANT_INT, storage)
elif cur.vtype == 4: # JSON_STRING
self._set_variant_raw(cur.key, VARIANT_STR, cur.str_val)
elif cur.vtype == 1: # JSON_BOOL
storage: t.CPtr = self.__mbuddy__.alloc(8)
bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
bp[0] = cur.bool_val
self._set_variant_raw(cur.key, VARIANT_BOOL, storage)
elif cur.vtype == 3: # JSON_FLOAT
storage: t.CPtr = self.__mbuddy__.alloc(8)
fp: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
fp[0] = cur.float_val
self._set_variant_raw(cur.key, VARIANT_FLOAT, storage)
cur = cur.next
def dumps(self, pool: memhub.MemManager | t.CPtr) -> str:
"""Serialize dict to JSON string."""
obj: json.JsonValue | t.CPtr = self.to_json(pool)
return json.write(pool, obj, False)
def loads(self, pool: memhub.MemManager | t.CPtr, json_str: str):
"""Parse JSON string and populate dict instance."""
root: json.JsonValue | t.CPtr = json.parse(pool, json_str)
self.from_json(pool, root)
+320
View File
@@ -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
+90
View File
@@ -0,0 +1,90 @@
import t, c
import memhub
import string
from stdint import *
class list[T]:
"""Heap-allocated dynamic list container backed by memhub.MemManager polymorphic allocator.
Usage:
pool: memhub.MemManager = memhub.MemBuddy(arena, arena_size)
nums: list[int] = list[int](pool)
nums.append(42)
x: int = nums.get(0)
For pointer types (e.g. AST | t.CPtr), pass elem_size=8 to avoid object slicing:
lst: list[AST | t.CPtr] = list[AST | t.CPtr](pool, 8)
"""
__data__: t.CVoid | t.CPtr
__count__: t.CSizeT
__capacity__: t.CSizeT
__pool__: memhub.MemManager | t.CPtr
__elem_size__: t.CSizeT
__iter_index__: t.CSizeT
def __new__(self, pool: memhub.MemManager | t.CPtr, elem_size: t.CSizeT = 0):
ret = pool.alloc(48)
return ret
def __init__(self, pool: memhub.MemManager | t.CPtr, elem_size: t.CSizeT = 0):
self.__pool__ = pool
self.__count__ = 0
self.__capacity__ = 8
if elem_size == 0:
self.__elem_size__ = T.__sizeof__()
else:
self.__elem_size__ = elem_size
self.__data__ = pool.alloc(self.__capacity__ * self.__elem_size__)
self.__iter_index__ = 0
def __len__(self) -> t.CSizeT:
return self.__count__
def append(self, item: T):
if self.__count__ >= self.__capacity__:
new_cap: t.CSizeT = self.__capacity__ * 2
new_data: t.CPtr = self.__pool__.alloc(new_cap * self.__elem_size__)
if new_data == None: return
string.memcpy(new_data, self.__data__, self.__count__ * self.__elem_size__)
self.__data__ = new_data
self.__capacity__ = new_cap
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + self.__count__ * self.__elem_size__)
elem_ptr[0] = item
self.__count__ += 1
def get(self, index: t.CSizeT) -> T:
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__)
return elem_ptr[0]
def __getitem__(self, index: t.CSizeT) -> T:
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__)
return elem_ptr[0]
def set(self, index: t.CSizeT, value: T):
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__)
elem_ptr[0] = value
def __setitem__(self, index: t.CSizeT, value: T):
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__)
elem_ptr[0] = value
def pop(self) -> T:
self.__count__ -= 1
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + self.__count__ * self.__elem_size__)
return elem_ptr[0]
def clear(self):
self.__count__ = 0
def __iter__(self) -> list[T] | t.CPtr:
self.__iter_index__ = 0
return self
def __next__(self) -> T:
if self.__iter_index__ >= self.__count__:
raise StopIteration
idx: t.CSizeT = self.__iter_index__
self.__iter_index__ = idx + 1
elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + idx * self.__elem_size__)
return elem_ptr[0]
+64
View File
@@ -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
+75
View File
@@ -0,0 +1,75 @@
import t, c
from stdint import *
from w32.win32process import TlsAlloc, TlsGetValue, TlsSetValue
import stdlib
import stdio
import string
# Maximum provider stack depth (compiler verifies sufficiency; increase if needed)
_MAX_PROVIDER_DEPTH: t.CDefine = 32
@t.Object
class _ProviderStack:
"""Provider stack, stores pairs of field names and pointers."""
names: t.CArray[VOIDPTR, 32]
ptrs: t.CArray[VOIDPTR, 32]
top: UINT64
# TLS index (global; all threads share the same index)
_tls_index: ULONG = 0
@t.TLS
def _init_tls():
"""Initialize TLS index (executes once; subsequent calls are skipped)."""
global _tls_index
# 双保险:TPV 已正式实现 @t.TLS(函数级一次性守卫,首次执行后置
# __tls_init_done 标志,后续调用直接返回),此判重守卫保留以兼容
# 尚未重建的旧 TPV.exe。_tls_index 初始为 0(TlsAlloc 成功不会返回 0)。
if _tls_index == 0:
_tls_index = TlsAlloc()
def _get_stack() -> _ProviderStack | t.CPtr:
"""Obtain current thread's provider stack. Allocate one if none exists."""
_init_tls()
stack: _ProviderStack | t.CPtr = TlsGetValue(_tls_index)
if stack == None:
stack = stdlib.malloc(_ProviderStack.__sizeof__())
string.memset(stack, 0, _ProviderStack.__sizeof__())
TlsSetValue(_tls_index, stack)
return stack
def _push_provider(field_name: str, ptr: t.CPtr):
"""Push a provider (field_name, ptr) onto the stack."""
stack: _ProviderStack | t.CPtr = _get_stack()
if stack.top >= _MAX_PROVIDER_DEPTH:
stdio.printf("[with] ERROR: provider stack overflow (depth=%lu, max=%d), field '%s' not injected\n", stack.top, _MAX_PROVIDER_DEPTH, field_name)
return
stack.names[stack.top] = field_name
stack.ptrs[stack.top] = ptr
stack.top = stack.top + 1
def _pop_provider():
"""Pop the top provider entry from the stack."""
stack: _ProviderStack | t.CPtr = _get_stack()
if stack.top > 0:
stack.top = stack.top - 1
def _find_provider(field_name: str) -> t.CPtr:
"""Search for matching field_name starting from stack top.
Return associated pointer, or NULL if no match found."""
stack: _ProviderStack | t.CPtr = _get_stack()
for i in range(stack.top - 1, -1, -1):
# 字段名用 strcmp 内容比较:编译器对每次 create_global_string 生成
# 独立的字符串常量(TPV 不去重),push/find 的指针地址不同,
# 指针 == 永假会导致 provider 匹配失败(__mbuddy__ 注入不上)。
if string.strcmp((str)(stack.names[i]), field_name) == 0:
return stack.ptrs[i]
return None
+460
View File
@@ -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))
+153
View File
@@ -0,0 +1,153 @@
import t, c
def cli():
c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])
def sti():
c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY])
def hlt():
c.Asm("hlt", [t.ASM_DESCR.CLOBBER_MEMORY])
def nop():
c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY])
def pause():
c.Asm("pause", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def inb(port: t.CUInt16T) -> t.CUInt8T:
value: t.CUInt32T
c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
in al, dx
movzx eax, al""",
out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)],
op =[t.ASM_DESCR.CLOBBER_RDX])
return t.CUInt8T(value)
def outb(port: t.CUInt16T, value: t.CUInt8T):
c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)}
out dx, al""",
op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX])
def inw(port: t.CUInt16T) -> t.CUInt16T:
value: t.CUInt32T
c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
in ax, dx
movzx eax, ax""",
out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)],
op =[t.ASM_DESCR.CLOBBER_RDX])
return t.CUInt16T(value)
def outw(port: t.CUInt16T, value: t.CUInt16T):
c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)}
out dx, ax""",
op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX])
def inl(port: t.CUInt16T) -> t.CUInt32T:
value: t.CUInt32T
c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
in eax, dx""",
out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)],
op =[t.ASM_DESCR.CLOBBER_RDX])
return value
def outl(port: t.CUInt16T, value: t.CUInt32T):
c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
out dx, eax""",
op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX])
def io_wait():
c.Asm(f"mov dx, 0x80; out dx, al",
op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_DX])
def pushall() -> t.CInline | t.CVoid:
c.Asm(f"""
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15""",
[t.ASM_DESCR.CLOBBER_MEMORY]
)
def popall() -> t.CInline | t.CVoid:
c.Asm(f"""
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax""",
[t.ASM_DESCR.CLOBBER_MEMORY]
)
def cpu_switch_context(old_stack: t.CUInt64T | t.CPtr, new_stack: t.CUInt64T):
c.Asm(f"""
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov [{c.AsmInp(old_stack, t.ASM_DESCR.REG_ANY)}], rsp
mov rsp, {c.AsmInp(new_stack, t.ASM_DESCR.REG_ANY)}
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
def BSSClean():
c.Asm(
"lea rdi, [rip + __bss_start]\n"
"lea rcx, [rip + __bss_end]\n"
"sub rcx, rdi\n"
"xor eax, eax\n"
"cld\n"
"rep stosb",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX]
)
+115
View File
@@ -0,0 +1,115 @@
import t, c
from stdint import *
import memhub
import string
# Import submodule
from .tokens import (
Token, TokenType, Keyword, TokOp, _init_tables,
)
# Common Section: Base Classes, Enums, Constants, Helper Functions, Dump
from .base import (
AST, Stmt, ExprNode, ASTKind, ASTCtx, OpKind, ASTFlag,
# Constants
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR,
# Helper Functions
_init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list,
_binop_from_op, _augop_from_op, _cmpop_from_op,
_emit, _emit_str, _emit_int, _dump_list,
dump, _op_name,
)
# Statement Nodes: Module, Expression, Interactive, FunctionType
from .stmts import (
# Module Layer
Module, Expression, Interactive, FunctionType,
# Statement
FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign,
For, While, If, With, Raise, Try, Assert, Global, Nonlocal,
Pass, Break, Continue, Expr, Import, ImportFrom, Match,
)
# Expression Nodes: BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set
from .exprs import (
# Expression Layer
BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set,
ListComp, SetComp, DictComp, GeneratorExp,
Await, Yield, YieldFrom, FormattedValue, JoinedStr,
Constant, NamedExpr, Attribute, Subscript, Starred, Name,
List, Tuple, Slice,
Call, Compare, OpNode,
)
# Auxiliary Nodes
from .astaux import (
ExceptHandler, Arguments, Arg, Keyword, Alias, WithItem,
Comprehension,
)
# Pattern Matching
from .match import (
MatchCase, MatchValue, MatchSingleton, MatchSequence,
MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr,
)
# from .visitor import ASTVisitor
from .lexer import Lexer, _lexer_init, tokenize, new_lexer
from .parser import Parser, _parser_init, parse_tokens, new_parser
from .parser import _parse_test
from .parser import _dbg_lookup_lit_val, _dbg_lit_found
from .parser import get_parse_err_line, get_parse_err_col, get_parse_err_msg
# ============================================================
# Global Memory Pool Pointer (follows project rules: declare _mbuddy)
# User initializes in main: ast._mbuddy = memhub.MemBuddy(arena, size)
# ============================================================
_mbuddy: memhub.MemBuddy | t.CPtr
# ============================================================
# Common API: parse
# ============================================================
def parse(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr:
"""Parse Python source code, return the AST Module node.
Parameters:
src: NUL source code string, terminated with NUL
pool: memhub.MemManager instance, to allocate AST nodes
Returns:
AST Module node, or None
"""
if src is None or pool is None:
return None
_init_tables(pool)
lx: Lexer | t.CPtr = new_lexer(pool)
if lx is None:
return None
_lexer_init(lx, src, pool)
tokens: Token | t.CPtr = tokenize(lx)
if tokens is None:
return None
tree: AST | t.CPtr = parse_tokens(pool, tokens)
return tree
def parse_expression(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr:
"""Parse a single expression, return the Expression node.
Parameters:
src: NUL expression string, terminated with NUL
pool: memhub.MemManager instance, to allocate AST nodes
Returns:
Expression node, or None
"""
if src is None or pool is None:
return None
_init_tables(pool)
lx: Lexer | t.CPtr = new_lexer(pool)
if lx is None: return None
_lexer_init(lx, src, pool)
tokens: Token | t.CPtr = tokenize(lx)
if tokens is None: return None
ps: Parser | t.CPtr = new_parser(pool)
if ps is None: return None
_parser_init(ps, tokens, pool)
body: AST | t.CPtr = _parse_test(ps)
return Expression(pool, body)
+337
View File
@@ -0,0 +1,337 @@
import t, c
from stdint import *
import memhub
import string
from .base import (
AST, ASTKind,
_init_ast, _copy_str, _set_parent_list,
_emit, _emit_str, _emit_int, _dump_list,
)
# ============================================================
# ExceptHandler Node
# ============================================================
class ExceptHandler(AST):
"""ExceptHandler(type: AST, name: str)"""
type: AST | t.CPtr
name: str
def __new__(self, pool: memhub.MemManager | t.CPtr,
type: AST | t.CPtr, name: str):
ptr: ExceptHandler | t.CPtr = pool.alloc(ExceptHandler.__sizeof__())
if ptr:
string.memset(ptr, 0, ExceptHandler.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
type: AST | t.CPtr, name: str):
_init_ast(self, pool, 0, 0)
self.type = type
self.name = _copy_str(pool, name)
def kind(self) -> t.CInt:
return ASTKind.ExceptHandler
def type_name(self) -> str:
return "ExceptHandler"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "ExceptHandler(type=")
if self.type is not None:
pos = self.type.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ", name='")
pos = _emit_str(buf, size, pos, self.name)
pos = _emit(buf, size, pos, "', body=")
pos = _dump_list(self.children, buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# Arguments Node
# ============================================================
class Arguments(AST):
"""Arguments(args: list[AST | CPtr], vararg: AST, kwarg: AST,
defaults: list[AST | CPtr], kw_defaults: list[AST | CPtr])"""
args: list[AST | t.CPtr] | t.CPtr
vararg: AST | t.CPtr
kwarg: AST | t.CPtr
defaults: list[AST | t.CPtr] | t.CPtr
kw_defaults: list[AST | t.CPtr] | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
args: list[AST | t.CPtr] | t.CPtr,
vararg: AST | t.CPtr, kwarg: AST | t.CPtr,
defaults: list[AST | t.CPtr] | t.CPtr,
kw_defaults: list[AST | t.CPtr] | t.CPtr):
ptr: Arguments | t.CPtr = pool.alloc(Arguments.__sizeof__())
if ptr:
string.memset(ptr, 0, Arguments.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
args: list[AST | t.CPtr] | t.CPtr,
vararg: AST | t.CPtr, kwarg: AST | t.CPtr,
defaults: list[AST | t.CPtr] | t.CPtr,
kw_defaults: list[AST | t.CPtr] | t.CPtr):
_init_ast(self, pool, 0, 0)
self.args = args
self.vararg = vararg
self.kwarg = kwarg
self.defaults = defaults
self.kw_defaults = kw_defaults
_set_parent_list(args, self)
_set_parent_list(defaults, self)
_set_parent_list(kw_defaults, self)
def kind(self) -> t.CInt:
return ASTKind.Arguments
def type_name(self) -> str:
return "Arguments"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "Arguments(args=")
pos = _dump_list(self.args, buf, size, pos)
pos = _emit(buf, size, pos, ", vararg=")
if self.vararg is not None:
pos = self.vararg.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ", kwarg=")
if self.kwarg is not None:
pos = self.kwarg.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ", defaults=")
pos = _dump_list(self.defaults, buf, size, pos)
pos = _emit(buf, size, pos, ", kw_defaults=")
pos = _dump_list(self.kw_defaults, buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# Arg Node
# ============================================================
class Arg(AST):
"""Arg(arg: str, annotation: AST)"""
arg: str
annotation: AST | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
arg: str, annotation: AST | t.CPtr):
ptr: Arg | t.CPtr = pool.alloc(Arg.__sizeof__())
if ptr:
string.memset(ptr, 0, Arg.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
arg: str, annotation: AST | t.CPtr):
_init_ast(self, pool, 0, 0)
self.arg = _copy_str(pool, arg)
self.annotation = annotation
def kind(self) -> t.CInt:
return ASTKind.Arg
def type_name(self) -> str:
return "Arg"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "Arg(arg='")
pos = _emit_str(buf, size, pos, self.arg)
pos = _emit(buf, size, pos, "', annotation=")
if self.annotation is not None:
pos = self.annotation.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# Keyword Node
# ============================================================
class Keyword(AST):
"""Keyword(arg: str, value: AST)"""
arg: str
value: AST | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
arg: str, value: AST | t.CPtr):
ptr: Keyword | t.CPtr = pool.alloc(Keyword.__sizeof__())
if ptr:
string.memset(ptr, 0, Keyword.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
arg: str, value: AST | t.CPtr):
_init_ast(self, pool, 0, 0)
self.arg = _copy_str(pool, arg)
self.value = value
def kind(self) -> t.CInt:
return ASTKind.Keyword
def type_name(self) -> str:
return "Keyword"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "Keyword(arg='")
pos = _emit_str(buf, size, pos, self.arg)
pos = _emit(buf, size, pos, "', value=")
if self.value is not None:
pos = self.value.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# Alias Node
# ============================================================
class Alias(AST):
"""Alias(name: str, asname: str)"""
name: str
asname: str
def __new__(self, pool: memhub.MemManager | t.CPtr,
name: str, asname: str):
ptr: Alias | t.CPtr = pool.alloc(Alias.__sizeof__())
if ptr:
string.memset(ptr, 0, Alias.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
name: str, asname: str):
_init_ast(self, pool, 0, 0)
self.name = _copy_str(pool, name)
self.asname = _copy_str(pool, asname)
def kind(self) -> t.CInt:
return ASTKind.Alias
def type_name(self) -> str:
return "Alias"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "Alias(name='")
pos = _emit_str(buf, size, pos, self.name)
pos = _emit(buf, size, pos, "', asname='")
pos = _emit_str(buf, size, pos, self.asname)
pos = _emit(buf, size, pos, "')")
return pos
# ============================================================
# WithItem Node
# ============================================================
class WithItem(AST):
"""WithItem(context_expr: AST, optional_vars: AST)"""
context_expr: AST | t.CPtr
optional_vars: AST | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr):
ptr: WithItem | t.CPtr = pool.alloc(WithItem.__sizeof__())
if ptr:
string.memset(ptr, 0, WithItem.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr):
_init_ast(self, pool, 0, 0)
self.context_expr = context_expr
self.optional_vars = optional_vars
def kind(self) -> t.CInt:
return ASTKind.WithItem
def type_name(self) -> str:
return "WithItem"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "WithItem(context_expr=")
if self.context_expr is not None:
pos = self.context_expr.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ", optional_vars=")
if self.optional_vars is not None:
pos = self.optional_vars.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# Comprehension Node
# ============================================================
class Comprehension(AST):
"""Comprehension(target: AST, iter: AST, ifs: list[AST | CPtr], is_async: CInt)"""
target: AST | t.CPtr
iter: AST | t.CPtr
ifs: list[AST | t.CPtr] | t.CPtr
is_async: t.CInt
def __new__(self, pool: memhub.MemManager | t.CPtr,
target: AST | t.CPtr, iter: AST | t.CPtr,
ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt):
ptr: Comprehension | t.CPtr = pool.alloc(Comprehension.__sizeof__())
if ptr:
string.memset(ptr, 0, Comprehension.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
target: AST | t.CPtr, iter: AST | t.CPtr,
ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt):
_init_ast(self, pool, 0, 0)
self.target = target
self.iter = iter
self.ifs = ifs
self.is_async = is_async
_set_parent_list(ifs, self)
def kind(self) -> t.CInt:
return ASTKind.Comprehension
def type_name(self) -> str:
return "Comprehension"
def dump(self, buf: bytes, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "Comprehension(target=")
if self.target is not None:
pos = self.target.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ", iter=")
if self.iter is not None:
pos = self.iter.dump(buf, size, pos)
else:
pos = _emit(buf, size, pos, "None")
pos = _emit(buf, size, pos, ", ifs=")
pos = _dump_list(self.ifs, buf, size, pos)
pos = _emit(buf, size, pos, ", is_async=")
pos = _emit_int(buf, size, pos, t.CInt64T(self.is_async))
pos = _emit(buf, size, pos, ")")
return pos
+504
View File
@@ -0,0 +1,504 @@
import t, c
from stdint import *
import memhub
import string
import viperlib
from .tokens import TokOp
# ============================================================
# ASTKind - Node type enum (kind() virtual function return value)
# ============================================================
class ASTKind(t.CEnum):
# Core 15 nodes
Module: t.State
FunctionDef: t.State
ClassDef: t.State
Assign: t.State
If: t.State
For: t.State
While: t.State
Return: t.State
Expr: t.State
Name: t.State
Constant: t.State
BinOp: t.State
UnaryOp: t.State
Call: t.State
Compare: t.State
# Module Layer
Expression: t.State
Interactive: t.State
FunctionType: t.State
# Statement
Delete: t.State
AugAssign: t.State
AnnAssign: t.State
With: t.State
Raise: t.State
Try: t.State
Assert: t.State
Global: t.State
Nonlocal: t.State
Pass: t.State
Break: t.State
Continue: t.State
Import: t.State
ImportFrom: t.State
Match: t.State
# Expression Layer
BoolOp: t.State
Lambda: t.State
IfExp: t.State
Dict: t.State
Set: t.State
ListComp: t.State
SetComp: t.State
DictComp: t.State
GeneratorExp: t.State
Await: t.State
Yield: t.State
YieldFrom: t.State
FormattedValue: t.State
JoinedStr: t.State
Attribute: t.State
Subscript: t.State
Starred: t.State
List: t.State
Tuple: t.State
Slice: t.State
NamedExpr: t.State
# Auxiliary Nodes
ExceptHandler: t.State
Arguments: t.State
Arg: t.State
Keyword: t.State
Alias: t.State
WithItem: t.State
Comprehension: t.State
OpNode: t.State
# Pattern Matching
MatchCase: t.State
MatchValue: t.State
MatchSingleton: t.State
MatchSequence: t.State
MatchMapping: t.State
MatchClass: t.State
MatchStar: t.State
MatchAs: t.State
MatchOr: t.State
# ============================================================
# ASTCtx - Name context (Load/Store/Del)
# ============================================================
class ASTCtx(t.CEnum):
Load: t.State
Store: t.State
Del: t.State
# ============================================================
# OpKind - Operator enum (BinOp/UnaryOp/Compare)
# ============================================================
class OpKind(t.CEnum):
# Binary arithmetic operators
Add: t.State
Sub: t.State
Mult: t.State
MatMult: t.State
Div: t.State
Mod: t.State
Pow: t.State
LShift: t.State
RShift: t.State
BitOr: t.State
BitXor: t.State
BitAnd: t.State
FloorDiv: t.State
# Boolean operators
And: t.State
Or: t.State
# Comparison operators
Eq: t.State
Ne: t.State
Lt: t.State
Le: t.State
Gt: t.State
Ge: t.State
Is: t.State
IsNot: t.State
In: t.State
NotIn: t.State
# Unary operators
Not: t.State
UAdd: t.State
USub: t.State
Invert: t.State
# None
NoneOp: t.State
# Constant subtype identifiers
CONST_INT: t.CDefine = 1
CONST_FLOAT: t.CDefine = 2
CONST_STR: t.CDefine = 3
CONST_BOOL: t.CDefine = 4
CONST_NONE: t.CDefine = 5
CONST_CHAR: t.CDefine = 6
# Node flags
FLAG_IS_ASYNC: t.CDefine = 1
FLAG_SIMPLE: t.CDefine = 2
FLAG_HAS_STAR: t.CDefine = 4
FLAG_IS_EXTERN: t.CDefine = 8
# ============================================================
# ASTFlag - Node flags enum
# ============================================================
class ASTFlag(t.CEnum):
IsAsync: t.State
Simple: t.State
HasStar: t.State
# ============================================================
# Helper Functions
# ============================================================
def _copy_str(pool: memhub.MemManager | t.CPtr, src: str) -> str:
"""Allocate and copy a C string from pool."""
if src is None: return None
slen: t.CSizeT = string.strlen(src)
buf: str = pool.alloc(slen + 1)
if buf is None: return None
string.memcpy(buf, src, slen + 1)
return buf
def _set_pos(node: AST | t.CPtr, lineno: t.CInt, col_offset: t.CInt,
end_lineno: t.CInt, end_col_offset: t.CInt):
if node is None: return
node.lineno = lineno
node.col_offset = col_offset
node.end_lineno = end_lineno
node.end_col_offset = end_col_offset
def _inherit_pos(node: AST | t.CPtr, ref: AST | t.CPtr):
if node is None or ref is None: return
node.lineno = ref.lineno
node.col_offset = ref.col_offset
node.end_lineno = ref.end_lineno
node.end_col_offset = ref.end_col_offset
def _init_ast(node: AST | t.CPtr, pool: memhub.MemManager | t.CPtr,
lineno: t.CInt, col: t.CInt):
"""Initialize AST base fields."""
node.parent = None
node.pool = pool
node.lineno = lineno
node.col_offset = col
node.end_lineno = lineno
node.end_col_offset = col
node.children = None
def _set_parent_list(lst: list[AST | t.CPtr] | t.CPtr, parent: AST | t.CPtr):
"""Set list children parent pointers."""
if lst is None: return
n: t.CSizeT = lst.__len__()
i: t.CSizeT = 0
while i < n:
child: AST | t.CPtr = lst.get(i)
if child is not None:
child.parent = parent
i += 1
def _append_child(lst: list[AST | t.CPtr] | t.CPtr, node: AST | t.CPtr,
pool: memhub.MemManager | t.CPtr):
"""Append child nodes to a list (module-level function, to avoid conflicts with the AST.append method name).
Call this function within the AST.append method to bypass the compiler mistaking list.append for a virtual function call to AST.append when doing type inference."""
if lst is None or node is None:
return
lst.append(node)
# ============================================================
# Operator Mapping: TokOp -> OpKind
# ============================================================
def _binop_from_op(op_id: t.CInt) -> t.CInt:
if op_id == TokOp.Plus: return OpKind.Add
if op_id == TokOp.Minus: return OpKind.Sub
if op_id == TokOp.Star: return OpKind.Mult
if op_id == TokOp.At: return OpKind.MatMult
if op_id == TokOp.Slash: return OpKind.Div
if op_id == TokOp.Percent: return OpKind.Mod
if op_id == TokOp.StarStar: return OpKind.Pow
if op_id == TokOp.LtLt: return OpKind.LShift
if op_id == TokOp.GtGt: return OpKind.RShift
if op_id == TokOp.VBar: return OpKind.BitOr
if op_id == TokOp.Caret: return OpKind.BitXor
if op_id == TokOp.Amp: return OpKind.BitAnd
if op_id == TokOp.DSlash: return OpKind.FloorDiv
return OpKind.NoneOp
def _augop_from_op(op_id: t.CInt) -> t.CInt:
if op_id == TokOp.PlusEq: return OpKind.Add
if op_id == TokOp.MinusEq: return OpKind.Sub
if op_id == TokOp.StarEq: return OpKind.Mult
if op_id == TokOp.AtEq: return OpKind.MatMult
if op_id == TokOp.SlashEq: return OpKind.Div
if op_id == TokOp.PercentEq: return OpKind.Mod
if op_id == TokOp.StarEqEq: return OpKind.Pow
if op_id == TokOp.LtLtEq: return OpKind.LShift
if op_id == TokOp.GtGtEq: return OpKind.RShift
if op_id == TokOp.VBarEq: return OpKind.BitOr
if op_id == TokOp.CaretEq: return OpKind.BitXor
if op_id == TokOp.AmpEq: return OpKind.BitAnd
if op_id == TokOp.DSlashEq: return OpKind.FloorDiv
return OpKind.NoneOp
def _cmpop_from_op(op_id: t.CInt) -> t.CInt:
if op_id == TokOp.EqEq: return OpKind.Eq
if op_id == TokOp.ExclaimEq: return OpKind.Ne
if op_id == TokOp.Less: return OpKind.Lt
if op_id == TokOp.LessEq: return OpKind.Le
if op_id == TokOp.Greater: return OpKind.Gt
if op_id == TokOp.GreaterEq: return OpKind.Ge
return OpKind.NoneOp
# ============================================================
# dump Helper Functions
# ============================================================
def _emit(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""Append literal to buf+pos."""
if buf is None or pos >= size:
return pos
cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos)
rem: t.CSizeT = size - pos
n: t.CInt = viperlib.snprintf(cur, rem, "%s", text)
if n < 0:
return pos
return pos + t.CSizeT(n)
def _emit_str(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""Append a string value to buf pos (using %s format)"""
if buf is None or pos >= size:
return pos
cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos)
rem: t.CSizeT = size - pos
n: t.CInt = viperlib.snprintf(cur, rem, "%s", text)
if n < 0:
return pos
return pos + t.CSizeT(n)
def _emit_int(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
val: t.CInt64T) -> t.CSizeT:
"""Append an integer value to buf pos (using %lld format)."""
if buf is None or pos >= size:
return pos
cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos)
rem: t.CSizeT = size - pos
n: t.CInt = viperlib.snprintf(cur, rem, "%lld", val)
if n < 0:
return pos
return pos + t.CSizeT(n)
def _op_name(op: t.CInt) -> str:
"""Return the string name of an OpKind."""
if op == OpKind.Add: return "Add"
if op == OpKind.Sub: return "Sub"
if op == OpKind.Mult: return "Mult"
if op == OpKind.MatMult: return "MatMult"
if op == OpKind.Div: return "Div"
if op == OpKind.Mod: return "Mod"
if op == OpKind.Pow: return "Pow"
if op == OpKind.LShift: return "LShift"
if op == OpKind.RShift: return "RShift"
if op == OpKind.BitOr: return "BitOr"
if op == OpKind.BitXor: return "BitXor"
if op == OpKind.BitAnd: return "BitAnd"
if op == OpKind.FloorDiv: return "FloorDiv"
if op == OpKind.And: return "And"
if op == OpKind.Or: return "Or"
if op == OpKind.Eq: return "Eq"
if op == OpKind.Ne: return "Ne"
if op == OpKind.Lt: return "Lt"
if op == OpKind.Le: return "Le"
if op == OpKind.Gt: return "Gt"
if op == OpKind.Ge: return "Ge"
if op == OpKind.Is: return "Is"
if op == OpKind.IsNot: return "IsNot"
if op == OpKind.In: return "In"
if op == OpKind.NotIn: return "NotIn"
if op == OpKind.Not: return "Not"
if op == OpKind.UAdd: return "UAdd"
if op == OpKind.USub: return "USub"
if op == OpKind.Invert: return "Invert"
return "NoneOp"
def _dump_list(lst: list[AST | t.CPtr] | t.CPtr, buf: t.CChar | t.CPtr,
size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT:
"""Traverse a list[AST | CPtr] container, polymorphically dump each element."""
if lst is None:
pos = _emit(buf, size, pos, "[]")
return pos
pos = _emit(buf, size, pos, "[")
n: t.CSizeT = lst.__len__()
i: t.CSizeT = 0
while i < n:
if i > 0:
pos = _emit(buf, size, pos, ", ")
child: AST | t.CPtr = lst.get(i)
if child is not None:
pos = child.dump(buf, size, pos)
i += 1
pos = _emit(buf, size, pos, "]")
return pos
def _dump_op_list(lst: t.CPtr, buf: t.CChar | t.CPtr,
size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT:
"""Traverse a list[CInt] (OpKind values), output a list of op names."""
if lst is None:
pos = _emit(buf, size, pos, "[]")
return pos
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(lst)
pos = _emit(buf, size, pos, "[")
n: t.CSizeT = ops_list.__len__()
i: t.CSizeT = 0
while i < n:
if i > 0:
pos = _emit(buf, size, pos, ", ")
op: t.CInt = ops_list.get(i)
pos = _emit(buf, size, pos, _op_name(op))
i += 1
pos = _emit(buf, size, pos, "]")
return pos
# ============================================================
# AST - Polymorphic Base Class
# @t.CVTable enables vtable, supporting virtual functions like kind()/type_name()/dump()/accept()
# Child nodes are stored in a list[AST | CPtr] container (O(1) random access, more efficient than linked lists)
# The parent field maintains a pointer to the parent (used for upward traversal)
# ============================================================
@t.CVTable
class AST:
"""AST node base class. All specific node classes inherit from this.
Fields:
parent: Pointer to the parent node (for upward traversal)
pool: Allocator (used for allocating child nodes/strings)
lineno/col_offset: Starting position
end_lineno/end_col_offset: Ending position
children: List of child nodes (body block, added via append)
"""
parent: AST | t.CPtr
pool: memhub.MemManager | t.CPtr
lineno: t.CInt
col_offset: t.CInt
end_lineno: t.CInt
end_col_offset: t.CInt
children: list[AST | t.CPtr] | t.CPtr
def kind(self) -> t.CInt:
"""Returns the node type (ASTKind value), overridden by subclasses"""
return 0
def type_name(self) -> str:
"""Return the node type name, subclasses override"""
return "AST"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
"""Polymorphic dump: subclasses override to define custom format. Returns the written pos"""
return pos
def accept(self, visitor: t.CPtr):
"""Visitor pattern entry point: subclasses override to dispatch to ASTVisitor in the visitor pattern.
Current implementation is empty. override this method to dispatch to visitor.visit_X(self)"""
pass
def append(self, node: AST | t.CPtr):
"""Append node to the children list.
Used for parser to build statement blocks: module.append(stmt), if_node.append(stmt), etc.
The children list is lazily initialized on first call.
Note: list[AST|CPtr] is currently stored by value (compiler limitation), so you must set
node.parent before appending, so the parent in the copy is correct."""
if self is None or node is None:
return
if self.children is None:
self.children = list[AST | t.CPtr](self.pool, 8)
node.parent = self
_append_child(self.children, node, self.pool)
# ============================================================
# Stmt - Statement Base Class
#
# 所有语句节点(Assign/If/For/While/Return/...)继承 Stmt。
# isinstance(node, ast.Stmt) 可在运行时区分"语句"与"表达式"
# (依赖 TPV isinstance 子类集合判定 + 三层 vtable 继承)。
# 不 override kind()(继承 AST 的 0),具体节点各自返回 ASTKind 值。
# ============================================================
@t.CVTable
class Stmt(AST):
"""语句节点基类(Assign/If/For/While/Return/...)"""
# ============================================================
# ExprNode - Expression Base Class
#
# 所有表达式节点(Name/Constant/Call/BinOp/...)继承 ExprNode。
# isinstance(node, ast.ExprNode) 可在运行时区分"表达式"与"语句"。
#
# 命名说明:不能叫 Expr——ASTKind.Expr(base.vp L23)与 stmts.vp 的
# Expr 类已是"表达式语句"(Expression Statement)的既有语义。
# ============================================================
@t.CVTable
class ExprNode(AST):
"""表达式节点基类(Name/Constant/Call/BinOp/...)"""
# ============================================================
# Module dump function (for ast.dump(node, buf, size))
# ============================================================
def dump(node: AST | t.CPtr, buf: t.CChar | t.CPtr, size: t.CSizeT):
"""Serialize AST node to buf (with capacity size)"""
if node is None or buf is None or size == 0:
return
buf[0] = '\0'
final_pos: t.CSizeT = node.dump(buf, size, 0)
# NUL-terminate to prevent printf overflow
if final_pos < size:
buf[final_pos] = '\0'
else:
buf[size - 1] = '\0'
+1239
View File
File diff suppressed because it is too large. Load diff
+773
View File
@@ -0,0 +1,773 @@
import t, c
from stdint import *
import memhub
import string
from .tokens import (
Token, TokenType, TokOp, _init_tables, _kw_lookup, _op_head,
OpEntry, new_token, token_set_str, token_set_str_literal,
)
# Maximum Indentation Stack Depth
LEXER_MAX_INDENT: t.CDefine = 256
# ============================================================
# Lexer State Structure
# ============================================================
class Lexer:
src: str # Source code (NUL-terminated)
pos: t.CSizeT # Current position
len: t.CSizeT # Source code length
lineno: t.CInt # Current line number (1-based)
col: t.CInt # Current column number (0-based)
pool: memhub.MemManager | t.CPtr # Memory pool
indent_stack: t.CInt | t.CPtr # Indent stack (int array, allocated from pool)
indent_top: t.CInt # Stack top (-1 for empty stack)
paren_depth: t.CInt # Paren depth (>0 for no TokenType.NewLine)
tokens_head: Token | t.CPtr # token list head
tokens_tail: Token | t.CPtr # token list tail
at_line_start: t.CInt # 1=line start (need indent)
error_count: t.CInt # Error count
def __new__(self, pool: memhub.MemManager | t.CPtr):
ptr: Lexer | t.CPtr = pool.alloc(Lexer.__sizeof__())
if ptr:
string.memset(ptr, 0, Lexer.__sizeof__())
return ptr
def new_lexer(pool: memhub.MemManager | t.CPtr) -> Lexer | t.CPtr:
"""Allocate from the pool and return a Lexer (cross-module safe wrapper)"""
return Lexer(pool)
def _lexer_init(lx: Lexer | t.CPtr, src: str,
pool: memhub.MemManager | t.CPtr):
"""Initialize Lexer"""
if lx == None: return
lx.src = src
lx.pos = 0
lx.len = string.strlen(src) if src != None else 0
lx.lineno = 1
lx.col = 0
lx.pool = pool
# Allocate indentation stack
lx.indent_stack = pool.alloc(LEXER_MAX_INDENT * 8)
if lx.indent_stack != None:
string.memset(lx.indent_stack, 0, LEXER_MAX_INDENT * 8)
lx.indent_top = -1
# Push 0 (base indent)
if lx.indent_stack != None:
lx.indent_stack[0] = 0
lx.indent_top = 0
lx.paren_depth = 0
lx.tokens_head = None
lx.tokens_tail = None
lx.at_line_start = 1
lx.error_count = 0
_init_tables(pool)
# ============================================================
# Auxiliary Functions
# ============================================================
def _peek(lx: Lexer | t.CPtr, offset: t.CSizeT) -> t.CChar:
"""Peek character at position pos+offset, return '\0' if out of bounds"""
p: t.CSizeT = lx.pos + offset
if p >= lx.len:
return '\0'
return lx.src[p]
def _peek_cur(lx: Lexer | t.CPtr) -> t.CChar:
if lx.pos >= lx.len:
return '\0'
return lx.src[lx.pos]
def _advance(lx: Lexer | t.CPtr) -> t.CChar:
"""Advance one character, return the character"""
if lx.pos >= lx.len:
return '\0'
ch: t.CChar = lx.src[lx.pos]
lx.pos += 1
if ch == '\n':
lx.lineno += 1
lx.col = 0
else:
lx.col += 1
return ch
def _is_alpha(ch: t.CChar) -> t.CInt:
if ch >= 'a' and ch <= 'z': return 1
if ch >= 'A' and ch <= 'Z': return 1
if ch == '_': return 1
return 0
def _is_digit(ch: t.CChar) -> t.CInt:
if ch >= '0' and ch <= '9': return 1
return 0
def _is_alnum(ch: t.CChar) -> t.CInt:
if _is_alpha(ch): return 1
if _is_digit(ch): return 1
return 0
def _is_hex(ch: t.CChar) -> t.CInt:
if ch >= '0' and ch <= '9': return 1
if ch >= 'a' and ch <= 'f': return 1
if ch >= 'A' and ch <= 'F': return 1
return 0
def _is_space(ch: t.CChar) -> t.CInt:
if ch == ' ': return 1
if ch == '\t': return 1
if ch == '\f': return 1
if ch == '\v': return 1
if ch == '\r': return 1
return 0
def _emit(lx: Lexer | t.CPtr, tok: Token | t.CPtr):
"""Append token to token list"""
if tok == None: return
if lx.tokens_head == None:
lx.tokens_head = tok
lx.tokens_tail = tok
else:
lx.tokens_tail.next = tok
lx.tokens_tail = tok
def _make_op_token(lx: Lexer | t.CPtr, op_id: t.CInt, length: t.CInt,
lineno: t.CInt, col: t.CInt) -> Token | t.CPtr:
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Op, lineno, col)
if tok == None: return None
tok.op_subtype = op_id
tok.end_col_offset = col + length
return tok
# ============================================================
# Indent Handling
# ============================================================
def _handle_indent(lx: Lexer | t.CPtr):
"""Handle line start indent, generate TokenType.Indent/TokenType.Dedent.
Skip empty lines and comment lines."""
# Skip empty lines and comment lines
while lx.pos < lx.len:
# Save line start position for non-empty lines
line_start_pos: t.CSizeT = lx.pos
line_start_col: t.CInt = lx.col
# Skip whitespace, not across lines
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == ' ' or ch == '\t' or ch == '\f' or ch == '\v':
lx.pos += 1
lx.col += 1
elif ch == '\r':
# CRLF line end \r, skip \n to trigger empty line processing
lx.pos += 1
else:
break
if lx.pos >= lx.len:
break
ch = lx.src[lx.pos]
if ch == '\n':
# Empty line, skip
lx.pos += 1
lx.lineno += 1
lx.col = 0
continue
if ch == '\r':
# CRLF line end \r, skip \n to trigger empty line processing
lx.pos += 1
if lx.pos < lx.len and lx.src[lx.pos] == '\n':
lx.pos += 1
lx.lineno += 1
lx.col = 0
continue
if ch == '#':
# Comment line, skip to end of line
while lx.pos < lx.len and lx.src[lx.pos] != '\n':
lx.pos += 1
continue
# Non-empty line: backtrack to line start to allow indent calculation
lx.pos = line_start_pos
lx.col = line_start_col
break
if lx.pos >= lx.len:
# End of file, no indent to handle
lx.at_line_start = 0
return
# Calculate current line indent
indent: t.CInt = 0
save_pos: t.CSizeT = lx.pos
save_col: t.CInt = lx.col
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == ' ':
indent += 1
lx.pos += 1
lx.col += 1
elif ch == '\t':
indent += 8 - (indent % 8)
lx.pos += 1
lx.col += 1
else:
break
# If line end (empty line), skip indent calculation
if lx.pos < lx.len:
ch = lx.src[lx.pos]
if ch == '\n' or ch == '\r' or ch == '#':
# Empty line or comment line, backtrack position to allow loop to handle indent
lx.pos = save_pos
lx.col = save_col
lx.at_line_start = 0
return
# Compare indent with top of indent stack
top_indent: t.CInt = lx.indent_stack[lx.indent_top]
if indent > top_indent:
# TokenType.Indent
if lx.indent_top + 1 >= LEXER_MAX_INDENT:
lx.error_count += 1
return
lx.indent_top += 1
lx.indent_stack[lx.indent_top] = indent
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Indent, lx.lineno, 0)
_emit(lx, tok)
else:
while indent < lx.indent_stack[lx.indent_top] and lx.indent_top > 0:
lx.indent_top -= 1
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0)
_emit(lx, tok)
lx.at_line_start = 0
# ============================================================
# Identifier/Keyword Handling
# ============================================================
def _read_name(lx: Lexer | t.CPtr):
start: t.CSizeT = lx.pos
start_lineno: t.CInt = lx.lineno
start_col: t.CInt = lx.col
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if _is_alnum(ch):
lx.pos += 1
lx.col += 1
else:
break
length: t.CSizeT = lx.pos - start
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Name, start_lineno, start_col)
if tok == None: return
token_set_str(lx.pool, tok, lx.src, start, length)
tok.end_lineno = lx.lineno
tok.end_col_offset = start_col + t.CInt(length)
# Look up keyword if any
kw_id: t.CInt = _kw_lookup(tok.str_val)
if kw_id:
tok.kw_subtype = kw_id
_emit(lx, tok)
# ============================================================
# Number Handling
# ============================================================
def _read_number(lx: Lexer | t.CPtr):
start: t.CSizeT = lx.pos
start_lineno: t.CInt = lx.lineno
start_col: t.CInt = lx.col
is_float: t.CInt = 0
is_complex: t.CInt = 0
ch0: t.CChar = lx.src[lx.pos]
# Handle 0x/0o/0b prefix
if ch0 == '0' and lx.pos + 1 < lx.len:
ch1: t.CChar = lx.src[lx.pos + 1]
if ch1 == 'x' or ch1 == 'X':
lx.pos += 2
lx.col += 2
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if _is_hex(ch) or ch == '_':
lx.pos += 1
lx.col += 1
else:
break
_emit_number(lx, start, start_lineno, start_col, 0, 0, 0)
return
if ch1 == 'o' or ch1 == 'O':
lx.pos += 2
lx.col += 2
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch >= '0' and ch <= '7':
lx.pos += 1
lx.col += 1
elif ch == '_':
lx.pos += 1
lx.col += 1
else:
break
_emit_number(lx, start, start_lineno, start_col, 0, 0, 0)
return
if ch1 == 'b' or ch1 == 'B':
lx.pos += 2
lx.col += 2
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == '0' or ch == '1' or ch == '_':
lx.pos += 1
lx.col += 1
else:
break
_emit_number(lx, start, start_lineno, start_col, 0, 0, 0)
return
# Decimal integer/float
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if _is_digit(ch) or ch == '_':
lx.pos += 1
lx.col += 1
else:
break
# Decimal part
if lx.pos < lx.len and lx.src[lx.pos] == '.':
is_float = 1
lx.pos += 1
lx.col += 1
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if _is_digit(ch) or ch == '_':
lx.pos += 1
lx.col += 1
else:
break
# Exponent part
if lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == 'e' or ch == 'E':
is_float = 1
lx.pos += 1
lx.col += 1
if lx.pos < lx.len:
ch = lx.src[lx.pos]
if ch == '+' or ch == '-':
lx.pos += 1
lx.col += 1
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if _is_digit(ch) or ch == '_':
lx.pos += 1
lx.col += 1
else:
break
# Complex suffix part
if lx.pos < lx.len and lx.src[lx.pos] == 'j':
is_complex = 1
is_float = 1
lx.pos += 1
lx.col += 1
_emit_number(lx, start, start_lineno, start_col, is_float, is_complex, 0)
def _emit_number(lx: Lexer | t.CPtr, start: t.CSizeT,
start_lineno: t.CInt, start_col: t.CInt,
is_float: t.CInt, is_complex: t.CInt, is_hex: t.CInt):
length: t.CSizeT = lx.pos - start
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Number, start_lineno, start_col)
if tok == None: return
token_set_str(lx.pool, tok, lx.src, start, length)
tok.is_float = is_float
tok.is_complex = is_complex
tok.end_lineno = lx.lineno
tok.end_col_offset = start_col + t.CInt(length)
# Parse number
if is_float:
tok.float_val = string.atof(tok.str_val)
else:
tok.int_val = string.atoll(tok.str_val)
_emit(lx, tok)
# ============================================================
# String Handling
# ============================================================
def _read_string(lx: Lexer | t.CPtr):
"""Read string literal.
Supports prefixes: r, b, u, f, rb, br, rf, fr (case insensitive)
Supports quotes: ', ", ''',
Later we need to support string prefixes like i16/i24"""
start_lineno: t.CInt = lx.lineno
start_col: t.CInt = lx.col
prefix_start: t.CSizeT = lx.pos
# Read prefix (r/b/u/f)
is_raw: t.CInt = 0
is_bytes: t.CInt = 0
is_fstring: t.CInt = 0
while lx.pos < lx.len:
ch: t.CChar = lx.src[lx.pos]
if ch == 'r' or ch == 'R':
is_raw = 1
lx.pos += 1
lx.col += 1
elif ch == 'b' or ch == 'B':
is_bytes = 1
lx.pos += 1
lx.col += 1
elif ch == 'u' or ch == 'U':
lx.pos += 1
lx.col += 1
elif ch == 'f' or ch == 'F':
is_fstring = 1
lx.pos += 1
lx.col += 1
else:
break
if lx.pos >= lx.len:
lx.error_count += 1
return
# Determine quote type
quote: t.CChar = lx.src[lx.pos]
if quote != '\'' and quote != '"':
lx.error_count += 1
return
# Check triple quote
is_triple: t.CInt = 0
if lx.pos + 2 < lx.len:
if lx.src[lx.pos] == quote and lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote:
is_triple = 1
content_start: t.CSizeT = lx.pos
if is_triple:
lx.pos += 3
lx.col += 3
else:
lx.pos += 1
lx.col += 1
# Read string content
content_buf_start: t.CSizeT = lx.pos
while lx.pos < lx.len:
ch = lx.src[lx.pos]
if is_triple:
if ch == quote:
if lx.pos + 2 < lx.len:
if lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote:
break
elif lx.pos + 2 == lx.len:
break
if ch == '\\':
lx.pos += 1
lx.col += 1
if lx.pos < lx.len:
if lx.src[lx.pos] == '\n':
lx.lineno += 1
lx.col = 0
lx.pos += 1
lx.col += 1
continue
if ch == '\n':
lx.lineno += 1
lx.col = 0
lx.pos += 1
lx.col += 1
else:
if ch == quote:
break
if ch == '\n':
# Single quote string cannot span multiple lines (unless continued)
lx.error_count += 1
return
if ch == '\\' and not is_raw:
lx.pos += 1
lx.col += 1
if lx.pos < lx.len:
lx.pos += 1
lx.col += 1
continue
lx.pos += 1
lx.col += 1
content_end: t.CSizeT = lx.pos
# Skip the closing quote
if is_triple:
if lx.pos + 2 < lx.len:
lx.pos += 3
lx.col += 3
else:
lx.pos = lx.len
else:
if lx.pos < lx.len:
lx.pos += 1
lx.col += 1
# Create token
tok: Token | t.CPtr = new_token(lx.pool, TokenType.String, start_lineno, start_col)
if tok == None: return
content_len: t.CSizeT = content_end - content_buf_start
# esc_len: Actual bytes after escaping (used to check single character)
esc_len: t.CSizeT = content_len
# Handle escape sequences (non-raw strings)
if is_raw == 0 and content_len > 0:
# Allocate conversion buffer (max case: each char is plain, no extension)
conv_buf: str = lx.pool.alloc(content_len + 1)
if conv_buf == None:
token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len)
else:
wpos: t.CSizeT = 0
rpos: t.CSizeT = 0
while rpos < content_len:
ch: t.CChar = lx.src[content_buf_start + rpos]
if ch == '\\' and rpos + 1 < content_len:
rpos += 1
next_ch: t.CChar = lx.src[content_buf_start + rpos]
if next_ch == 'n':
conv_buf[wpos] = '\n'
elif next_ch == 't':
conv_buf[wpos] = '\t'
elif next_ch == 'r':
conv_buf[wpos] = '\r'
elif next_ch == 'f':
conv_buf[wpos] = '\f'
elif next_ch == 'v':
conv_buf[wpos] = '\v'
elif next_ch == 'a':
conv_buf[wpos] = '\a'
elif next_ch == 'b':
conv_buf[wpos] = '\b'
elif next_ch == '\\':
conv_buf[wpos] = '\\'
elif next_ch == '\'':
conv_buf[wpos] = '\''
elif next_ch == '"':
conv_buf[wpos] = '"'
elif next_ch == '0':
conv_buf[wpos] = '\0'
else:
# Unknown escape sequence, keep original (includes \xNN)
conv_buf[wpos] = '\\'
wpos += 1
conv_buf[wpos] = next_ch
wpos += 1
rpos += 1
else:
conv_buf[wpos] = ch
wpos += 1
rpos += 1
conv_buf[wpos] = '\0'
token_set_str_literal(lx.pool, tok, conv_buf)
esc_len = wpos
else:
token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len)
tok.end_lineno = lx.lineno
tok.end_col_offset = lx.col
# flags field: bit0=raw, bit1=bytes, bit2=fstring, bit3=triple, bit4=dquote, bit5=single char candidate
if is_raw: tok.kw_subtype = tok.kw_subtype | 1
if is_bytes: tok.kw_subtype = tok.kw_subtype | 2
if is_fstring: tok.kw_subtype = tok.kw_subtype | 4
if is_triple: tok.kw_subtype = tok.kw_subtype | 8
# bit4 (16) = double quote=single quote
if quote == '"': tok.kw_subtype = tok.kw_subtype | 16
# bit5 (32) = single-character candidate (not triple quotes, not f-string, exactly 1 byte after escaping)
# Used for CONST_CHAR checks to prevent '0' and other NUL bytes from being mistaken as empty strings by strlen
if is_triple == 0 and is_fstring == 0 and esc_len == 1:
tok.kw_subtype = tok.kw_subtype | 32
_emit(lx, tok)
# ============================================================
# Operator Matching
# ============================================================
def _read_operator(lx: Lexer | t.CPtr):
"""Greedy match operator"""
start_lineno: t.CInt = lx.lineno
start_col: t.CInt = lx.col
remaining: t.CSizeT = lx.len - lx.pos
# Traverse operator table, find longest match
best_entry: OpEntry | t.CPtr = None
best_len: t.CInt = 0
cur: OpEntry | t.CPtr = _op_head
while cur != None:
if cur.length <= t.CInt(remaining):
# Compare cur.name with src[pos:pos+cur.length]
match: t.CInt = 1
i: t.CSizeT = 0
while i < t.CSizeT(cur.length):
if lx.src[lx.pos + i] != cur.name[i]:
match = 0
break
i += 1
if match:
if cur.length > best_len:
best_len = cur.length
best_entry = cur
cur = cur.next
if best_entry == None:
# Unknown character, report error and skip
lx.error_count += 1
lx.pos += 1
lx.col += 1
return
# Update parenthesis depth
if best_entry.op_id == TokOp.LPar or best_entry.op_id == TokOp.Lsqb or best_entry.op_id == TokOp.LBrace:
lx.paren_depth += 1
elif best_entry.op_id == TokOp.RPar or best_entry.op_id == TokOp.Rsqb or best_entry.op_id == TokOp.RBrace:
if lx.paren_depth > 0:
lx.paren_depth -= 1
tok: Token | t.CPtr = _make_op_token(lx, best_entry.op_id, best_entry.length,
start_lineno, start_col)
if tok == None: return
token_set_str(lx.pool, tok, lx.src, lx.pos, t.CSizeT(best_len))
lx.pos += t.CSizeT(best_len)
lx.col += best_len
_emit(lx, tok)
# ============================================================
# Main Lexical Analysis Entry Point
# ============================================================
def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
"""Execute tokenization, return token list head"""
if lx == None: return None
while lx.pos < lx.len:
# Handle line start indent
if lx.at_line_start and lx.paren_depth == 0:
_handle_indent(lx)
if lx.pos >= lx.len:
break
ch: t.CChar = _peek_cur(lx)
if ch == '\0':
break
# New line
if ch == '\n':
if lx.paren_depth > 0:
# # In bi brackets, generates TokenType.Nl
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Nl, lx.lineno, lx.col)
_emit(lx, tok)
else:
# Logical new line
tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col)
_emit(lx, tok)
lx.at_line_start = 1
lx.pos += 1
lx.lineno += 1
lx.col = 0
continue
# Backslash continuation line
# 支持 LF 与 CRLF(Windows 文件行尾):CRLF 下 `\` 后是 '\r'(非 '\n'),
# 只查 '\n' 会失效 → `\` 被当未知字符跳过、'\n' 产生 NEWLINE → 表达式
# 中断(VpiReader.vp L324 `or \` 行尾续行根因,CRLF 文件)。
if ch == '\\' and lx.pos + 1 < lx.len:
if lx.src[lx.pos + 1] == '\n':
lx.pos += 2
lx.lineno += 1
lx.col = 0
continue
if lx.src[lx.pos + 1] == '\r':
# \ + \r\n:跳 \、\r、\n
lx.pos += 2
if lx.pos < lx.len and lx.src[lx.pos] == '\n':
lx.pos += 1
lx.lineno += 1
lx.col = 0
continue
# Whitespace
if _is_space(ch):
lx.pos += 1
lx.col += 1
continue
# Comment
if ch == '#':
while lx.pos < lx.len and lx.src[lx.pos] != '\n':
lx.pos += 1
continue
# String prefixes (like r"...") or strings
if ch == '\'' or ch == '"':
_read_string(lx)
continue
# A string prefix letter followed by a quote (must be checked before _is_alpha, otherwise f/r/b/u will be treated as TokenType.Name)
if (ch == 'r' or ch == 'R' or ch == 'b' or ch == 'B' or
ch == 'u' or ch == 'U' or ch == 'f' or ch == 'F'):
if lx.pos + 1 < lx.len:
ch1: t.CChar = lx.src[lx.pos + 1]
if ch1 == '\'' or ch1 == '"':
_read_string(lx)
continue
# Double prefixes like rb, br, rf, fr
if lx.pos + 2 < lx.len:
ch2: t.CChar = lx.src[lx.pos + 2]
if ((ch1 == 'r' or ch1 == 'R' or ch1 == 'b' or ch1 == 'B' or
ch1 == 'f' or ch1 == 'F' or ch1 == 'u' or ch1 == 'U') and
(ch2 == '\'' or ch2 == '"')):
_read_string(lx)
continue
# Identifier/keyword
if _is_alpha(ch):
_read_name(lx)
continue
# Number
if _is_digit(ch):
_read_number(lx)
continue
# Operator
_read_operator(lx)
# End of file: generate TokenType.NewLine (if there's content)
if lx.tokens_tail != None:
if lx.tokens_tail.type != TokenType.NewLine and lx.tokens_tail.type != TokenType.Nl:
tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col)
_emit(lx, tok)
# Generate remaining remaining TokenType.Dedent
while lx.indent_top > 0:
lx.indent_top -= 1
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0)
_emit(lx, tok)
# TokenType.EndMarker
tok: Token | t.CPtr = new_token(lx.pool, TokenType.EndMarker, lx.lineno, 0)
_emit(lx, tok)
return lx.tokens_head
+363
View File
@@ -0,0 +1,363 @@
import t, c
from stdint import *
import memhub
import string
from .base import (
AST, ASTKind,
_init_ast, _copy_str, _set_parent_list,
_emit, _emit_str, _emit_int, _dump_list,
)
# ============================================================
# MatchCase 节点Node
# ============================================================
class MatchCase(AST):
"""MatchCase(pattern: AST, guard: AST)"""
pattern: AST | t.CPtr
guard: AST | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
pattern: AST | t.CPtr, guard: AST | t.CPtr):
ptr: MatchCase | t.CPtr = pool.alloc(MatchCase.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchCase.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
pattern: AST | t.CPtr, guard: AST | t.CPtr):
_init_ast(self, pool, 0, 0)
self.pattern = pattern
self.guard = guard
def kind(self) -> t.CInt:
return ASTKind.MatchCase
def type_name(self) -> str:
return "MatchCase"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchCase(pattern=")
if self.pattern is not None:
pos = self.pattern.dump(buf, size, pos)
pos = _emit(buf, size, pos, ", guard=")
if self.guard is not None:
pos = self.guard.dump(buf, size, pos)
pos = _emit(buf, size, pos, ", body=")
pos = _dump_list(self.children, buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# MatchValue Node
# ============================================================
class MatchValue(AST):
"""MatchValue(value: AST)"""
value: AST | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr):
ptr: MatchValue | t.CPtr = pool.alloc(MatchValue.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchValue.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr):
_init_ast(self, pool, 0, 0)
self.value = value
def kind(self) -> t.CInt:
return ASTKind.MatchValue
def type_name(self) -> str:
return "MatchValue"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchValue(value=")
if self.value is not None:
pos = self.value.dump(buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# MatchSingleton Node
# ============================================================
class MatchSingleton(AST):
"""MatchSingleton(value: AST)"""
value: AST | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr):
ptr: MatchSingleton | t.CPtr = pool.alloc(MatchSingleton.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchSingleton.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr):
_init_ast(self, pool, 0, 0)
self.value = value
def kind(self) -> t.CInt:
return ASTKind.MatchSingleton
def type_name(self) -> str:
return "MatchSingleton"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchSingleton(value=")
if self.value is not None:
pos = self.value.dump(buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# MatchSequence Node
# ============================================================
class MatchSequence(AST):
"""MatchSequence(patterns: list[AST | t.CPtr])"""
patterns: list[AST | t.CPtr] | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr):
ptr: MatchSequence | t.CPtr = pool.alloc(MatchSequence.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchSequence.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr):
_init_ast(self, pool, 0, 0)
self.patterns = patterns
_set_parent_list(patterns, self)
def kind(self) -> t.CInt:
return ASTKind.MatchSequence
def type_name(self) -> str:
return "MatchSequence"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchSequence(patterns=")
pos = _dump_list(self.patterns, buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# MatchMapping Node
# ============================================================
class MatchMapping(AST):
"""MatchMapping(keys: list[AST | t.CPtr], patterns: list[AST | t.CPtr], rest: str)"""
keys: list[AST | t.CPtr] | t.CPtr
patterns: list[AST | t.CPtr] | t.CPtr
rest: str
def __new__(self, pool: memhub.MemManager | t.CPtr,
keys: list[AST | t.CPtr] | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr,
rest: str):
ptr: MatchMapping | t.CPtr = pool.alloc(MatchMapping.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchMapping.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
keys: list[AST | t.CPtr] | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr,
rest: str):
_init_ast(self, pool, 0, 0)
self.keys = keys
self.patterns = patterns
self.rest = _copy_str(pool, rest)
_set_parent_list(keys, self)
_set_parent_list(patterns, self)
def kind(self) -> t.CInt:
return ASTKind.MatchMapping
def type_name(self) -> str:
return "MatchMapping"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchMapping(keys=")
pos = _dump_list(self.keys, buf, size, pos)
pos = _emit(buf, size, pos, ", patterns=")
pos = _dump_list(self.patterns, buf, size, pos)
pos = _emit(buf, size, pos, ", rest='")
pos = _emit_str(buf, size, pos, self.rest)
pos = _emit(buf, size, pos, "')")
return pos
# ============================================================
# MatchClass Node
# ============================================================
class MatchClass(AST):
"""MatchClass(cls: AST, patterns: list[AST | t.CPtr],
kwd_attrs: list[AST | t.CPtr], kwd_patterns: list[AST | t.CPtr])"""
cls: AST | t.CPtr
patterns: list[AST | t.CPtr] | t.CPtr
kwd_attrs: list[AST | t.CPtr] | t.CPtr
kwd_patterns: list[AST | t.CPtr] | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
cls: AST | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr,
kwd_attrs: list[AST | t.CPtr] | t.CPtr,
kwd_patterns: list[AST | t.CPtr] | t.CPtr):
ptr: MatchClass | t.CPtr = pool.alloc(MatchClass.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchClass.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
cls: AST | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr,
kwd_attrs: list[AST | t.CPtr] | t.CPtr,
kwd_patterns: list[AST | t.CPtr] | t.CPtr):
_init_ast(self, pool, 0, 0)
self.cls = cls
self.patterns = patterns
self.kwd_attrs = kwd_attrs
self.kwd_patterns = kwd_patterns
_set_parent_list(patterns, self)
_set_parent_list(kwd_attrs, self)
_set_parent_list(kwd_patterns, self)
def kind(self) -> t.CInt:
return ASTKind.MatchClass
def type_name(self) -> str:
return "MatchClass"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchClass(cls=")
if self.cls is not None:
pos = self.cls.dump(buf, size, pos)
pos = _emit(buf, size, pos, ", patterns=")
pos = _dump_list(self.patterns, buf, size, pos)
pos = _emit(buf, size, pos, ", kwd_attrs=")
pos = _dump_list(self.kwd_attrs, buf, size, pos)
pos = _emit(buf, size, pos, ", kwd_patterns=")
pos = _dump_list(self.kwd_patterns, buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
# ============================================================
# MatchStar Node
# ============================================================
class MatchStar(AST):
"""MatchStar(name: str)"""
name: str
def __new__(self, pool: memhub.MemManager | t.CPtr, name: str):
ptr: MatchStar | t.CPtr = pool.alloc(MatchStar.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchStar.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr, name: str):
_init_ast(self, pool, 0, 0)
self.name = _copy_str(pool, name)
def kind(self) -> t.CInt:
return ASTKind.MatchStar
def type_name(self) -> str:
return "MatchStar"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchStar(name='")
pos = _emit_str(buf, size, pos, self.name)
pos = _emit(buf, size, pos, "')")
return pos
# ============================================================
# MatchAs Node
# ============================================================
class MatchAs(AST):
"""MatchAs(pattern: AST, name: str)"""
pattern: AST | t.CPtr
name: str
def __new__(self, pool: memhub.MemManager | t.CPtr,
pattern: AST | t.CPtr, name: str):
ptr: MatchAs | t.CPtr = pool.alloc(MatchAs.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchAs.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
pattern: AST | t.CPtr, name: str):
_init_ast(self, pool, 0, 0)
self.pattern = pattern
self.name = _copy_str(pool, name)
def kind(self) -> t.CInt:
return ASTKind.MatchAs
def type_name(self) -> str:
return "MatchAs"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchAs(pattern=")
if self.pattern is not None:
pos = self.pattern.dump(buf, size, pos)
pos = _emit(buf, size, pos, ", name='")
pos = _emit_str(buf, size, pos, self.name)
pos = _emit(buf, size, pos, "')")
return pos
# ============================================================
# MatchOr Node
# ============================================================
class MatchOr(AST):
"""MatchOr(patterns: list[AST | t.CPtr])"""
patterns: list[AST | t.CPtr] | t.CPtr
def __new__(self, pool: memhub.MemManager | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr):
ptr: MatchOr | t.CPtr = pool.alloc(MatchOr.__sizeof__())
if ptr:
string.memset(ptr, 0, MatchOr.__sizeof__())
return ptr
def __init__(self, pool: memhub.MemManager | t.CPtr,
patterns: list[AST | t.CPtr] | t.CPtr):
_init_ast(self, pool, 0, 0)
self.patterns = patterns
_set_parent_list(patterns, self)
def kind(self) -> t.CInt:
return ASTKind.MatchOr
def type_name(self) -> str:
return "MatchOr"
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pos: t.CSizeT) -> t.CSizeT:
pos = _emit(buf, size, pos, "MatchOr(patterns=")
pos = _dump_list(self.patterns, buf, size, pos)
pos = _emit(buf, size, pos, ")")
return pos
+2749
View File
File diff suppressed because it is too large. Load diff
+1157
View File
File diff suppressed because it is too large. Load diff
+404
View File
@@ -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
+41
View File
@@ -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)
+80
View File
@@ -0,0 +1,80 @@
import t, c
# ==============================================
# Base64 Encoder & Decoder, pure bare-metal implementation
# ==============================================
# Base64 encoding lookup table
b64_tab: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# Base64 反向解码表,映射字符到索引值
b64_dec_tab: t.CArray[t.CInt8T, 80] = [
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
-1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
-1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
]
# * @brief Base64 encoding
# * @param s: Input binary data
# * @param out: Output buffer for Base64 string
# * @retval Length of encoded string
def b64encode(s: str, out: str) -> t.CSizeT:
_s = t.CUInt8T(s, t.CPtr)
length: t.CSizeT = len(s)
i: t.CSizeT = 0
j: t.CSizeT = 0
val: t.CUInt32T = 0
# Process input in groups of 3 bytes, produce 4 Base64 characters
for i in range(0, length, 3):
# Assemble 24-bit chunk
val = ((t.CUInt32T(_s[i + 0]) << 16 ) |
(t.CUInt32T(_s[i + 1]) << 8 if (i + 1 < length) else 0) |
(t.CUInt32T(_s[i + 2]) << 0 if (i + 2 < length) else 0))
# Split into four 6-bit values for table lookup
out[j + 0] = b64_tab[(val >> 18) & 0x3F]
out[j + 1] = b64_tab[(val >> 12) & 0x3F]
out[j + 2] = b64_tab[(val >> 6) & 0x3F] if (i + 1 < length) else '='
out[j + 3] = b64_tab[(val >> 0) & 0x3F] if (i + 2 < length) else '='
j += 4
out[j] = '\0' # Null terminator for C-style string
return j
# * @brief Base64 decoding
# * @param s: Base64 encoded string
# * @param out: Output binary buffer
# * @retval Length of decoded binary data
def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT:
length: t.CSizeT = len(s)
i: t.CSizeT = 0
j: t.CSizeT = 0
val: t.CUInt32T = 0
c: t.CInt
# Restore 3 bytes from every 4 Base64 characters
for i in range(0, length, 4):
if s[i] == '=':
break
val = 0
# Parse 6-bit values sequentially
c = s[i] - 43
val |= (b64_dec_tab[c] & 0x3F) << 18
c = s[i+1] - 43
val |= (b64_dec_tab[c] & 0x3F) << 12
c = s[i+2] - 43
if s[i+2] != '=':
val |= (b64_dec_tab[c] & 0x3F) << 6
c = s[i+3] - 43
if s[i+3] != '=':
val |= (b64_dec_tab[c] & 0x3F)
# Write recovered bytes
out[j] = (val >> 16) & 0xFF
j += 1
if s[i+2] != '=':
out[j] = (val >> 8) & 0xFF
j += 1
if s[i+3] != '=':
out[j] = val & 0xFF
j += 1
return j
+349
View File
@@ -0,0 +1,349 @@
import t, c
import stdlib
HEX_CHARS: t.CArray[t.CChar, None] = "0123456789abcdef"
HEX_VALS: t.CArray[t.CInt, 256]
B64_CHARS: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
B64_VALS: t.CArray[t.CInt, 256]
HQX_CHARS: t.CArray[t.CChar, 64] = [
' ', '!', chr(34), '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'@',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z',
'[', chr(92), '`',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'
]
HQX_VALS: t.CArray[t.CInt, 256]
UU_CHARS: t.CArray[t.CChar, None] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
CRC32_TABLE: t.CArray[t.CUnsignedInt, 256] = [
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
]
CRC_HQX_TABLE: t.CArray[t.CUnsignedShort, 256] = [
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
]
def init_binascii():
i: t.CInt
for i in range(256):
HEX_VALS[i] = -1
B64_VALS[i] = -1
HQX_VALS[i] = -1
for i in range(16):
HEX_VALS[t.CInt(HEX_CHARS[i])] = i
HEX_VALS[t.CInt(HEX_CHARS[i] - 32)] = i
for i in range(64):
B64_VALS[t.CInt(B64_CHARS[i])] = i
for i in range(64):
HQX_CHARS[i] = t.CChar(32 + i)
for i in range(64):
HQX_VALS[t.CUnsignedChar(HQX_CHARS[i])] = i
def crc32(data: str, length: t.CInt, crc: t.CUnsignedInt) -> t.CUnsignedInt:
i: t.CInt
s: t.CUnsignedInt = crc ^ 0xFFFFFFFF
for i in range(length):
s = CRC32_TABLE[(s ^ t.CUnsignedChar(data[i])) & 0xFF] ^ (s >> 8)
return s ^ 0xFFFFFFFF
def crc_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort) -> t.CUnsignedShort:
i: t.CInt
s: t.CUnsignedShort = crc
for i in range(length):
s = CRC_HQX_TABLE[t.CUnsignedChar(s >> 8)] ^ (s << 1 | (data[i] & 0xFF))
return s
def hexlify(data: str, length: t.CInt) -> str:
if not data or length < 0: return None
out: str = str(stdlib.malloc(length * 2 + 1))
if not out: return None
oi: t.CInt = 0
for i in range(length):
s: t.CUnsignedChar = t.CUnsignedChar(data[i])
out[oi] = HEX_CHARS[(s >> 4) & 0x0F]
oi += 1
out[oi] = HEX_CHARS[(s >> 0) & 0x0F]
oi += 1
out[oi] = '\0'
return out
def b2a_hex(data: str, length: t.CInt) -> str:
return hexlify(data, length)
def a2b_hex(hexstr: str, length: t.CInt) -> str:
if not hexstr or length < 0 or length % 2 != 0: return None
out_len: t.CInt = length // 2
out: str = str(stdlib.malloc(out_len + 1))
if not out: return None
oi: t.CInt = 0
for i in range(0, length, 2):
hi: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i])]
lo: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i + 1])]
if hi < 0 or lo < 0:
stdlib.free(out)
return None
out[oi] = t.CChar((hi << 4) | lo)
oi += 1
out[oi] = '\0'
return out
def unhexlify(data: str, length: t.CInt) -> bytes:
return a2b_hex(data, length)
def b2a_base64(data: str, length: t.CInt) -> str:
if not data or length < 0: return None
olen: t.CInt = (length // 3) * 4
if length % 3 != 0:
olen += 4
olen += 1
out: str = str(stdlib.malloc(olen + 1))
if not out: return None
oi: t.CInt = 0
for i in range(0, length, 3):
b0: t.CUnsignedChar = t.CUnsignedChar(data[i])
b1: t.CUnsignedChar = 0
b2: t.CUnsignedChar = 0
if i + 1 < length:
b1 = t.CUnsignedChar(data[i + 1])
if i + 2 < length:
b2 = t.CUnsignedChar(data[i + 2])
out[oi] = B64_CHARS[(b0 >> 2) & 0x3F]
oi += 1
out[oi] = B64_CHARS[((b0 & 0x03) << 4) | ((b1 >> 4) & 0x0F)]
oi += 1
if i + 1 < length:
out[oi] = B64_CHARS[((b1 & 0x0F) << 2) | ((b2 >> 6) & 0x03)]
else:
out[oi] = '='
oi += 1
if i + 2 < length:
out[oi] = B64_CHARS[b2 & 0x3F]
else:
out[oi] = '='
oi += 1
out[oi] = '\0'
return out
def a2b_base64(data: str, length: t.CInt) -> str:
if not data or length < 4: return None
olen: t.CInt = (length // 4) * 3
if length >= 4 and data[length - 1] == '=':
olen -= 1
if length >= 4 and data[length - 2] == '=':
olen -= 1
out: str = str(stdlib.malloc(olen + 1))
if not out: return None
oi: t.CInt = 0
for i in range(0, length, 4):
v0: t.CInt = 0
v1: t.CInt = 0
v2: t.CInt = 0
v3: t.CInt = 0
j: t.CInt
for j in range(4):
c: t.CChar = data[i + j]
if c == '=':
pass
else:
k: t.CInt
for k in range(64):
if B64_CHARS[k] == c:
if j == 0: v0 = k
elif j == 1: v1 = k
elif j == 2: v2 = k
elif j == 3: v3 = k
break
out[oi] = t.CChar((v0 << 2) | (v1 >> 4))
oi += 1
if data[i + 2] != '=':
out[oi] = t.CChar(((v1 & 0x0F) << 4) | (v2 >> 2))
oi += 1
if data[i + 3] != '=':
out[oi] = t.CChar(((v2 & 0x03) << 6) | v3)
oi += 1
out[oi] = '\0'
return out
def b2a_uu(data: str, length: t.CInt) -> str:
if not data or length < 1 or length > 45: return None
out: str = str(stdlib.malloc(length * 2 + 2))
if not out: return None
oi: t.CInt = 0
out[oi] = UU_CHARS[length]
oi += 1
for i in range(0, length, 3):
b0: t.CUnsignedChar = t.CUnsignedChar(data[i])
b1: t.CUnsignedChar = 0
b2: t.CUnsignedChar = 0
if i + 1 < length:
b1 = t.CUnsignedChar(data[i + 1])
if i + 2 < length:
b2 = t.CUnsignedChar(data[i + 2])
m: t.CUnsignedInt = (t.CUnsignedInt(b0) << 16) | (t.CUnsignedInt(b1) << 8) | t.CUnsignedInt(b2)
out[oi] = UU_CHARS[(m >> 18) & 0x3F]
oi += 1
out[oi] = UU_CHARS[(m >> 12) & 0x3F]
oi += 1
out[oi] = UU_CHARS[(m >> 6) & 0x3F]
oi += 1
out[oi] = UU_CHARS[m & 0x3F]
oi += 1
out[oi] = '\n'
oi += 1
out[oi] = '\0'
return out
def a2b_uu(data: str) -> str:
if not data or data[0] == ' ' or data[0] == '`': return None
length: t.CInt = t.CInt(data[0]) - 32
if length < 0 or length > 45: return None
out: str = str(stdlib.malloc(length + 1))
if not out: return None
oi: t.CInt = 0
i: t.CInt = 1
while oi < length:
v0: t.CInt = data[i] - 32
v1: t.CInt = data[i + 1] - 32
v2: t.CInt = data[i + 2] - 32
v3: t.CInt = data[i + 3] - 32
if v0 < 0 or v0 > 63: v0 = 0
if v1 < 0 or v1 > 63: v1 = 0
if v2 < 0 or v2 > 63: v2 = 0
if v3 < 0 or v3 > 63: v3 = 0
m: t.CUnsignedInt = (t.CUnsignedInt(v0) << 18) | (t.CUnsignedInt(v1) << 12) | (t.CUnsignedInt(v2) << 6) | t.CUnsignedInt(v3)
if oi < length:
out[oi] = t.CChar((m >> 16) & 0xFF)
oi += 1
if oi < length:
out[oi] = t.CChar((m >> 8) & 0xFF)
oi += 1
if oi < length:
out[oi] = t.CChar(m & 0xFF)
oi += 1
i += 4
out[oi] = '\0'
return out
def b2a_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]:
if not data or length != 3:
return None, crc
out: str = str(stdlib.malloc(5))
if not out:
return None, crc
# 3字节 → 4字节 HQX
m: t.CUnsignedInt = (t.CUnsignedChar(data[0]) << 16) | (t.CUnsignedChar(data[1]) << 8) | t.CUnsignedChar(data[2])
out[0] = HQX_CHARS[(m >> 18) & 0x3F]
out[1] = HQX_CHARS[(m >> 12) & 0x3F]
out[2] = HQX_CHARS[(m >> 6) & 0x3F]
out[3] = HQX_CHARS[m & 0x3F]
out[4] = '\0'
# CRC 初始化 + 正确计算
s: t.CUnsignedShort = crc
for i in range(3):
byte: t.CUnsignedChar = t.CUnsignedChar(data[i])
s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF]
return out, s
def a2b_hqx(data: str, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]:
if not data:
return None, crc
# 检查字符是否有效
for i in range(4):
cchar: t.CUnsignedChar = t.CUnsignedChar(data[i])
if HQX_VALS[cchar] < 0:
return None, crc
# 解码
m: t.CUnsignedInt = 0
for i in range(4):
m = (m << 6) | t.CUnsignedInt(HQX_VALS[t.CUnsignedChar(data[i])])
out: str = str(stdlib.malloc(4))
if not out:
return None, crc
out[0] = t.CChar((m >> 16) & 0xFF)
out[1] = t.CChar((m >> 8) & 0xFF)
out[2] = t.CChar(m & 0xFF)
out[3] = '\0'
# CRC 初始化 + 正确计算
s: t.CUnsignedShort = crc
for i in range(3):
byte: t.CUnsignedChar = t.CUnsignedChar(out[i])
s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF]
return out, s
def adler32(data: str, length: t.CInt, adler: t.CUnsignedInt) -> t.CUnsignedInt:
a: t.CUnsignedInt = adler & 0xFFFF
b: t.CUnsignedInt = (adler >> 16) & 0xFFFF
i: t.CInt
for i in range(length):
a = (a + t.CUnsignedChar(data[i])) % 65521
b = (b + a) % 65521
return (b << 16) | a
+13
View File
@@ -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
+52
View File
@@ -0,0 +1,52 @@
import t, c
from stdint import *
from w32.win32base import *
from w32.win32sync import (
CRITICAL_SECTION,
InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection,
InitializeConditionVariable, SleepConditionVariableCS,
WakeConditionVariable, WakeAllConditionVariable
)
class Condition:
"""Windows condition variable backed primitive, internally bundled with CRITICAL_SECTION.
Usage:
cond: Condition = Condition()
with cond:
while not ready:
cond.wait()
cond.notify()
"""
cond_var: VOIDPTR
cs: CRITICAL_SECTION
def __init__(self):
InitializeCriticalSection(c.Addr(self.cs))
InitializeConditionVariable(c.Addr(self.cond_var))
def wait(self, timeout_ms: ULONG = INFINITE) -> BOOL:
return SleepConditionVariableCS(c.Addr(self.cond_var), c.Addr(self.cs), timeout_ms)
def notify(self):
WakeConditionVariable(c.Addr(self.cond_var))
def notify_all(self):
WakeAllConditionVariable(c.Addr(self.cond_var))
def acquire(self):
EnterCriticalSection(c.Addr(self.cs))
def release(self):
LeaveCriticalSection(c.Addr(self.cs))
def __enter__(self) -> 'Condition' | t.CPtr:
self.acquire()
return self
def __exit__(self):
self.release()
def delete(self):
DeleteCriticalSection(c.Addr(self.cs))
+19
View File
@@ -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
+36
View File
@@ -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)
+4
View File
@@ -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
+132
View File
@@ -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
+120
View File
@@ -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
+124
View File
@@ -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
+149
View File
@@ -0,0 +1,149 @@
import t, c
import string
# ==============================================
# SHA512 Hash Algorithm
# ==============================================
SHA512_BLOCK_LEN: t.CDefine = 128
SHA512_DIGEST_LEN: t.CDefine = 64
def sha512_ror(x: t.CUInt64T, n: int) -> t.CUInt64T: return (x >> n) | (x << (64 - n))
def sha512_shr(x: t.CUInt64T, n: int) -> t.CUInt64T: return x >> n
def sha512_Ch (x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (~x & z)
def sha512_Maj(x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (x & z) ^ (y & z)
def sha512_BigSigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 28) ^ sha512_ror(x, 34) ^ sha512_ror(x, 39)
def sha512_BigSigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 14) ^ sha512_ror(x, 18) ^ sha512_ror(x, 41)
def sha512_Sigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 1) ^ sha512_ror(x, 8) ^ sha512_shr(x, 7)
def sha512_Sigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 19) ^ sha512_ror(x, 61) ^ sha512_shr(x, 6)
sha512_K: t.CArray[t.CUInt64T, 80] = [
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
]
@t.Object
class sha512:
state: t.CArray[t.CUInt64T, 8]
count: t.CArray[t.CUInt64T, 2]
buf: t.CArray[t.CUInt8T, SHA512_BLOCK_LEN]
def __init__(self):
string.memset(self, 0, sha512.__sizeof__())
self.state[0] = 0x6a09e667f3bcc908
self.state[1] = 0xbb67ae8584caa73b
self.state[2] = 0x3c6ef372fe94f82b
self.state[3] = 0xa54ff53a5f1d36f1
self.state[4] = 0x510e527fade682d1
self.state[5] = 0x9b05688c2b3e6c1f
self.state[6] = 0x1f83d9abfb41bd6b
self.state[7] = 0x5be0cd19137e2179
def transform(self, block: t.CArray[t.CUInt8T, SHA512_BLOCK_LEN]):
w: t.CArray[t.CUInt64T, 80]
a: t.CUInt64T
b: t.CUInt64T
c: t.CUInt64T
d: t.CUInt64T
e: t.CUInt64T
f: t.CUInt64T
g: t.CUInt64T
h: t.CUInt64T
t1: t.CUInt64T
t2: t.CUInt64T
for i in range(16):
w[i] = t.CUInt64T(block[i * 8 + 0]) << 56
w[i] |= t.CUInt64T(block[i * 8 + 1]) << 48
w[i] |= t.CUInt64T(block[i * 8 + 2]) << 40
w[i] |= t.CUInt64T(block[i * 8 + 3]) << 32
w[i] |= t.CUInt64T(block[i * 8 + 4]) << 24
w[i] |= t.CUInt64T(block[i * 8 + 5]) << 16
w[i] |= t.CUInt64T(block[i * 8 + 6]) << 8
w[i] |= t.CUInt64T(block[i * 8 + 7]) << 0
for i in range(16, 80):
w[i] = sha512_Sigma1(w[i-2]) + w[i-7] + sha512_Sigma0(w[i-15]) + w[i-16]
a = self.state[0]
b = self.state[1]
c = self.state[2]
d = self.state[3]
e = self.state[4]
f = self.state[5]
g = self.state[6]
h = self.state[7]
for i in range(80):
t1 = h + sha512_BigSigma1(e) + sha512_Ch(e, f, g) + sha512_K[i] + w[i]
t2 = sha512_BigSigma0(a) + sha512_Maj(a, b, c)
h = g; g = f; f = e
e = d + t1
d = c; c = b; b = a
a = t1 + t2
self.state[0] += a
self.state[1] += b
self.state[2] += c
self.state[3] += d
self.state[4] += e
self.state[5] += f
self.state[6] += g
self.state[7] += h
def update(self, s: str):
data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr)
length: t.CSizeT = len(s)
idx: t.CUInt32T = t.CUInt32T(self.count[0] % SHA512_BLOCK_LEN)
self.count[0] += length
if self.count[0] < length:
self.count[1] += 1
if idx > 0:
left: t.CSizeT = SHA512_BLOCK_LEN - idx
if length >= left:
string.memcpy(self.buf + idx, data, left)
self.transform(self.buf)
data += left
length -= left
idx = 0
while length >= SHA512_BLOCK_LEN:
self.transform(data)
data += SHA512_BLOCK_LEN
length -= SHA512_BLOCK_LEN
if length > 0:
string.memcpy(self.buf + idx, data, length)
def final(self, out: t.CArray[t.CUInt8T, SHA512_DIGEST_LEN]):
bits_lo: t.CUInt64T = self.count[0] << 3
bits_hi: t.CUInt64T = (self.count[1] << 3) | (self.count[0] >> 61)
idx: t.CUInt32T = t.CUInt32T(self.count[0] % SHA512_BLOCK_LEN)
self.buf[idx] = 0x80
idx += 1
if idx > SHA512_BLOCK_LEN - 16:
string.memset(self.buf + idx, 0, SHA512_BLOCK_LEN - idx)
self.transform(self.buf)
idx = 0
string.memset(self.buf + idx, 0, SHA512_BLOCK_LEN - 16 - idx)
for i in range(8):
self.buf[SHA512_BLOCK_LEN - 16 + i] = t.CUInt8T(bits_hi >> (56 - i * 8))
for i in range(8):
self.buf[SHA512_BLOCK_LEN - 8 + i] = t.CUInt8T(bits_lo >> (56 - i * 8))
self.transform(self.buf)
for i in range(8):
out[i * 8 + 0] = t.CUInt8T(self.state[i] >> 56)
out[i * 8 + 1] = t.CUInt8T(self.state[i] >> 48)
out[i * 8 + 2] = t.CUInt8T(self.state[i] >> 40)
out[i * 8 + 3] = t.CUInt8T(self.state[i] >> 32)
out[i * 8 + 4] = t.CUInt8T(self.state[i] >> 24)
out[i * 8 + 5] = t.CUInt8T(self.state[i] >> 16)
out[i * 8 + 6] = t.CUInt8T(self.state[i] >> 8)
out[i * 8 + 7] = t.CUInt8T(self.state[i] >> 0)
+242
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
import stdio
def helloworld():
stdio.printf("Hello, world!\n")
+237
View File
@@ -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
+291
View File
@@ -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)
+119
View File
@@ -0,0 +1,119 @@
import t, c
from stdint import *
import memhub
import string
from stdio import snprintf
from . import (
JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT,
JSON_STRING, JSON_ARRAY, JSON_OBJECT,
)
def _write_char(buf: t.CChar | t.CPtr, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT:
buf[pos] = ch
return pos + 1
def _write_str(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT:
if s == None: return pos
slen: t.CSizeT = string.strlen(s)
string.memcpy(t.CChar(t.CUInt64T(buf) + pos, t.CPtr), s, slen)
return pos + slen
def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT:
if s == None:
pos = _write_str(buf, pos, "null")
return pos
pos = _write_char(buf, pos, '"')
i: t.CSizeT = 0
slen: t.CSizeT = string.strlen(s)
while i < slen:
ch: t.CChar = s[i]
if ch == '"':
pos = _write_str(buf, pos, "\\\"")
elif ch == '\\':
pos = _write_str(buf, pos, "\\\\")
elif ch == '\n':
pos = _write_str(buf, pos, "\\n")
elif ch == '\r':
pos = _write_str(buf, pos, "\\r")
elif ch == '\t':
pos = _write_str(buf, pos, "\\t")
else:
pos = _write_char(buf, pos, ch)
i += 1
pos = _write_char(buf, pos, '"')
return pos
def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: memhub.MemManager | t.CPtr) -> t.CSizeT:
if val == None:
pos = _write_str(buf, pos, "null")
return pos
if val.vtype == JSON_NULL:
pos = _write_str(buf, pos, "null")
elif val.vtype == JSON_BOOL:
if val.bool_val != 0:
pos = _write_str(buf, pos, "true")
else:
pos = _write_str(buf, pos, "false")
elif val.vtype == JSON_INT:
tmp: t.CChar | t.CPtr = pool.alloc(32)
if tmp != None:
snprintf(tmp, 32, "%lld", val.int_val)
pos = _write_str(buf, pos, tmp)
elif val.vtype == JSON_FLOAT:
tmp2: t.CChar | t.CPtr = pool.alloc(32)
if tmp2 != None:
snprintf(tmp2, 32, "%.6g", val.float_val)
pos = _write_str(buf, pos, tmp2)
elif val.vtype == JSON_STRING:
pos = _write_string_escaped(buf, pos, val.str_val)
elif val.vtype == JSON_ARRAY:
if val.child == None:
pos = _write_str(buf, pos, "[]")
return pos
pos = _write_char(buf, pos, '[')
cur: JsonValue | t.CPtr = val.child
first: bool = True
while cur != None:
if not first:
pos = _write_char(buf, pos, ',')
pos = _write_value(buf, pos, cur, pool)
first = False
cur = cur.next
pos = _write_char(buf, pos, ']')
elif val.vtype == JSON_OBJECT:
if val.child == None:
pos = _write_str(buf, pos, "{}")
return pos
pos = _write_char(buf, pos, '{')
cur2: JsonValue | t.CPtr = val.child
first2: bool = True
while cur2 != None:
if not first2:
pos = _write_char(buf, pos, ',')
pos = _write_string_escaped(buf, pos, cur2.key)
pos = _write_char(buf, pos, ':')
pos = _write_value(buf, pos, cur2, pool)
first2 = False
cur2 = cur2.next
pos = _write_char(buf, pos, '}')
return pos
def write(pool: memhub.MemManager | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> t.CChar | t.CPtr:
"""将 JsonValue 序列化为 JSON 字符串"""
buf: t.CChar | t.CPtr = pool.alloc(4096)
if buf == None:
return None
end_pos: t.CSizeT = _write_value(buf, 0, val, pool)
buf[end_pos] = '\0'
return buf
+479
View File
@@ -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
+301
View File
@@ -0,0 +1,301 @@
# llvmlite 设计方案
用 TransPyC 自身实现的轻量级 LLVM IR 文本生成库,替代 Python `llvmlite` 依赖,为自举(见 `wiki/13-bootstrapping.md` 路径 B)铺路。
## 1. 目标与定位
- **输入**:类型/值/指令的语义对象
- **输出**:合法的 LLVM IR 文本(`.ll`),可直接喂给 `llc`
- **不做什么**:不解析 IR、不做优化、不绑定 LLVM C API(纯文本生成)
- **自举约束**:本库必须能用当前 TransPyC 编译器完整编译,不得依赖任何 Python 运行时
## 2. 核心设计决策
### 2.1 类型系统用 `t.REnum`(tagged union)
LLVM 类型变体少、无通用字段、字段都是指针/小整数、操作主要通过 `match` 分派 —— 完全契合 REnum 的 tag+union 模型。
### 2.2 指令 opcode 用 `t.CEnum`
指令类别(Binary/Unary/Cast/Memory/Terminator/Compare)与具体 opcode(Add/Sub/Load/Store/Br/Ret/...)用 `t.CEnum` 组织,类型安全且零开销。
### 2.3 IR 文本生成用 `viperlib.snprintf`
所有 IR 文本通过 `viperlib.snprintf(buf, size, fmt, *args)` 格式化写入缓冲区,避免手写逐字符拼接。`snprintf` 已支持宽度/精度/符号/`%s`/`%d`/`%x` 等,足够覆盖 IR 语法。
### 2.4 对象分配用普通类 + `mpool`
像 `mbuddy` 一样用普通类(无 `__new__`),由调用方注入 `mpool.MPool` 做批量分配。库内部不持有全局 `mbuddy`,遵循项目约定(`_mbuddy` 指针由 `os.vp` 或调用方设置)。
---
## 3. 为什么 AST 不用 REnum,而 llvmlite 用?
用户质疑:REnum 是 tag+union(Rust enum),配合 `match` 模式匹配,按理很适合 AST。下面解释两者的适配性差异。
### 3.1 REnum 的硬限制(来自 `HandlesClassDef._EmitREnumLlvm`)
1. **无通用字段共享**:每个 variant 独立声明字段,通用字段(如 `lineno`/`child`/`next`)必须在每 variant 重复声明。
2. **共享最大变体尺寸**:布局为 `{ i32 __tag, <max_variant_payload> }`,小变体浪费内存。
3. **payload 仅位置绑定**:`match` 通过位置绑定 payload,不能直接 `node.child` 属性访问 payload 字段。
4. **无方法**:variant 不能挂方法。
### 3.2 AST 不适合 REnum 的四个原因
| 维度 | AST 需求 | REnum 限制 | 冲突 |
|------|----------|------------|------|
| 变体数量 | 70+ 节点类型 | 共享最大变体尺寸 | 内存膨胀(每节点都占最大变体空间) |
| 通用字段 | lineno/child/next/parent 等 ~8 个字段全节点共享 | 无通用字段共享 | 要么每 variant 重复声明(冗长),要么放弃统一访问 |
| 访问模式 | 频繁直接 `node.child`/`node.next`/`node.lineno` | payload 仅位置绑定,需 match 分派 | 遍历代码爆炸(每次访问都要 match) |
| 字段复用 | `int_val`/`str_val`/`op` 等字段按 vtype 复用语义 | 每 variant 独立 payload | 无法复用 |
AST 采用"胖节点"设计(所有节点共用一个 `AST` struct,用 `vtype` 区分):一次 `malloc`、统一链表遍历(`child`/`next`)、字段复用。这与 REnum"每变体独立 payload"的哲学根本冲突。
### 3.3 llvmlite 的 LLVMType 适合 REnum 的原因
| 维度 | LLVMType 需求 | REnum 特性 | 契合度 |
|------|---------------|------------|--------|
| 变体数量 | ~10 个(Int/Ptr/Func/Array/Struct/Void/Float/Label/...) | 共享最大变体尺寸 | 浪费可接受(最大变体 ~24 字节) |
| 通用字段 | 无(每变体字段不同) | 无通用字段共享 | 完美匹配 |
| 访问模式 | 类型操作天然通过 match 分派("是 Int 取 bits,是 Ptr 取 pointee") | payload 位置绑定 + match | 天然契合 |
| 字段尺寸 | 都是指针(8B)或小整数(4B) | 共享最大变体 | 浪费小 |
**结论**:REnum 是"少变体、无共性、match 分派"场景的最佳工具 —— llvmlite 类型系统正好如此,AST 正好相反。
---
## 4. 文件结构
```
includes/llvmlite/
├── __init__.vp # 公共导出 + 便捷工厂函数
├── __types.vp # LLVMType (REnum) + 类型构造/打印
├── __values.vp # Value/Constant/SSA 值表示
├── __module.vp # Module 容器(函数列表 + 目标三元组 + 输出 .ll)
├── __function.vp # Function + BasicBlock + 参数管理
├── __builder.vp # IRBuilder(指令发射 + SSA 命名 + 块跳转)
└── README.md # 本文件
```
### 职责划分
- `__types.vp`:`LLVMType` REnum 定义 + `TypePrint(buf, ty)` 将类型序列化为 IR 文本(如 `i32`/`i32*`/`{i32, i8*}`)
- `__values.vp`:`Value` 表示一个 SSA 值(`%0`/`%result`/常量),含类型指针 + 名字 + 是否常量
- `__module.vp`:`Module` 持有函数链表 + 目标三元组 + 数据布局,`ModulePrint` 输出完整 `.ll`
- `__function.vp`:`Function` 持有基本块链表 + 参数 + 返回类型;`BasicBlock` 持有指令文本缓冲
- `__builder.vp`:`IRBuilder` 游标式 API,`build_add`/`build_load`/`build_br`/... 发射指令到当前块
---
## 5. 类型系统设计(REnum)
```python
import t
from stdint import *
class LLVMType(t.REnum):
# 变体 Int:整数类型
IntBits: t.CInt # 位宽 1/8/16/32/64/128
# 变体 Ptr:指针类型
PtrPointee: LLVMType | t.CPtr # 指向的类型(自引用用指针)
# 变体 Func:函数类型
FuncRet: LLVMType | t.CPtr # 返回类型
FuncParams: LLVMType | t.CPtr # 参数类型链表头
FuncPCount: t.CInt # 参数数量
# 变体 Array:数组类型
ArrayElem: LLVMType | t.CPtr # 元素类型
ArrayCount: t.CInt # 元素数量
# 变体 Struct:结构体类型
StructHead: LLVMType | t.CPtr # 字段类型链表头
StructCount: t.CInt # 字段数量
# 变体 Float:浮点类型
FloatBits: t.CInt # 16/32/64/128
# 变体 Void / Label / Metadata:无 payload
# (REnum 允许空变体,仅靠 __tag 区分)
```
### 类型工厂(`__init__.vp` 导出)
```python
def Int1() -> LLVMType | t.CPtr: ... # i1
def Int8() -> LLVMType | t.CPtr: ... # i8
def Int32() -> LLVMType | t.CPtr: ... # i32
def Int64() -> LLVMType | t.CPtr: ... # i64
def Ptr(pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: ...
def Func(ret: LLVMType | t.CPtr, params: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: ...
def Void() -> LLVMType | t.CPtr: ...
```
### 类型打印(match 分派)
```python
def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr):
match ty:
case LLVMType.Int: # 位置绑定 IntBits
viperlib.snprintf(buf, size, "i%d", ty.IntBits)
case LLVMType.Ptr: # 位置绑定 PtrPointee
TypePrint(inner, size2, ty.PtrPointee)
# 拼接 "*"
case LLVMType.Func:
# 打印 ret (params)
case LLVMType.Void:
string.strcpy(buf, "void")
...
```
---
## 6. Value / SSA 设计
```python
class Value:
Ty: LLVMType | t.CPtr # 值的类型
Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本
IsConst: t.CInt # 1=常量字面量,0=SSA 临时值
Next: Value | t.CPtr # 链表(函数内的值池)
```
`IRBuilder` 维护一个递增的 `%N` 计数器,每发射一条产生结果的指令就分配一个新名。
---
## 7. IRBuilder 设计
游标式 API,跟踪当前 `BasicBlock`,发射指令文本到块的缓冲区。
```python
class IRBuilder:
Func: Function | t.CPtr # 所属函数
CurBlock: BasicBlock | t.CPtr # 当前插入点
Counter: t.CInt # SSA 名计数器
def build_add(self, lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
# 1. 分配 SSA 名 %N
# 2. snprintf(buf, size, " %%%d = add %s %s, %s\n", N, ty, lhs, rhs)
# 3. 追加到 CurBlock 缓冲
# 4. 返回新 Value
def build_load(self, ty: LLVMType | t.CPtr, ptr: Value | t.CPtr) -> Value | t.CPtr: ...
def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr): ...
def build_br(self, target: BasicBlock | t.CPtr): ...
def build_cond_br(self, cond: Value | t.CPtr, then: BasicBlock | t.CPtr, else_: BasicBlock | t.CPtr): ...
def build_ret(self, val: Value | t.CPtr): ...
def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: ...
def build_gep(self, ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: ...
def build_call(self, callee: t.CChar | t.CPtr, args: Value | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: ...
```
### 指令 opcode(CEnum)
```python
class IROp(t.CEnum):
# Terminator
Ret: t.CEnum = 1
Br: t.CEnum = 2
CondBr: t.CEnum = 3
Switch: t.CEnum = 4
# Binary
Add: t.CEnum = 10
Sub: t.CEnum = 11
Mul: t.CEnum = 12
SDiv: t.CEnum = 13
# Memory
Load: t.CEnum = 20
Store: t.CEnum = 21
Alloca: t.CEnum = 22
Gep: t.CEnum = 23
# Cast
BitCast: t.CEnum = 30
SExt: t.CEnum = 31
Trunc: t.CEnum = 32
# Compare
ICmp: t.CEnum = 40
# Call
Call: t.CEnum = 50
```
---
## 8. IR 文本生成(snprintf 用法)
每条指令发射用 `viperlib.snprintf` 格式化到块缓冲区。示例:
```python
import viperlib
def _emit_add(block: BasicBlock | t.CPtr, name: t.CChar | t.CPtr,
ty_str: t.CChar | t.CPtr, lhs: t.CChar | t.CPtr, rhs: t.CChar | t.CPtr):
line: t.CChar | t.CPtr = mpool.alloc(128) # 行缓冲
viperlib.snprintf(line, 128, " %s = add %s %s, %s\n", name, ty_str, lhs, rhs)
_block_append(block, line)
```
### Module 输出
```python
def ModulePrint(mod: Module | t.CPtr, out_path: t.CChar | t.CPtr):
# 1. 写头部:target triple / datalayout
# 2. 遍历函数,写 declare/define
# 3. 每函数:签名 + 基本块 + 指令
# 用 snprintf 拼接,写到文件(viperio 或 w32/win32file)
```
---
## 9. 内存管理
- 库内所有对象从 `mpool.MPool` 分配(像 `ast` 库一样)
- `IRBuilder`/`Module`/`Function` 不持有 `mbuddy`,由调用方传入 `mpool`
- 文本缓冲区按行分配(每指令一行,128 字节起步),避免频繁 realloc
---
## 10. 基础构建范围(第一阶段)
最小可用集,能生成一个完整的小程序 IR:
1. **类型**:`IntType`(1/8/16/32/64) + `PointerType` + `FunctionType` + `VoidType` + `StructType`
2. **值**:`Value` + 常量整数字面量
3. **Module/Function/BasicBlock**:容器与链表
4. **IRBuilder** 指令子集:
- `alloca` / `load` / `store`
- `add` / `sub` / `mul` / `sdiv`
- `icmp` (eq/ne/sgt/sge/slt/sle)
- `br` / `cond_br` / `ret`
- `call`(外部函数)
- `bitcast` / `sext` / `trunc`
- `getelementptr`
5. **ModulePrint**:输出完整 `.ll` 文件
### 后续扩展路线
- **第二阶段**:浮点指令、`phi` 节点、`switch`、字符串常量全局、属性(`nounwind`/`nocapture`)
- **第三阶段**:内联汇编、`atomic` 指令、`va_arg`、精确的 SSA 验证(支配边界、phi 完整性)
- **第四阶段**:对接 TransPyC 的 `LLVMCG`,替换 Python `llvmlite`,完成路径 B 自举
---
## 11. 测试计划
独立测试项目(`Test/LLvmLiteTest/`):
1. **类型打印测试**:构造各 `LLVMType`,`TypePrint` 输出,对比预期字符串
2. **小函数生成**:用 `IRBuilder` 生成 `i32 add(i32 a, i32 b) { ret i32 %r }`,`ModulePrint` 写 `.ll`,用 `llc` 编译验证语法合法
3. **match 分派测试**:构造各变体 `LLVMType`,`match` 正确绑定 payload
4. **snprintf 格式测试**:验证 `%d`/`%s`/`%x` 在 IR 文本中的正确性
---
## 12. 与现有架构的对接点
- **`lib/core/Codegen/LLVMCG.py`**:当前用 Python `llvmlite` 生成 IR,自举时改用本库
- **`includes/viperlib.vp`**:提供 `snprintf` / `sprintf`
- **`includes/mpool.vp`**:提供 `MPool` 内存池
- **`includes/string.vp`**:提供 `strcpy`/`strlen`/`memcpy`
- **`includes/ast/`**:参考其"胖节点 + mpool + CEnum 常量"的组织方式(但类型系统用 REnum 而非胖节点)
File diff suppressed because it is too large. Load diff
+811
View File
@@ -0,0 +1,811 @@
import t, c
from stdint import *
import string
import viperlib
import memhub
import stdio
from linkedlist import GSListNode, GSList
from .__types import LLVMType, ParamNode, TypePrint
# ============================================================
# Line: 指令文本行
#
# 每条 LLVM IR 指令序列化为一行文本,通过链表组织。
# 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr
#
# 注意: 必须加 @t.NoVTable。否则 TransPyC 为子类添加 vtable 指针(T*),
# 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位,
# 所有字段访问读取垃圾值(见续 XV 会话根因分析)。
# ============================================================
@t.NoVTable
class Line(GSListNode[Line]):
Buf: t.CChar | t.CPtr # 行文本(NUL 结尾)
Len: t.CSizeT # 文本长度(不含 NUL)
# ============================================================
# BasicBlock: 基本块
#
# 持有名称 + 指令行链表 + 终止指令标志。
# 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr
# Lines 为 GSList[Line] 指针,提供 O(1) 追加。
#
# 注意: 必须加 @t.NoVTable(理由同 Line)。
# ============================================================
@t.NoVTable
class BasicBlock(GSListNode[BasicBlock]):
Name: t.CChar | t.CPtr # 块名(如 "entry"/"if.then")
Lines: GSList[Line] | t.CPtr # 指令行链表容器(Head/Tail/Count)
IsTerminated: t.CInt # 1=已有终止指令(br/ret)
# ============================================================
# Param: 函数参数
#
# 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr
# Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"),None=无属性
#
# 注意: 必须加 @t.NoVTable(理由同 Line)。
# ============================================================
@t.NoVTable
class Param(GSListNode[Param]):
Ty: LLVMType | t.CPtr # 参数类型
Name: t.CChar | t.CPtr # 参数名(如 "%0"/"%a")
Attrs: t.CChar | t.CPtr # 参数属性文本(None=无属性)
# ============================================================
# Function: 函数
#
# 持有名称 + 返回类型 + 参数链表 + 基本块链表。
# 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr
# Params/Blocks 为 GSList 指针,提供 O(1) 追加。
# Attrs 存储函数级属性文本(如 "nounwind"/"noinline"),None=无属性
#
# 注意: 必须加 @t.NoVTable(理由同 Line)。
# ============================================================
@t.NoVTable
class Function(GSListNode[Function]):
Name: t.CChar | t.CPtr # 函数名
RetTy: LLVMType | t.CPtr # 返回类型
Params: GSList[Param] | t.CPtr # 参数链表容器
Blocks: GSList[BasicBlock] | t.CPtr # 基本块链表容器
IsDeclared: t.CInt # 1=仅声明(declare), 0=定义(define)
IsVarArg: t.CInt # 1=变参函数(...)
Attrs: t.CChar | t.CPtr # 函数属性文本(None=无属性)
# ============================================================
# 工厂函数
# ============================================================
# Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节
LINE_SIZE: t.CDefine = 24
def new_line(pool: memhub.MemBuddy | t.CPtr, text: t.CChar | t.CPtr) -> Line | t.CPtr:
"""创建一个指令行,复制 text 到新分配的缓冲区"""
ptr: Line | t.CPtr = pool.alloc(LINE_SIZE)
if ptr is None: return None
string.memset(ptr, 0, LINE_SIZE)
if text is not None:
slen: t.CSizeT = string.strlen(text)
buf: t.CChar | t.CPtr = pool.alloc(slen + 1)
if buf is not None:
string.strcpy(buf, text)
ptr.Buf = buf
ptr.Len = slen
return ptr
def _new_gslist(pool: memhub.MemBuddy | t.CPtr, list_size: t.CSizeT) -> t.CPtr:
"""从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)"""
gsl: t.CPtr = pool.alloc(list_size)
if gsl is None: return None
string.memset(gsl, 0, list_size)
return gsl
# BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节
BLOCK_SIZE: t.CDefine = 32
def new_basic_block(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
"""创建一个基本块"""
ptr: BasicBlock | t.CPtr = pool.alloc(BLOCK_SIZE)
if ptr is None: return None
string.memset(ptr, 0, BLOCK_SIZE)
ptr.Name = name
ptr.Lines = _new_gslist(pool, 24) # GSList: Head+Tail+Count
ptr.IsTerminated = 0
return ptr
# Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节
PARAM_SIZE: t.CDefine = 32
def new_param(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Param | t.CPtr:
"""创建一个函数参数"""
ptr: Param | t.CPtr = pool.alloc(PARAM_SIZE)
if ptr is None: return None
string.memset(ptr, 0, PARAM_SIZE)
ptr.Ty = ty
ptr.Name = name
ptr.Attrs = None
return ptr
# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) = 56 字节
FUNC_SIZE: t.CDefine = 56
def new_function(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr,
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建一个函数"""
ptr: Function | t.CPtr = pool.alloc(FUNC_SIZE)
if ptr is None: return None
string.memset(ptr, 0, FUNC_SIZE)
ptr.Name = name
ptr.RetTy = ret_ty
ptr.Params = _new_gslist(pool, 24) # GSList: Head+Tail+Count
ptr.Blocks = _new_gslist(pool, 24)
ptr.IsDeclared = 0
ptr.Attrs = None
return ptr
# ============================================================
# 链表操作(委托 GSList.append)
# ============================================================
def function_add_param(func: Function | t.CPtr, param: Param | t.CPtr):
"""将参数追加到函数参数链表"""
if func is None or param is None: return
if func.Params is None: return
func.Params.append(param)
def function_add_block(func: Function | t.CPtr, block: BasicBlock | t.CPtr):
"""将基本块追加到函数块链表"""
if func is None or block is None: return
if func.Blocks is None: return
func.Blocks.append(block)
def function_move_block_to_end(func: Function | t.CPtr, block: BasicBlock | t.CPtr):
"""将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。
用于解决 SSA 名非单调问题:BB 按创建顺序排列,但指令按控制流顺序生成,
导致 SSA 编号在文本输出时非单调递增,llc 报错。
在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。
注意:必须使用 GSList[BasicBlock] 带类型参数,否则 TransPyC 创建不完整
struct 类型,导致 blocks.Head/Tail/Count 字段访问读取垃圾值。
"""
if func is None or block is None: return
blocks: GSList[BasicBlock] | t.CPtr = func.Blocks
if blocks is None: return
# 已经是 Tail,无需移动
if blocks.Tail is block:
return
# 从链表中移除 block
if blocks.Head is block:
# block 是 Head,直接后移 Head
blocks.Head = block.Next
else:
# 遍历找前驱
prev: BasicBlock | t.CPtr = blocks.Head
while prev is not None and prev.Next is not block:
prev = prev.Next
if prev is None:
# block 不在链表中,直接 append
blocks.append(block)
return
prev.Next = block.Next
# block.Next 由移除逻辑处理,重置为 None
block.Next = None
# append 到末尾(不调用 blocks.append 以避免 Count 重复递增)
if blocks.Tail is not None:
blocks.Tail.Next = block
blocks.Tail = block
def block_append_line(block: BasicBlock | t.CPtr, line: Line | t.CPtr):
"""将指令行追加到基本块"""
if block is None or line is None: return
if block.Lines is None: return
block.Lines.append(line)
def block_set_terminated(block: BasicBlock | t.CPtr, val: t.CInt):
"""设置块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)"""
if block is None: return
block.IsTerminated = val
def block_get_terminated(block: BasicBlock | t.CPtr) -> t.CInt:
"""获取块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)"""
if block is None:
return 1
return block.IsTerminated
def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr,
text: t.CChar | t.CPtr):
"""创建指令行并追加到基本块"""
if block is None or text is None: return
line: Line | t.CPtr = new_line(pool, text)
if line is not None:
block_append_line(block, line)
def block_insert_text_before_terminator(pool: memhub.MemBuddy | t.CPtr,
block: BasicBlock | t.CPtr,
text: t.CChar | t.CPtr):
"""创建指令行并插入到基本块终止指令之前
如果块未终止,追加到末尾。
如果块已终止(有 br/ret),在终止指令之前插入,确保 alloca 等指令
不出现在终止指令之后。
"""
if block is None or text is None: return
if block.Lines is None: return
line: Line | t.CPtr = new_line(pool, text)
if line is None: return
# 块未终止:直接追加
if block.IsTerminated == 0:
block_append_line(block, line)
return
# 块已终止:在 Tail(终止指令)之前插入
lines: GSList[Line] | t.CPtr = block.Lines
if lines.Head is None:
block_append_line(block, line)
return
# 只有一个节点:在 Head 之前插入
if lines.Head is lines.Tail:
line.Next = lines.Head
lines.Head = line
lines.Count += 1
return
# 找到 Tail 的前驱节点
prev: Line | t.CPtr = lines.Head
while prev is not None and prev.Next is not lines.Tail:
prev = prev.Next
if prev is None:
# 找不到前驱,回退到追加
block_append_line(block, line)
return
# 在 prev 和 Tail 之间插入 line
line.Next = lines.Tail
prev.Next = line
lines.Count += 1
# ============================================================
# 属性设置
# ============================================================
def function_set_attrs(func: Function | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置函数级属性文本(如 "nounwind"/"noinline")"""
if func is None: return
func.Attrs = attrs
def param_set_attrs(param: Param | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置参数属性文本(如 "noundef"/"nocapture"/"readonly")"""
if param is None: return
param.Attrs = attrs
# ============================================================
# _ll_name_needs_quote - 检查 LLVM 标识符是否需要加引号
#
# LLVM IR 规范:标识符合法字符集为 [-a-zA-Z$._][-a-zA-Z$._0-9]*
# 以数字开头或含非合法字符(如 '['、']'、' '、'@' 等)时必须用双引号包围。
# '.' 是合法字符,不需要加引号(如 @.str、@llvm.memcpy 都不加引号)。
# SHA1 命名空间的函数名(如 "4dad2ba72ed7ba09.GSListNode[Param]")含 '['、']',
# 需要加引号;但纯 hex+点 的名字(如 "abc.def")不需要。
# ============================================================
def _ll_name_needs_quote(name: str) -> t.CInt:
"""检查 LLVM 标识符是否需要加引号(以数字开头或含非合法字符)
LLVM IR 合法字符:a-z, A-Z, 0-9, -, $, ., _
首字符是数字时需要加引号(LLVM 要求局部/全局标识符首字符非数字,除非加引号)。
含其他字符(如 '['、']'、空格)时需要加引号。
"""
if name is None:
return 0
c0: t.CChar = name[0]
if c0 >= '0' and c0 <= '9':
return 1
name_len: t.CSizeT = string.strlen(name)
i: t.CSizeT = 0
while i < name_len:
ch: t.CChar = name[i]
# 合法字符:a-z, A-Z, 0-9, -, $, ., _
if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or
(ch >= '0' and ch <= '9') or ch == '-' or ch == '$' or
ch == '.' or ch == '_'):
return 1
i += 1
return 0
# ============================================================
# RenumberSSA: 重编号函数内数字 SSA 名
#
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
# SSA 名在文本输出中非单调递增的问题(llc 报错:
# "instruction expected to be numbered '%N' or greater")。
#
# 现象: entry 块原指令 %0-%6 + br,alloca_at_entry 插入 %28/%41 到 br 之前,
# 文本输出顺序为 entry(%0..%6, %28, %41) → if.then(%7..%27),
# 导致 %28 出现在 %7 之前,llc 拒绝编译。
#
# 算法:
# 1. 扫描所有 BB 指令行,按文本输出顺序收集数字 SSA 名 %N
# 2. 按首次出现顺序建立 old→new 映射(从 0 递增)
# 3. 替换所有指令行文本中的 %N 为新编号
#
# 注意:
# - 仅重编号纯数字 SSA 名(%0, %1, ...)
# - 命名 SSA 名(%entry, %.tmp, %self)、块标签、全局符号 @N 不重编号
# - 仅对 define(有函数体)调用,declare 无函数体无需处理
# - 当前 TransPyV 参数多为命名(%self/%env/%n),非数字,无需重编号参数
# ============================================================
# 判定字符是否为十进制数字
def _is_digit_ch(ch: t.CChar) -> t.CInt:
"""判断字符是否是 '0'-'9'
ch 是值类型 (t.CChar = i8),TPC 已修复值类型 is None 处理:
值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。
"""
if ch is None:
return 0
if ch >= '0' and ch <= '9':
return 1
return 0
# ============================================================
# i32 数组的安全访问(显式字节偏移)
#
# TransPyC 的 ptr[i] 指针索引可能被当作字节索引(i8*)而非 i32* 索引,
# 导致内存损坏。必须显式计算字节偏移:addr = base + idx * 4,再转型为 i32*。
# 参见 HandlesTranslator.py:358 的 t.CUInt64T(ptr) + offset * sizeof 用法。
# ============================================================
def _map_get_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt) -> t.CInt:
"""读取 i32 数组 map_arr[idx](显式字节偏移 idx*4)
使用 (t.CInt | t.CPtr)(uint64) 强转将字节偏移转为 i32*,再用 c.Deref 解引用。
TPC 已修复类型联合强转(_HandleTypeUnionCastLlvm 添加 fallback),此写法可用。
"""
if map_arr is None:
return -1
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off)
return c.Deref(elem_ptr)
def _map_set_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt, val: t.CInt):
"""写入 map_arr[idx] = val(i32 数组,显式字节偏移 idx*4)
使用 (t.CInt | t.CPtr)(uint64) 强转 + c.DerefAs 解引用赋值。
TPC 已修复类型联合强转,此写法可用。
"""
if map_arr is None:
return
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off)
c.DerefAs(elem_ptr, val)
def _scan_max_ssa_in_text(text: t.CChar | t.CPtr, cur_max: t.CInt) -> t.CInt:
"""扫描文本,找出 %N(N 为数字)中最大的 N,与 cur_max 比较返回更大值
仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。
"""
result: t.CInt = cur_max
p: t.CChar | t.CPtr = text
while p is not None and p[0] != '\0':
if p[0] == '%':
nxt: t.CChar | t.CPtr = p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: t.CInt = string.atoi(nxt)
if num > result:
result = num
p = p + 1
return result
def _find_max_ssa_number(func: Function | t.CPtr) -> t.CInt:
"""遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1"""
max_n: t.CInt = -1
if func is None or func.Blocks is None:
return max_n
blk: BasicBlock | t.CPtr = func.Blocks.Head
while blk is not None:
if blk.Lines is not None:
line: Line | t.CPtr = blk.Lines.Head
while line is not None:
if line.Buf is not None:
max_n = _scan_max_ssa_in_text(line.Buf, max_n)
line = line.Next
blk = blk.Next
return max_n
def _assign_new_numbers(text: t.CChar | t.CPtr,
map_arr: t.CChar | t.CPtr,
max_n: t.CInt, next_new: t.CInt) -> t.CInt:
"""扫描文本,对每个 %N(数字),若 map_arr[N]==-1 则分配 next_new
返回更新后的 next_new。按文本首次出现顺序建立映射。
"""
result: t.CInt = next_new
p: t.CChar | t.CPtr = text
while p is not None and p[0] != '\0':
if p[0] == '%':
nxt: t.CChar | t.CPtr = p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: t.CInt = string.atoi(nxt)
if num >= 0 and num <= max_n:
if _map_get_i32(map_arr, num) == -1:
_map_set_i32(map_arr, num, result)
result += 1
p = p + 1
return result
def _replace_ssa_numbers(text: t.CChar | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
map_arr: t.CChar | t.CPtr,
max_n: t.CInt) -> t.CChar | t.CPtr:
"""构建新文本,将 %N 替换为映射后的新编号
逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。
返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。
"""
src_len: t.CSizeT = string.strlen(text)
# 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64
new_size: t.CSizeT = src_len * 2 + 64
new_buf: t.CChar | t.CPtr = pool.alloc(new_size)
if new_buf is None:
return None
# 一次性分配数字缓冲区(循环中复用)
num_buf: t.CChar | t.CPtr = pool.alloc(16)
if num_buf is None:
new_buf[0] = '\0'
return new_buf
dst_idx: t.CSizeT = 0
src_p: t.CChar | t.CPtr = text
while src_p is not None and src_p[0] != '\0':
if dst_idx + 16 >= new_size:
# 缓冲区不足,截断
break
if src_p[0] == '%':
nxt: t.CChar | t.CPtr = src_p + 1
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
num: t.CInt = string.atoi(nxt)
# 先做范围检查再读 map_arr:num 超 max_n 时 map_arr 只有
# (max_n+1)*4 字节,先读后查会越界读远端内存
if num >= 0 and num <= max_n:
new_num: t.CInt = _map_get_i32(map_arr, num)
if new_num != -1:
# 写入 '%'
new_buf[dst_idx] = '%'
dst_idx += 1
# 写入新编号
num_buf[0] = '\0'
viperlib.snprintf(num_buf, 16, "%d", new_num)
k: t.CSizeT = 0
while num_buf[k] != '\0' and dst_idx + 1 < new_size:
new_buf[dst_idx] = num_buf[k]
dst_idx += 1
k += 1
# 跳过旧数字字符
src_p = src_p + 1
while src_p is not None and _is_digit_ch(src_p[0]) != 0:
src_p = src_p + 1
continue
# 普通字符:直接复制
new_buf[dst_idx] = src_p[0]
dst_idx += 1
src_p = src_p + 1
new_buf[dst_idx] = '\0'
return new_buf
def RenumberSSA(func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增
在 FunctionPrint 序列化函数体之前调用。
仅对 define(IsDeclared==0)且 Blocks 非空 的函数生效。
"""
if func is None or pool is None:
return
if func.IsDeclared == 1:
return # declare 无函数体
if func.Blocks is None:
return
# 1. 第一遍扫描:找出最大 SSA 编号
max_n: t.CInt = _find_max_ssa_number(func)
if max_n < 0:
return # 无数字 SSA 名
# 2. 分配并初始化映射数组 map_arr[0..max_n] = -1
# 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。
# 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。
# 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。
map_bytes: t.CSizeT = (max_n + 1) * 4 # t.CInt = 4 字节
map_arr: t.CChar | t.CPtr = pool.alloc(map_bytes)
if map_arr is None:
return
string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1
# 3. 第二遍扫描:按文本顺序分配新编号
next_new: t.CInt = 0
blk: BasicBlock | t.CPtr = func.Blocks.Head
while blk is not None:
if blk.Lines is not None:
line: Line | t.CPtr = blk.Lines.Head
while line is not None:
if line.Buf is not None:
next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new)
line = line.Next
blk = blk.Next
# 4. 检查是否有需要重编号的(old != new)
need_renumber: t.CInt = 0
i: t.CInt = 0
while i <= max_n:
v: t.CInt = _map_get_i32(map_arr, i)
if v != -1 and v != i:
need_renumber = 1
break
i += 1
if need_renumber == 0:
return # 编号已单调,无需替换
# 5. 第三遍扫描:替换所有指令行文本
blk = func.Blocks.Head
while blk is not None:
if blk.Lines is not None:
line: Line | t.CPtr = blk.Lines.Head
while line is not None:
if line.Buf is not None:
new_buf: t.CChar | t.CPtr = _replace_ssa_numbers(
line.Buf, pool, map_arr, max_n)
if new_buf is not None:
line.Buf = new_buf
line.Len = string.strlen(new_buf)
line = line.Next
blk = blk.Next
# ============================================================
# FunctionPrint: 将函数序列化为 IR 文本
#
# 格式:
# define <ret_ty> @<name>(<params>) {
# <block_name>:
# <instruction>
# <instruction>
# <block_name>:
# <instruction>
# }
# ============================================================
def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""将函数 func 序列化为 IR 文本写入 buf"""
if func is None or buf is None or size == 0: return
# 在序列化前重编号数字 SSA 名,确保按文本输出顺序单调递增。
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
# SSA 名非单调(llc 报错 "instruction expected to be numbered '%N' or greater")。
# RenumberSSA 内部会跳过 declare 函数(IsDeclared==1),无需在此判断。
RenumberSSA(func, pool)
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
if ty_buf is None: return
ty_buf[0] = '\0'
# define <ret_ty> @<name>(<params>)
if func.IsDeclared == 1:
_append_cstr(buf, size, "declare ")
else:
# 泛型特化类方法(如 GSList[NameEntry].__before_init__):多个模块各自
# 特化生成同名定义 → ld.lld duplicate symbol warning。特化方法代码由
# 相同模板+类型参数生成,定义相同,输出 linkonce_odr 让链接器合并。
if func.Name is not None and string.strchr(func.Name, 91) is not None:
_append_cstr(buf, size, "define linkonce_odr ")
else:
_append_cstr(buf, size, "define ")
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, func.RetTy, pool)
_append_cstr(buf, size, ty_buf)
_append_cstr(buf, size, " @")
if func.Name is not None:
if _ll_name_needs_quote(func.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, func.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, func.Name)
_append_cstr(buf, size, "(")
# 参数列表(从 GSList[Param].Head 遍历)
cur: Param | t.CPtr = None
if func.Params is not None:
cur = func.Params.Head
first: t.CInt = 1
while cur is not None:
if first == 0:
_append_cstr(buf, size, ", ")
# 参数属性(如 "noundef"/"nocapture")在类型之前
if cur.Attrs is not None:
_append_cstr(buf, size, cur.Attrs)
_append_cstr(buf, size, " ")
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, cur.Ty, pool)
_append_cstr(buf, size, ty_buf)
# declare 和 define 都打印参数名(如果有)
if cur.Name is not None:
_append_cstr(buf, size, " ")
# LLVM IR 要求参数名以 % 开头
if cur.Name[0] != '%':
_append_cstr(buf, size, "%")
_append_cstr(buf, size, cur.Name)
cur = cur.Next
first = 0
# 变参函数追加 ...
if func.IsVarArg == 1:
if func.Params is not None and func.Params.Head is not None:
_append_cstr(buf, size, ", ...")
else:
_append_cstr(buf, size, "...")
_append_cstr(buf, size, ")")
# 函数级属性(如 "nounwind"/"noinline")在 ) 之后
if func.Attrs is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, func.Attrs)
if func.IsDeclared == 1:
_append_cstr(buf, size, "\n")
return
# 函数体
_append_cstr(buf, size, " {\n")
blk: BasicBlock | t.CPtr = None
if func.Blocks is not None:
blk = func.Blocks.Head
while blk is not None:
# 块标签
if blk.Name is not None:
_append_cstr(buf, size, blk.Name)
_append_cstr(buf, size, ":\n")
# 指令行(从 GSList[Line].Head 遍历)
line: Line | t.CPtr = None
if blk.Lines is not None:
line = blk.Lines.Head
has_lines: t.CInt = 0
while line is not None:
if line.Buf is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, line.Buf)
_append_cstr(buf, size, "\n")
has_lines = 1
line = line.Next
# 块未终止兜底:LLVM IR 要求每个基本块以终止指令(br/ret/unreachable)结尾。
# 两种情况需要补 unreachable:
# 1. 空块(has_lines==0):标签后无任何指令
# 2. 有指令但未终止(IsTerminated==0):如 break/continue 后的 dead.N 块
# 被后续语句填入指令但缺少终止符,导致下一个标签处报
# "expected instruction opcode"
if has_lines == 0 or blk.IsTerminated == 0:
_append_cstr(buf, size, " unreachable\n")
blk = blk.Next
_append_cstr(buf, size, "}\n")
# ============================================================
# 内部辅助
# ============================================================
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 C 字符串 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外
if dlen >= dst_size:
return
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型
# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过
# 字段访问(不生成 GEP,不报错),字段值永远为 null。
#
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问
# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。
# ============================================================
def function_get_name(func: Function | t.CPtr) -> t.CChar | t.CPtr:
"""获取函数名"""
if func is None:
return None
return func.Name
def function_get_ret_ty(func: Function | t.CPtr) -> LLVMType | t.CPtr:
"""获取函数返回类型"""
if func is None:
return None
return func.RetTy
def function_get_params(func: Function | t.CPtr) -> GSList[Param] | t.CPtr:
"""获取函数参数链表容器"""
if func is None:
return None
return func.Params
def function_get_param_head(func: Function | t.CPtr) -> Param | t.CPtr:
"""获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)"""
if func is None:
return None
if func.Params is None:
return None
return func.Params.Head
def function_get_next(func: Function | t.CPtr) -> Function | t.CPtr:
"""获取链表下一个函数"""
if func is None:
return None
return func.Next
def function_is_declared(func: Function | t.CPtr) -> t.CInt:
"""获取函数是否为声明(1=declare 仅声明, 0=define 定义)"""
if func is None:
return 0
return func.IsDeclared
def param_get_name(param: Param | t.CPtr) -> t.CChar | t.CPtr:
"""获取参数名"""
if param is None:
return None
return param.Name
def param_get_ty(param: Param | t.CPtr) -> LLVMType | t.CPtr:
"""获取参数类型"""
if param is None:
return None
return param.Ty
def param_get_next(param: Param | t.CPtr) -> Param | t.CPtr:
"""获取链表下一个参数"""
if param is None:
return None
return param.Next
+423
View File
@@ -0,0 +1,423 @@
import t, c
from stdint import *
import memhub
import string
import viperlib
# 导入子模块
from .__types import (
LLVMType, ParamNode, LLVMTypeCore,
Int1, Int8, Int16, Int32, Int64, Ptr, Func, Void, Array, Struct,
Half, Float, Double, FP128, Label,
new_param_node, param_list_append,
paramnode_get_ty, paramnode_get_next, paramnode_set_ty, paramnode_set_next,
TypePrint, PrintStructDefinition, get_struct_name,
get_struct_fields, get_struct_fcount, DeepCopyType,
)
from .__values import (
Value, new_value, ConstInt, ConstNull, ConstZero, ConstFloat, SSAValue, ValuePrint,
value_get_ty, value_get_next,
value_set_ty, value_set_next, value_set_name, value_set_isconst,
)
from .__function import (
Line, BasicBlock, Param, Function,
new_line, new_basic_block, new_param, new_function,
function_add_param, function_add_block,
block_append_line, block_append_text,
function_set_attrs, param_set_attrs,
function_get_name, function_get_ret_ty, function_get_params,
function_get_param_head, function_get_next, function_is_declared,
param_get_name, param_get_ty, param_get_next,
FunctionPrint,
)
from .__module import (
LLVMModule, GlobalVariable, NamedTypeNode, new_module, new_global_variable,
module_add_function, module_add_global, module_add_named_type,
module_set_target, module_set_datalayout,
global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section,
LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT,
module_ensure_opaque_for_type,
)
from .__builder import (
IRBuilder, new_builder, position_at_end,
builder_cur_block_is_terminated,
build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store,
build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem,
build_and, build_or, build_xor, build_shl, build_lshr, build_ashr,
build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg,
build_icmp, build_fcmp,
build_br, build_cond_br, build_ret, build_ret_void,
build_call, build_call_indirect, build_bitcast, build_sext, build_trunc, build_zext,
build_ptrtoint, build_inttoptr,
build_fpext, build_fptrunc, build_fp2si, build_si2fp, build_fp2ui, build_ui2fp,
build_gep, build_gep_array, build_gep_struct,
build_phi, build_switch, build_select, build_unreachable,
build_atomicrmw, build_cmpxchg, build_inline_asm, build_va_arg,
PhiIncoming, new_phi_incoming, SwitchCase, new_switch_case,
ICMP_EQ, ICMP_NE, ICMP_SGT, ICMP_SGE, ICMP_SLT, ICMP_SLE,
ICMP_UGT, ICMP_UGE, ICMP_ULT, ICMP_ULE,
FCMP_FALSE, FCMP_OEQ, FCMP_OGT, FCMP_OGE, FCMP_OLT, FCMP_OLE,
FCMP_ONE, FCMP_ORD, FCMP_UNO, FCMP_UEQ, FCMP_UGT, FCMP_UGE,
FCMP_ULT, FCMP_ULE, FCMP_UNE, FCMP_TRUE,
ATOMIC_XCHG, ATOMIC_ADD, ATOMIC_SUB, ATOMIC_AND, ATOMIC_NAND,
ATOMIC_OR, ATOMIC_XOR, ATOMIC_MAX, ATOMIC_MIN, ATOMIC_UMAX, ATOMIC_UMIN,
ATOMIC_ORDER_NOTATOMIC, ATOMIC_ORDER_UNORDERED, ATOMIC_ORDER_MONOTONIC,
ATOMIC_ORDER_ACQUIRE, ATOMIC_ORDER_RELEASE, ATOMIC_ORDER_ACQ_REL,
ATOMIC_ORDER_SEQ_CST,
)
from .__verify import (
VerifyResult, NameEntry,
verify_function, verify_module,
VERIFY_OK, VERIFY_ERR_NO_TERMINATOR, VERIFY_ERR_DUPLICATE_DEF,
VERIFY_ERR_UNDEFINED_USE, VERIFY_ERR_PHI_NOT_FIRST,
_new_verify_result,
)
# ============================================================
# 便捷工厂: 字符串复制
# ============================================================
def _str_dup(pool: memhub.MemBuddy | t.CPtr, src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""从 pool 分配并复制一个 C 字符串"""
if src is None: return None
slen: t.CSizeT = string.strlen(src)
buf: t.CChar | t.CPtr = pool.alloc(slen + 1)
if buf is None: return None
string.strcpy(buf, src)
return buf
# ============================================================
# 便捷工厂: 创建带名称的基本块
# ============================================================
def create_block(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr,
name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
"""创建基本块并添加到函数"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
blk: BasicBlock | t.CPtr = new_basic_block(pool, name_dup)
if blk is not None:
function_add_block(func, blk)
return blk
# ============================================================
# 便捷工厂: 创建整数常量值
# ============================================================
def const_int(pool: memhub.MemBuddy | t.CPtr, bits: t.CInt,
val: t.CInt64T) -> Value | t.CPtr:
"""创建整数常量值(自动创建类型 + 名字文本)
参数:
bits: 位宽 (1/8/16/32/64)
val: 整数值
"""
# 创建类型
ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if ty is None: return None
string.memset(ty, 0, LLVMType.__sizeof__())
c.DerefAs(ty, LLVMType.Int(bits))
# 创建名字文本
name: t.CChar | t.CPtr = pool.alloc(32)
if name is None: return None
viperlib.snprintf(name, 32, "%lld", val)
return ConstInt(pool, ty, val, name)
def const_int32(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr:
"""便捷: 创建 i32 整数常量"""
return const_int(pool, 32, val)
def const_int64(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr:
"""便捷: 创建 i64 整数常量"""
return const_int(pool, 64, val)
# ============================================================
# 便捷工厂: 创建函数并添加到模块
# ============================================================
def create_function(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建函数并添加到模块"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
func: Function | t.CPtr = new_function(pool, name_dup, ret_ty)
if func is not None:
module_add_function(mod, func)
return func
def add_param(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr,
ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Param | t.CPtr:
"""创建参数并添加到函数"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
param: Param | t.CPtr = new_param(pool, ty, name_dup)
if param is not None:
function_add_param(func, param)
return param
# ============================================================
# 便捷工厂: 创建函数声明(declare)
# ============================================================
def create_declare(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建函数声明(declare,无函数体)并添加到模块
与 create_function 不同,声明不生成函数体,仅生成:
declare <ret_ty> @<name>(<params>)
"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
func: Function | t.CPtr = new_function(pool, name_dup, ret_ty)
if func is not None:
func.IsDeclared = 1
module_add_function(mod, func)
return func
# ============================================================
# 便捷工厂: 创建字符串常量全局变量
#
# 生成 LLVM IR:
# @.str = private unnamed_addr constant [N x i8] c"contents\00"
# ============================================================
def create_global_string(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建字符串常量全局变量并添加到模块
参数:
name: 全局变量名(如 ".str")
text: 字符串内容(C 字符串,不含末尾 NUL,NUL 由本函数自动添加)
返回: GlobalVariable 指针,其类型为 [len+1 x i8]
"""
if text is None: return None
slen: t.CSizeT = string.strlen(text)
count: t.CInt = slen + 1 # 含末尾 NUL
# 创建 i8 类型
i8_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if i8_ty is None: return None
string.memset(i8_ty, 0, LLVMType.__sizeof__())
c.DerefAs(i8_ty, LLVMType.Int(8))
# 创建 [count x i8] 数组类型
arr_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if arr_ty is None: return None
string.memset(arr_ty, 0, LLVMType.__sizeof__())
c.DerefAs(arr_ty, LLVMType.Array(i8_ty, count))
# 创建全局变量
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, arr_ty)
if gv is None: return None
# 设置属性: private + unnamed_addr + constant
global_set_linkage(gv, "private")
global_set_unnamed_addr(gv, 1)
global_set_constant(gv, 1)
# 构造初始化值文本: c"contents\00"
# LLVM IR 字符串字面量格式: c"<chars>" 其中 " 和 \ 及非打印字符用 \xx 转义
# 缓冲区大小: 最坏情况每个字符4字节(\xx)+ c"..." + \00 + "
init_buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8)
if init_buf is None: return None
pos: t.CSizeT = 0
init_buf[pos] = 'c'
pos += 1
init_buf[pos] = '"'
pos += 1
i: t.CSizeT = 0
while i < slen:
ch: t.CUInt8T = text[i]
if ch == 0x22 or ch == 0x5C or ch < 0x20 or ch >= 0x7F:
# 需要转义: " → \22, \ → \5c, 非打印字符 → \xx
init_buf[pos] = '\\'
pos += 1
hi: t.CInt = (ch >> 4) & 0x0F
lo: t.CInt = ch & 0x0F
if hi < 10:
init_buf[pos] = 0x30 + hi
else:
init_buf[pos] = 0x61 + hi - 10
pos += 1
if lo < 10:
init_buf[pos] = 0x30 + lo
else:
init_buf[pos] = 0x61 + lo - 10
pos += 1
else:
init_buf[pos] = ch
pos += 1
i += 1
# 末尾 NUL 字节
init_buf[pos] = '\\'
pos += 1
init_buf[pos] = '0'
pos += 1
init_buf[pos] = '0'
pos += 1
init_buf[pos] = '"'
pos += 1
init_buf[pos] = '\0'
gv.Initializer = init_buf
module_add_global(mod, gv)
return gv
# ============================================================
# 便捷工厂: 创建带初始化值的整数全局变量
# ============================================================
def create_global_int(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr:
"""创建整数全局变量并添加到模块
生成 LLVM IR:
@<name> = global i<bits> <val>
"""
# 创建整数类型
ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if ty is None: return None
string.memset(ty, 0, LLVMType.__sizeof__())
c.DerefAs(ty, LLVMType.Int(bits))
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, ty)
if gv is None: return None
# 构造初始化值文本: "42" (类型由 _print_global 单独打印)
init_buf: t.CChar | t.CPtr = pool.alloc(48)
if init_buf is None: return None
viperlib.snprintf(init_buf, 48, "%lld", val)
gv.Initializer = init_buf
module_add_global(mod, gv)
return gv
# ============================================================
# LLVMModuleCore: 模块/函数/值创建核心,封装 pool 避免重复传参
#
# 用法:
# mcore: LLVMModuleCore | t.CPtr = LLVMModuleCore(pool)
# mod: LLVMModule | t.CPtr = mcore.NewModule("test")
# func: Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32)
# val: Value | t.CPtr = mcore.ConstInt32(42)
# ============================================================
@t.NoVTable
class LLVMModuleCore:
"""模块/函数/值创建核心,封装 pool 避免每次创建都传 pool"""
Pool: memhub.MemBuddy | t.CPtr
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
self.Pool = pool
# ---- 模块操作 ----
def NewModule(self, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr:
return new_module(self.Pool, name)
def CreateFunction(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
return create_function(self.Pool, mod, name, ret_ty)
def CreateDeclare(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建函数声明(declare,无函数体)"""
return create_declare(self.Pool, mod, name, ret_ty)
def AddParam(self, func: Function | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Param | t.CPtr:
return add_param(self.Pool, func, ty, name)
def FunctionSetAttrs(self, func: Function | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置函数级属性文本"""
function_set_attrs(func, attrs)
def ParamSetAttrs(self, param: Param | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置参数属性文本"""
param_set_attrs(param, attrs)
def CreateBlock(self, func: Function | t.CPtr,
name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
return create_block(self.Pool, func, name)
def NewBuilder(self, func: Function | t.CPtr) -> IRBuilder | t.CPtr:
return new_builder(self.Pool, func)
# ---- 全局变量 ----
def NewGlobal(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建全局变量并添加到模块"""
name_dup: t.CChar | t.CPtr = _str_dup(self.Pool, name)
gv: GlobalVariable | t.CPtr = new_global_variable(self.Pool, name_dup, ty)
if gv is not None:
module_add_global(mod, gv)
return gv
def CreateGlobalString(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建字符串常量全局变量"""
return create_global_string(self.Pool, mod, name, text)
def CreateGlobalInt(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr:
"""创建带初始化值的整数全局变量"""
return create_global_int(self.Pool, mod, name, bits, val)
def GlobalSetConstant(self, gv: GlobalVariable | t.CPtr, is_const: t.CInt):
global_set_constant(gv, is_const)
def GlobalSetLinkage(self, gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr):
global_set_linkage(gv, linkage)
def GlobalSetUnnamedAddr(self, gv: GlobalVariable | t.CPtr, level: t.CInt):
global_set_unnamed_addr(gv, level)
def GlobalSetSection(self, gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr):
global_set_section(gv, section)
# ---- 值创建 ----
def ConstInt(self, bits: t.CInt, val: t.CInt64T) -> Value | t.CPtr:
return const_int(self.Pool, bits, val)
def ConstInt32(self, val: t.CInt64T) -> Value | t.CPtr:
return const_int32(self.Pool, val)
def ConstInt64(self, val: t.CInt64T) -> Value | t.CPtr:
return const_int64(self.Pool, val)
def ConstFloat(self, ty: LLVMType | t.CPtr, val: t.CDouble) -> Value | t.CPtr:
return ConstFloat(self.Pool, ty, val)
def SSAValue(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr:
return SSAValue(self.Pool, ty, name)
def ConstNull(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr:
return ConstNull(self.Pool, ty, name)
# ---- 打印 ----
def PrintValue(self, buf: t.CChar | t.CPtr, size: t.CSizeT, val: Value | t.CPtr):
ValuePrint(buf, size, val, self.Pool)
def PrintFunction(self, buf: t.CChar | t.CPtr, size: t.CSizeT, func: Function | t.CPtr):
FunctionPrint(buf, size, func, self.Pool)
def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, mod: LLVMModule | t.CPtr):
LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL)
# ---- SSA 验证 ----
def NewVerifyResult(self, buf_size: t.CSizeT) -> VerifyResult | t.CPtr:
"""创建验证结果对象(buf_size 为错误消息缓冲区大小)"""
return _new_verify_result(self.Pool, buf_size)
def VerifyFunction(self, func: Function | t.CPtr,
result: VerifyResult | t.CPtr) -> t.CInt:
"""验证单个函数的 SSA 正确性,返回错误数(0=通过)"""
return verify_function(self.Pool, func, result)
def VerifyModule(self, mod: LLVMModule | t.CPtr,
result: VerifyResult | t.CPtr) -> t.CInt:
"""验证模块中所有函数的 SSA 正确性,返回错误数(0=通过)"""
return verify_module(self.Pool, mod, result)
+638
View File
@@ -0,0 +1,638 @@
import t, c
from stdint import *
import string
import stdio
import stdlib
import viperlib
import memhub
from linkedlist import GSList, GSListNode
from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, ParamNode
from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param
# ============================================================
# GlobalVariable: LLVM IR 全局变量
#
# 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。
# 继承 GSListNode[GlobalVariable] 获取强类型 Next。
# ============================================================
@t.NoVTable
class GlobalVariable(GSListNode[GlobalVariable]):
Name: t.CChar | t.CPtr # 全局变量名(如 ".str" / "my_global")
Ty: LLVMType | t.CPtr # 变量类型
Initializer: t.CVoid | t.CPtr # 初始化值 Value*(None = 无初始化)
IsConstant: t.CInt # 1=constant, 0=variable
Linkage: t.CChar | t.CPtr # 链接类型("private"/"internal"/"external"/...)
Section: t.CChar | t.CPtr # 段名(None = 默认)
UnnamedAddr: t.CInt # 1=unnamed_addr, 2=local_unnamed_addr, 0=none
# ============================================================
# NamedTypeNode: 命名结构体类型链表节点
#
# 持有 LLVMType* 指针(必须是命名 Struct 类型)。
# 继承 GSListNode[NamedTypeNode] 获取强类型 Next。
# ============================================================
@t.NoVTable
class NamedTypeNode(GSListNode[NamedTypeNode]):
Ty: LLVMType | t.CPtr # 命名结构体类型指针
# ============================================================
# LLVMModule: LLVM IR 模块容器
#
# 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针,
# 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。
# LLVMModulePrint 输出完整 .ll 文件内容。
# 注意: 类名必须为 LLVMModule 而非 Module,避免与 ast.Module 命名冲突
# ============================================================
@t.NoVTable
class LLVMModule:
Name: t.CChar | t.CPtr # 模块名
FuncHead: Function | t.CPtr # 函数链表头
FuncTail: Function | t.CPtr # 函数链表尾
FuncCount: t.CSizeT # 函数计数
GlobalHead: GlobalVariable | t.CPtr # 全局变量链表头
GlobalTail: GlobalVariable | t.CPtr # 全局变量链表尾
GlobalCount: t.CSizeT # 全局变量计数
TargetTriple: t.CChar | t.CPtr # 目标三元组(如 "x86_64-pc-linux-gnu")
DataLayout: t.CChar | t.CPtr # 数据布局(如 "e-m:e-p270:32:32-...")
NamedTypeHead: NamedTypeNode | t.CPtr # 命名结构体类型链表头
NamedTypeTail: NamedTypeNode | t.CPtr # 命名结构体类型链表尾
NamedTypeCount: t.CSizeT # 命名结构体类型计数
# 总计: 12 字段 * 8 = 96 字节(无 vtable)
# ============================================================
# 实例方法(对象化重构:原 module_* 顶层函数改写为方法,
# 原顶层函数保留为一行委托)
# ============================================================
# ---- 链表操作 ----
def add_function(self, func: Function | t.CPtr):
"""将函数追加到模块函数链表(O(1))"""
if self is None or func is None: return
func.Next = None
if self.FuncHead is None:
self.FuncHead = func
else:
self.FuncTail.Next = func
self.FuncTail = func
self.FuncCount += 1
def add_global(self, gv: GlobalVariable | t.CPtr):
"""将全局变量追加到模块全局变量链表(O(1))"""
if self is None or gv is None: return
gv.Next = None
if self.GlobalHead is None:
self.GlobalHead = gv
else:
self.GlobalTail.Next = gv
self.GlobalTail = gv
self.GlobalCount += 1
# ---- 目标属性 ----
def set_target(self, triple: t.CChar | t.CPtr):
"""设置目标三元组"""
if self is None: return
self.TargetTriple = triple
def set_datalayout(self, layout: t.CChar | t.CPtr):
"""设置数据布局"""
if self is None: return
self.DataLayout = layout
# ---- 命名结构体类型管理 ----
def add_named_type(self, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr):
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。
按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。
"""
if self is None or pool is None or ty is None:
return
name: t.CChar | t.CPtr = get_struct_name(ty)
if name is None:
return
# 去重检查(opaque 声明可被完整定义替换)
cur: NamedTypeNode | t.CPtr = self.NamedTypeHead
cnt_dedup: t.CInt = 0
while cur is not None:
# 步数守卫:NamedTypeHead 链表成环(内存损坏/插入 bug)会导致
# 无限遍历挂起(G3 编译 LinkedNode.prepend 挂起根因)。
# 正常链表节点数远小于此上限,超限即链表损坏 → 立即报错终止。
cnt_dedup += 1
if cnt_dedup > 100000:
stdio.printf("[ANT-LOOP] NamedTypeHead 链表疑似成环, name=%s, 遍历节点=%d, 强制终止\n",
name if name is not None else "(null)", cnt_dedup)
stdlib.exit(1)
if cur.Ty is not None:
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
if existing_name is not None:
if string.strcmp(existing_name, name) == 0:
# 已有完整定义则无需替换
if _is_opaque_struct(cur.Ty) == 0:
return
# 已有 opaque,新类型也是 opaque 则不重复
if _is_opaque_struct(ty) != 0:
return
# 用完整定义替换 opaque 声明(原地替换 Ty 指针)
cur.Ty = ty
return
cur = cur.Next
# 创建新节点
node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE)
if node is None:
return
string.memset(node, 0, NAMED_TYPE_NODE_SIZE)
node.Ty = ty
# opaque 类型插入链表头部,确保在引用它的完整定义之前声明。
# 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明
# 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。
# 完整定义追加到链表尾部,保持原有顺序。
if _is_opaque_struct(ty) != 0:
node.Next = self.NamedTypeHead
if self.NamedTypeHead is None:
self.NamedTypeTail = node
self.NamedTypeHead = node
else:
node.Next = None
if self.NamedTypeHead is None:
self.NamedTypeHead = node
else:
self.NamedTypeTail.Next = node
self.NamedTypeTail = node
self.NamedTypeCount += 1
def _is_type_defined_in_module(self, name: t.CChar | t.CPtr) -> int:
"""检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义"""
if self is None or name is None:
return 0
cur: NamedTypeNode | t.CPtr = self.NamedTypeHead
cnt_tdm: t.CInt = 0
while cur is not None:
# 步数守卫:同上,防 NamedTypeHead 链表成环无限遍历
cnt_tdm += 1
if cnt_tdm > 100000:
stdio.printf("[TDM-LOOP] NamedTypeHead 链表疑似成环, name=%s, 强制终止\n",
name if name is not None else "(null)")
stdlib.exit(1)
if cur.Ty is not None:
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
if existing_name is not None:
if string.strcmp(existing_name, name) == 0:
return 1
cur = cur.Next
return 0
def ensure_opaque_for_type(self, pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr):
"""为类型中的跨模块结构体引用添加 opaque 声明
当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
如果该名称未在模块中定义,则添加 opaque 声明。
"""
_scan_type_for_cross_module_refs(pool, self, ty)
# ---- 打印 ----
def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
pool: memhub.MemBuddy | t.CPtr, mode: t.CInt):
"""将模块序列化为 .ll 文本写入 buf"""
if self is None or buf is None or size == 0: return
# 头部注释(stub 和 full 模式输出,text 模式不输出)
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
_append_cstr(buf, size, "; ModuleID = '")
if self.Name is not None:
_append_cstr(buf, size, self.Name)
_append_cstr(buf, size, "'\n")
# 目标三元组
if self.TargetTriple is not None:
_append_cstr(buf, size, "target triple = \"")
_append_cstr(buf, size, self.TargetTriple)
_append_cstr(buf, size, "\"\n")
# 数据布局
if self.DataLayout is not None:
_append_cstr(buf, size, "target datalayout = \"")
_append_cstr(buf, size, self.DataLayout)
_append_cstr(buf, size, "\"\n")
# 空行
_append_cstr(buf, size, "\n")
# 命名结构体类型定义(stub 和 full 模式输出,text 模式不输出)
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
# 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义
# 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义
# 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册
func_scan: Function | t.CPtr = self.FuncHead
while func_scan is not None:
if func_scan.RetTy is not None:
self.ensure_opaque_for_type(pool, func_scan.RetTy)
if func_scan.Params is not None:
param_scan: Param | t.CPtr = func_scan.Params.Head
while param_scan is not None:
if param_scan.Ty is not None:
self.ensure_opaque_for_type(pool, param_scan.Ty)
param_scan = param_scan.Next
func_scan = func_scan.Next
nt: NamedTypeNode | t.CPtr = self.NamedTypeHead
# 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够
# 在循环外分配一次并复用,减少 pool 碎片
ty_buf: t.CChar | t.CPtr = pool.alloc(4096)
while nt is not None:
if nt.Ty is not None:
if ty_buf is not None:
ty_buf[0] = '\0'
PrintStructDefinition(ty_buf, 4096, nt.Ty, pool)
_append_cstr(buf, size, ty_buf)
_append_cstr(buf, size, "\n")
nt = nt.Next
if self.NamedTypeHead is not None:
_append_cstr(buf, size, "\n")
# 全局变量
gv: GlobalVariable | t.CPtr = self.GlobalHead
if mode == OUTPUT_STUB:
# stub 模式:输出 external global(无初值)
while gv is not None:
_print_global_stub(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
else:
# full 和 text 模式:输出完整全局变量
# text 模式跳过无初值的全局变量(纯声明)
gv_idx: t.CInt = 0
while gv is not None:
if mode == OUTPUT_TEXT and gv.Initializer is None:
gv = gv.Next
gv_idx += 1
continue
_print_global(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
gv_idx += 1
if self.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB):
_append_cstr(buf, size, "\n")
elif self.GlobalHead is not None and mode == OUTPUT_TEXT:
# text 模式下如果输出了全局变量,也加空行
had_global: t.CInt = 0
gv2: GlobalVariable | t.CPtr = self.GlobalHead
while gv2 is not None:
if gv2.Initializer is not None:
had_global = 1
break
gv2 = gv2.Next
if had_global != 0:
_append_cstr(buf, size, "\n")
# 遍历函数
func: Function | t.CPtr = self.FuncHead
func_idx: t.CInt = 0
while func is not None:
if mode == OUTPUT_STUB:
# stub 模式:仅输出 declare(IsDeclared==1)
if func.IsDeclared == 1:
FunctionPrint(buf, size, func, pool)
_append_cstr(buf, size, "\n")
elif mode == OUTPUT_TEXT:
# text 模式:仅输出 define(IsDeclared==0)
if func.IsDeclared == 0:
FunctionPrint(buf, size, func, pool)
_append_cstr(buf, size, "\n")
else:
# full 模式:输出所有函数
FunctionPrint(buf, size, func, pool)
_append_cstr(buf, size, "\n")
func = func.Next
func_idx += 1
# ============================================================
# 工厂函数
# ============================================================
def new_module(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr:
"""创建一个模块"""
# 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable)
ptr: LLVMModule | t.CPtr = pool.alloc(96)
if ptr is None: return None
string.memset(ptr, 0, 96)
ptr.Name = name
ptr.FuncHead = None
ptr.FuncTail = None
ptr.FuncCount = 0
ptr.GlobalHead = None
ptr.GlobalTail = None
ptr.GlobalCount = 0
ptr.TargetTriple = None
ptr.DataLayout = None
ptr.NamedTypeHead = None
ptr.NamedTypeTail = None
ptr.NamedTypeCount = 0
return ptr
# GlobalVariable 硬编码大小: Next(8) + Name(8) + Ty(8) + Initializer(8) + IsConstant(4) + Linkage(8) + Section(8) + UnnamedAddr(4) = 64 字节
GV_SIZE: t.CDefine = 64
# NamedTypeNode 硬编码大小: Next(8) + Ty(8) = 16 字节
NAMED_TYPE_NODE_SIZE: t.CDefine = 16
def new_global_variable(pool: memhub.MemBuddy | t.CPtr,
name: t.CChar | t.CPtr, ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建一个全局变量"""
ptr: GlobalVariable | t.CPtr = pool.alloc(GV_SIZE)
if ptr is None: return None
string.memset(ptr, 0, GV_SIZE)
ptr.Name = name
ptr.Ty = ty
ptr.Initializer = None
ptr.IsConstant = 0
ptr.Linkage = "external"
ptr.Section = None
ptr.UnnamedAddr = 0
return ptr
# ============================================================
# 链表操作(嵌入式 Head/Tail/Count,O(1) 追加)
# ============================================================
def module_add_function(mod: LLVMModule | t.CPtr, func: Function | t.CPtr):
return mod.add_function(func)
def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr):
return mod.add_global(gv)
def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr):
return mod.set_target(triple)
def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr):
return mod.set_datalayout(layout)
# ============================================================
# 命名结构体类型管理
# ============================================================
# ============================================================
# _is_opaque_struct - 检查类型是否是 opaque 结构体
#
# opaque 结构体特征: Struct 类型,fcount == -1(哨兵标记,跨模块前向
# 声明,仅名称无字段定义)。通过 Struct(pool, None, -1, name) 创建,
# IR 输出为 %"name" = type opaque。注意区分空结构体(fcount==0,
# fields==None,无字段类)——它是合法完整定义(= type {},可 alloca)。
# 用于在 module_add_named_type 中区分 opaque 声明和完整定义,
# 确保 opaque 声明插入链表头部(在使用之前声明)。
#
# Returns: 1=是 opaque / 0=否
# ============================================================
def _is_opaque_struct(ty: LLVMType | t.CPtr) -> int:
"""检查类型是否是 opaque 结构体
opaque 是跨模块前向声明(仅名称无字段定义),由
_scan_type_for_cross_module_refs 创建,fcount=-1 哨兵标记。
空结构体(fcount==0, fields==None,无字段类)是合法完整定义
(LLVM {} 类型,可 alloca),必须与 opaque 区分——此前混淆导致
空类结构体被输出为 "= type opaque",alloca 报 Cannot allocate
unsized type。
"""
if ty is None:
return 0
match ty:
case LLVMType.Struct(fields, fcount, name):
# opaque: fcount == -1(哨兵)
if fcount < 0:
return 1
return 0
case _:
return 0
def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr):
return mod.add_named_type(pool, ty)
# ============================================================
# module_ensure_opaque_for_type - 为类型中的跨模块结构体引用添加 opaque 声明
#
# 递归扫描 LLVMType 树,当遇到 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
# 如果该名称未在模块中定义,则添加 opaque 声明(%"name" = type opaque)。
# 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。
# ============================================================
def _is_type_defined_in_module(mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr) -> int:
return mod._is_type_defined_in_module(name)
def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
mod: LLVMModule | t.CPtr,
ty: LLVMType | t.CPtr,
depth: t.CInt = 0):
"""递归扫描类型树,为跨模块结构体引用添加 opaque 声明"""
if ty is None or mod is None or pool is None:
return
# 深度守卫:自引用结构体(链表/树节点,如 Node{...; Ptr(Node) next})
# 会无限递归栈溢出,与其他递归(TypePrint/DeepCopyType)一致设上限
if depth >= 100:
return
match ty:
case LLVMType.Ptr(pointee):
if pointee is not None:
match pointee:
case LLVMType.Struct(sfields, sfcount, sname):
if sname is not None:
# 检查是否为跨模块引用(名称包含 '.')
if string.strchr(sname, 46) is not None:
# 检查是否已在模块中定义
if _is_type_defined_in_module(mod, sname) == 0:
# 创建 opaque 类型并添加到模块
# fcount=-1 哨兵标记 opaque(区别于空结构体 {},
# 后者 fcount==0 是合法完整定义,可 alloca)
opaque_ty: LLVMType | t.CPtr = Struct(pool, None, -1, sname)
if opaque_ty is not None:
module_add_named_type(mod, pool, opaque_ty)
# 递归扫描结构体字段中的跨模块引用
# 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用
if sfields is not None:
fld: ParamNode | t.CPtr = sfields
while fld is not None:
if fld.Ty is not None:
_scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1)
fld = fld.Next
case _:
_scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1)
case LLVMType.Struct(sfields2, sfcount2, sname2):
# 顶层结构体(非指针):递归扫描字段
if sfields2 is not None:
fld2: ParamNode | t.CPtr = sfields2
while fld2 is not None:
if fld2.Ty is not None:
_scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1)
fld2 = fld2.Next
case LLVMType.Array(elem_ty, acount):
if elem_ty is not None:
_scan_type_for_cross_module_refs(pool, mod, elem_ty, depth + 1)
case _:
pass
def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr):
return mod.ensure_opaque_for_type(pool, ty)
# ============================================================
# 全局变量属性设置
# ============================================================
def global_set_constant(gv: GlobalVariable | t.CPtr, is_const: t.CInt):
"""设置全局变量是否为常量"""
if gv is None: return
gv.IsConstant = is_const
def global_set_linkage(gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr):
"""设置链接类型 (private/internal/external/... )"""
if gv is None: return
gv.Linkage = linkage
def global_set_unnamed_addr(gv: GlobalVariable | t.CPtr, level: t.CInt):
"""设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)"""
if gv is None: return
gv.UnnamedAddr = level
def global_set_section(gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr):
"""设置段名"""
if gv is None: return
gv.Section = section
# ============================================================
# 输出模式常量
# ============================================================
OUTPUT_FULL: t.CDefine = 0 # 完整 IR(stub + text)
OUTPUT_STUB: t.CDefine = 1 # 仅声明(header + 类型定义 + declare + external global)
OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值)
# ============================================================
# LLVMModulePrint: 将模块序列化为 .ll 文本
#
# mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码
# ============================================================
def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
mode: t.CInt):
return mod.PrintModule(buf, size, pool, mode)
# ============================================================
# 全局变量打印
# ============================================================
def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT,
gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印单个全局变量: @<name> = [linkage] [unnamed_addr] [constant] <ty> <init>"""
if gv is None: return
_append_cstr(buf, size, "@")
if gv.Name is not None:
if _ll_name_needs_quote(gv.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, " = ")
# 链接类型(有初始值时不输出 external,因为 external + 初始值是非法 IR)
if gv.Linkage is not None:
if gv.Initializer is not None and string.strcmp(gv.Linkage, "external") == 0:
pass
else:
_append_cstr(buf, size, gv.Linkage)
_append_cstr(buf, size, " ")
# unnamed_addr
if gv.UnnamedAddr == 1:
_append_cstr(buf, size, "unnamed_addr ")
elif gv.UnnamedAddr == 2:
_append_cstr(buf, size, "local_unnamed_addr ")
# constant / global
if gv.IsConstant == 1:
_append_cstr(buf, size, "constant ")
else:
_append_cstr(buf, size, "global ")
# 类型
ty_buf: t.CChar | t.CPtr = pool.alloc(512)
if ty_buf is not None:
ty_buf[0] = '\0'
TypePrint(ty_buf, 512, gv.Ty, pool)
_append_cstr(buf, size, ty_buf)
# 初始化值
if gv.Initializer is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, gv.Initializer)
# 段名
if gv.Section is not None:
_append_cstr(buf, size, ", section \"")
_append_cstr(buf, size, gv.Section)
_append_cstr(buf, size, "\"")
# ============================================================
# _print_global_stub - 打印全局变量的声明形式(external global,无初值)
# ============================================================
def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT,
gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印全局变量声明: @<name> = external global <ty>"""
if gv is None: return
_append_cstr(buf, size, "@")
if gv.Name is not None:
if _ll_name_needs_quote(gv.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, " = external global ")
# 类型
ty_buf: t.CChar | t.CPtr = pool.alloc(512)
if ty_buf is not None:
ty_buf[0] = '\0'
TypePrint(ty_buf, 512, gv.Ty, pool)
_append_cstr(buf, size, ty_buf)
# ============================================================
# 内部辅助
# ============================================================
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 C 字符串 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外
if dlen >= dst_size:
return
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
+765
View File
@@ -0,0 +1,765 @@
import t, c
from stdint import *
import viperlib
import string
import memhub
import stdio
import stdlib
from linkedlist import GSListNode
# ============================================================
# ParamNode: 函数参数类型链表节点
# 继承 GSListNode[ParamNode] 获取强类型 Next: ParamNode|CPtr
# Ty 用 t.CVoid | t.CPtr 前向引用,使用时转型为 (LLVMType | t.CPtr)
#
# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。
# ============================================================
@t.NoVTable
class ParamNode(GSListNode[ParamNode]):
Ty: t.CVoid | t.CPtr # LLVMType*(前向引用,使用时转型)
# ============================================================
# LLVMType: LLVM IR 类型系统(t.REnum tagged union)
#
# 变体少、无通用字段、操作通过 match 分派 —— 契合 REnum 模型。
# 布局: { i32 __tag, <max_variant_payload> }
# ============================================================
class LLVMType(t.REnum):
# 整数类型: i1/i8/i16/i32/i64
class Int:
Bits: t.CInt
# 指针类型: pointee*
class Ptr:
Pointee: LLVMType | t.CPtr
# 函数类型: ret (params)
class Func:
Ret: LLVMType | t.CPtr
Params: ParamNode | t.CPtr
PCount: t.CInt
# 数组类型: [N x elem_ty]
class Array:
ElemTy: LLVMType | t.CPtr
Count: t.CInt
# 结构体类型: {ty1, ty2, ...} 或 %"name" = type {ty1, ty2, ...}
# Fields 复用 ParamNode 链表(ParamNode.Ty 即字段类型)
# Name 非 None 时为命名结构体,TypePrint 输出 %"name" 而非 {...}
class Struct:
Fields: ParamNode | t.CPtr
FCount: t.CInt
Name: t.CChar | t.CPtr
# 浮点类型: half/float/double/fp128
class Float:
Bits: t.CInt # 16=half, 32=float, 64=double, 128=fp128
# 无值类型
class Void:
pass
# 标签类型
class Label:
pass
# 元数据类型
class Metadata:
pass
# ============================================================
# 内部分配辅助
# ============================================================
def _new_type(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""从 mpool 分配一个零初始化的 LLVMType"""
ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if ptr:
string.memset(ptr, 0, LLVMType.__sizeof__())
return ptr
# ============================================================
# 类型工厂函数
# ============================================================
def Int1(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(1))
return ptr
def Int8(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(8))
return ptr
def Int16(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(16))
return ptr
def Int32(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(32))
return ptr
def Int64(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(64))
return ptr
def Ptr(pool: memhub.MemBuddy | t.CPtr, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
"""创建指针类型 Ptr(pointee)
LLVM IR 中 **不允许 void* 指针**("pointers to void are invalid"),
因此:
- 若 pointee == None → 回退 Ptr(Int8)
- 若 pointee 是 LLVMType.Void → 回退 Ptr(Int8)(对应 C 的 void* 语法在 TPV 中写 Ptr(t.CVoid))
其他类型正常构造 Ptr(pointee)。
"""
# ============== 前置校验: 拦截 Void / None pointee(void* 非法)==============
safe_pointee: LLVMType | t.CPtr = pointee
if safe_pointee is None:
safe_pointee = Int8(pool)
else:
match safe_pointee:
case LLVMType.Void():
safe_pointee = Int8(pool)
case _:
pass
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Ptr(safe_pointee))
return ptr
def Func(pool: memhub.MemBuddy | t.CPtr, ret: LLVMType | t.CPtr,
params: ParamNode | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Func(ret, params, count))
return ptr
def Void(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Void())
return ptr
def Array(pool: memhub.MemBuddy | t.CPtr, elem_ty: LLVMType | t.CPtr,
count: t.CInt) -> LLVMType | t.CPtr:
"""创建数组类型 [count x elem_ty]"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Array(elem_ty, count))
return ptr
def Struct(pool: memhub.MemBuddy | t.CPtr, fields: ParamNode | t.CPtr,
fcount: t.CInt, name: t.CChar | t.CPtr) -> LLVMType | t.CPtr:
"""创建结构体类型 {ty1, ty2, ...}
fields 为 ParamNode 链表头,fcount 为字段数量。
name 非 None 时为命名结构体(如 "sha1.ClassName"),TypePrint 输出 %"name"。
name 为 None 时为匿名结构体,TypePrint 输出 {ty1, ty2, ...}。
"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Struct(fields, fcount, name))
return ptr
def Half(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建半精度浮点类型 half (16-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(16))
return ptr
def Float(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建单精度浮点类型 float (32-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(32))
return ptr
def Double(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建双精度浮点类型 double (64-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(64))
return ptr
def FP128(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建四精度浮点类型 fp128 (128-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(128))
return ptr
def Label(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建标签类型 label"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Label())
return ptr
# ============================================================
# ParamNode 辅助
# ============================================================
# ParamNode 硬编码大小: Next(8) + Ty(8) = 16 字节
PNODE_SIZE: t.CDefine = 16
def new_param_node(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
"""创建一个参数节点,Ty 设为给定类型指针"""
ptr: ParamNode | t.CPtr = pool.alloc(PNODE_SIZE)
if ptr is None: return None
string.memset(ptr, 0, PNODE_SIZE)
ptr.Ty = ty
ptr.Next = None
return ptr
def param_list_append(head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr,
node: ParamNode | t.CPtr) -> ParamNode | t.CPtr:
"""将 node 追加到参数链表尾部,返回 head 和更新后的 tail"""
if node is None: return head
node.Next = None
if head is None:
return node
if tail is not None:
tail.Next = node
return node
# ============================================================
# ParamNode 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 ParamNode 的 stub 类型,
# 导致 TransPyC 静默跳过字段访问。这些访问器在拥有完整类型定义的
# 本模块内执行,能正确访问所有字段。
# ============================================================
def paramnode_get_ty(node: ParamNode | t.CPtr) -> LLVMType | t.CPtr:
"""获取参数节点的类型"""
if node is None:
return None
return (LLVMType | t.CPtr)(node.Ty)
def paramnode_get_next(node: ParamNode | t.CPtr) -> ParamNode | t.CPtr:
"""获取链表下一个参数节点"""
if node is None:
return None
return node.Next
def paramnode_set_ty(node: ParamNode | t.CPtr, ty: LLVMType | t.CPtr):
"""设置参数节点的类型"""
if node is None:
return
node.Ty = ty
def paramnode_set_next(node: ParamNode | t.CPtr, nxt: ParamNode | t.CPtr):
"""设置链表下一个参数节点"""
if node is None:
return
node.Next = nxt
# ============================================================
# LLVMTypeCore: 类型创建核心,封装 pool 避免重复传参
#
# 用法:
# core: LLVMTypeCore | t.CPtr = LLVMTypeCore(pool)
# ty_i32: LLVMType | t.CPtr = core.Int32()
# ty_ptr: LLVMType | t.CPtr = core.Ptr(ty_i32)
# ty_void: LLVMType | t.CPtr = core.Void()
# ============================================================
@t.NoVTable
class LLVMTypeCore:
"""类型创建核心,封装 pool 避免每次创建类型都传 pool"""
Pool: memhub.MemBuddy | t.CPtr
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
self.Pool = pool
def Int1(self) -> LLVMType | t.CPtr:
return Int1(self.Pool)
def Int8(self) -> LLVMType | t.CPtr:
return Int8(self.Pool)
def Int16(self) -> LLVMType | t.CPtr:
return Int16(self.Pool)
def Int32(self) -> LLVMType | t.CPtr:
return Int32(self.Pool)
def Int64(self) -> LLVMType | t.CPtr:
return Int64(self.Pool)
def Ptr(self, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
return Ptr(self.Pool, pointee)
def Func(self, ret: LLVMType | t.CPtr, params: ParamNode | t.CPtr,
count: t.CInt) -> LLVMType | t.CPtr:
return Func(self.Pool, ret, params, count)
def Array(self, elem_ty: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr:
return Array(self.Pool, elem_ty, count)
def Struct(self, fields: ParamNode | t.CPtr, fcount: t.CInt,
name: t.CChar | t.CPtr = None) -> LLVMType | t.CPtr:
return Struct(self.Pool, fields, fcount, name)
def Void(self) -> LLVMType | t.CPtr:
return Void(self.Pool)
def Half(self) -> LLVMType | t.CPtr:
return Half(self.Pool)
def Float(self) -> LLVMType | t.CPtr:
return Float(self.Pool)
def Double(self) -> LLVMType | t.CPtr:
return Double(self.Pool)
def FP128(self) -> LLVMType | t.CPtr:
return FP128(self.Pool)
def Label(self) -> LLVMType | t.CPtr:
return Label(self.Pool)
def NewParamNode(self, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
return new_param_node(self.Pool, ty)
# ---- 链表辅助 ----
def ParamListAppend(self, head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr,
node: ParamNode | t.CPtr) -> ParamNode | t.CPtr:
"""将 node 追加到参数/字段链表,返回新的 tail"""
return param_list_append(head, tail, node)
# ---- 打印 ----
def PrintType(self, buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr):
TypePrint(buf, size, ty, self.Pool)
# ============================================================
# TypePrint: 将 LLVMType 序列化为 IR 文本
#
# 示例:
# Int(32) -> "i32"
# Int(8) -> "i8"
# Ptr(Int(32)) -> "i32*"
# Void -> "void"
# Array(Int(32),4) -> "[4 x i32]"
# Struct(...) -> "{i32, i8*}"
# Func(...) -> "i32 (i32, i8*)"
#
# pool 用于复杂类型(Array/Struct/Func)递归打印子类型时分配临时缓冲区。
# ============================================================
def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""将类型 ty 序列化为 IR 文本写入 buf(容量 size)
pool 用于递归打印子类型时分配临时缓冲区。
"""
_TypePrintDepth(buf, size, ty, pool, 0)
# 递归深度上限:悬空/自引用的 LLVMType 树(1b reset 后内存被复用)会导致
# Ptr(pointee)/Struct(fields)/Func(params) 无限递归,每次递归分配临时缓冲
# 造成 OOM(单文件暴涨 900MB 根因)。超过 100 层即停止打印。
TYPEPRINT_MAX_DEPTH: t.CDefine = 100
def _TypePrintDepth(buf: t.CChar | t.CPtr, size: t.CSizeT,
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
depth: t.CInt):
"""带递归深度上限的 TypePrint 内部实现"""
if ty is None or buf is None or size == 0:
return
if depth >= TYPEPRINT_MAX_DEPTH:
viperlib.snprintf(buf, size, "...")
return
buf[0] = '\0'
match ty:
case LLVMType.Int(bits):
viperlib.snprintf(buf, size, "i%d", bits)
case LLVMType.Ptr(pointee):
# ================================================================
# LLVM IR 不允许 "void*",必须是 "i8*"。
# 兜底处理:
# pointee == None / Void() / Label() / Metadata() → 统一打印 i8*
# ================================================================
# 先判断是否 Struct(name) 的快速路径(需先判断 pointee 非None)
if pointee is not None:
match pointee:
case LLVMType.Struct(sfields, sfcount, sname):
if sname is not None:
# 悬空防护:sname 可能指向被 reset 回收/部分复用的 pool 内存。
# viperlib 的 %s 未实现 precision(%.40s 会全量读 sname),
# 手动 strncpy 限长拷贝后再打印,读侧限制在缓冲内。
# 类型名含 sha1 前缀可超 40 字符(如
# "bbdf3bbd4c3bc28c.CONSOLE_SCREEN_BUFFER_INFO"=42),
# 原 40 字节截断会产生未定义类型引用(llc: undefined type)。
sn_cp: t.CChar | t.CPtr = pool.alloc(256)
if sn_cp is not None:
string.strncpy(sn_cp, sname, 255)
sn_cp[255] = '\0'
viperlib.snprintf(buf, size, "%%\"%s\"*", sn_cp)
return
case LLVMType.Void():
# Ptr(Void) → i8*(LLVM IR void* 非法)
viperlib.snprintf(buf, size, "%s", "i8*")
return
case LLVMType.Label():
viperlib.snprintf(buf, size, "%s", "i8*")
return
case LLVMType.Metadata():
viperlib.snprintf(buf, size, "%s", "i8*")
return
case _:
pass
# pointee == None 时也兜底 Ptr(Int8) 打印 i8*
if pointee is None:
viperlib.snprintf(buf, size, "%s", "i8*")
return
# 通用路径: 递归打印 pointee 后追加 '*'
_TypePrintDepth(buf, size, pointee, pool, depth + 1)
pos: t.CSizeT = string.strlen(buf)
if pos + 1 < size:
buf[pos] = '*'
buf[pos + 1] = '\0'
case LLVMType.Array(elem_ty, count):
# [N x elem_ty]
viperlib.snprintf(buf, size, "[%d x ", count)
# SHA1 限定类型名(如 %"21a7fcfc665f75ef.NamedTypeNode")可达 ~50 字节,
# 嵌套指针/数组更易超过 128,使用 512 字节避免截断
tmp: t.CChar | t.CPtr = pool.alloc(512)
if tmp is not None:
_TypePrintDepth(tmp, 512, elem_ty, pool, depth + 1)
_strappend(buf, size, tmp)
_strappend(buf, size, "]")
case LLVMType.Struct(fields, fcount, name):
if name is not None:
# 命名结构体: %"name"
viperlib.snprintf(buf, size, "%%\"%s\"", name)
else:
# 匿名结构体: {ty1, ty2, ...}
_print_struct_body(buf, size, fields, pool, depth)
case LLVMType.Func(ret, params, count):
# ret (ty1, ty2, ...)
_TypePrintDepth(buf, size, ret, pool, depth + 1)
_strappend(buf, size, " (")
cur2: ParamNode | t.CPtr = params
first2: t.CInt = 1
_pc2: t.CInt = 0
# 函数参数类型可能为 SHA1 限定命名结构体指针,512 字节避免截断
tmp3: t.CChar | t.CPtr = pool.alloc(512)
while cur2 is not None:
# 悬空保护:参数链若被 reset 回收后内容复用,可能成环无限循环
_pc2 += 1
if _pc2 > 200:
_strappend(buf, size, "...)")
break
if first2 == 0:
_strappend(buf, size, ", ")
if tmp3 is not None:
_TypePrintDepth(tmp3, 512, cur2.Ty, pool, depth + 1)
_strappend(buf, size, tmp3)
cur2 = cur2.Next
first2 = 0
_strappend(buf, size, ")")
case LLVMType.Void():
viperlib.snprintf(buf, size, "%s", "void")
case LLVMType.Label():
viperlib.snprintf(buf, size, "%s", "label")
case LLVMType.Metadata():
viperlib.snprintf(buf, size, "%s", "metadata")
case LLVMType.Float(bits):
if bits == 16:
viperlib.snprintf(buf, size, "%s", "half")
elif bits == 32:
viperlib.snprintf(buf, size, "%s", "float")
elif bits == 64:
viperlib.snprintf(buf, size, "%s", "double")
elif bits == 128:
viperlib.snprintf(buf, size, "%s", "fp128")
else:
viperlib.snprintf(buf, size, "float%x", bits)
case _:
viperlib.snprintf(buf, size, "%s", "void")
# ============================================================
# 内部辅助
# ============================================================
def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾(不超过 dst_size)"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到 GB 外
if dlen >= dst_size:
return
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# _print_struct_body - 打印结构体字段部分 {ty1, ty2, ...}
#
# 供 TypePrint(匿名结构体)和 PrintStructDefinition(命名结构体定义行)复用
# ============================================================
def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
depth: t.CInt = 0):
"""打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容)
直接在 buf 当前末尾写入字段类型,避免 pool.alloc 返回与 buf 重叠的内存
导致 TypePrint 写入 tmp 时覆盖 buf 已有内容。
"""
if buf is None or size == 0:
return
_strappend(buf, size, "{")
cur: ParamNode | t.CPtr = fields
first: t.CInt = 1
fidx: t.CInt = 0
while cur is not None:
# 悬空保护:ParamNode 链若被 reset 回收后内容复用,Next 指针可能成环或
# 指向垃圾,无限循环。最多打印 200 个字段即停止,防止 OOM。
if fidx >= 200:
_strappend(buf, size, "...}")
return
if first == 0:
_strappend(buf, size, ", ")
# 直接在 buf 当前末尾位置写入字段类型
# TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0')
pos: t.CSizeT = string.strlen(buf)
if pos + 2 < size:
_TypePrintDepth(buf + pos, size - pos, cur.Ty, pool, depth + 1)
cur = cur.Next
first = 0
fidx += 1
_strappend(buf, size, "}")
# ============================================================
# PrintStructDefinition - 打印命名结构体类型定义行
#
# 输出格式: %"name" = type { ty1, ty2, ... }
# 供 LLVMModulePrint 在全局变量/函数之前输出类型定义
# ============================================================
def PrintStructDefinition(buf: t.CChar | t.CPtr, size: t.CSizeT,
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印命名结构体类型定义行 %"name" = type { ty1, ty2, ... }
当 fcount == -1(哨兵)时输出 opaque 声明: %"name" = type opaque。
空结构体(fcount==0, fields==None,无字段类)是完整定义,输出 "= type {}"。
"""
if ty is None or buf is None or size == 0:
return
match ty:
case LLVMType.Struct(fields, fcount, name):
if name is None:
return
# 使用 snprintf 构建 "%%"name" = type" 前缀,避免 _strappend 截断
# opaque 类型: fcount == -1(哨兵,跨模块前向声明)
if fcount < 0:
viperlib.snprintf(buf, size, "%%\"%s\" = type opaque", name)
else:
viperlib.snprintf(buf, size, "%%\"%s\" = type ", name)
_print_struct_body(buf, size, fields, pool)
case _:
return
# ============================================================
# get_struct_name - 获取命名结构体的名称
#
# 返回 Name 字段(如 "sha1.ClassName"),非 Struct 类型或匿名 Struct 返回 None
# 供 module_add_named_type 检查是否为命名结构体及去重
# ============================================================
def get_struct_name(ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
"""获取命名结构体的名称,非命名结构体返回 None"""
if ty is None:
return None
match ty:
case LLVMType.Struct(fields, fcount, name):
return name
case _:
return None
def get_struct_fields(ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
"""获取结构体的字段链表(供跨模块重建 Struct 类型用)"""
if ty is None:
return None
match ty:
case LLVMType.Struct(fields, fcount, name):
return fields
case _:
return None
def get_struct_fcount(ty: LLVMType | t.CPtr) -> t.CInt:
"""获取结构体的字段数量(供跨模块重建 Struct 类型用)"""
if ty is None:
return 0
match ty:
case LLVMType.Struct(fields, fcount, name):
return fcount
case _:
return 0
# ============================================================
# DeepCopyType - 深拷贝 LLVMType 到 stdlib 区(跨文件 reset 存活)
#
# 背景: 1b 阶段(mark1 之后)新注册的结构体(泛型特化类等),其
# struct_ty 是 pool 分配的 LLVMType,所在文件翻译完 reset_to(mark1)
# 后指针悬空。_struct_table 中的 entry.Ty 指向它,后续文件遍历
# _struct_table(find_struct_by_type/lookup_field 等)时解引用悬空
# 指针导致崩溃(0xC0000005)。
#
# 本函数递归拷贝整棵 LLVMType 树到 stdlib(含 ParamNode 字段链和
# 字符串名),保证 entry.Ty 跨文件永久存活。
#
# 注意: 自引用类型(如 Value 含 Ptr(Value) 字段)会导致无限递归,
# 用深度上限防护(超过即返回浅拷贝副本,后续不再递归)。
# ============================================================
DEEPCOPY_MAX_DEPTH: t.CDefine = 64
def DeepCopyType(pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
"""深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None"""
return _DeepCopyDepth(pool, ty, 0)
def _DeepCopyDepth(pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr, depth: t.CInt) -> LLVMType | t.CPtr:
"""带深度上限的深拷贝实现
分配源用传入的 pool 参数(调用方决定):传主 pool 为瞬时拷贝
(随 mark/reset 回收),传永久 pool(CompilerFactory.get_perm_pool())
为跨 mark 持久拷贝(代替 stdlib.malloc,buddy 分配更快)。
"""
if ty is None:
return None
new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(pool.alloc(LLVMType.__sizeof__()))
if new_ty is None:
return None
string.memset(new_ty, 0, LLVMType.__sizeof__())
if depth >= DEEPCOPY_MAX_DEPTH:
# 深度超限:浅拷贝 tag 后停止递归(复制当前变体但不深拷子类型)
match ty:
case LLVMType.Int(bits):
c.DerefAs(new_ty, LLVMType.Int(bits))
case LLVMType.Float(bits):
c.DerefAs(new_ty, LLVMType.Float(bits))
case LLVMType.Void():
c.DerefAs(new_ty, LLVMType.Void())
case LLVMType.Label():
c.DerefAs(new_ty, LLVMType.Label())
case LLVMType.Metadata():
c.DerefAs(new_ty, LLVMType.Metadata())
case _:
c.DerefAs(new_ty, LLVMType.Void())
return new_ty
match ty:
case LLVMType.Int(bits):
c.DerefAs(new_ty, LLVMType.Int(bits))
case LLVMType.Float(bits):
c.DerefAs(new_ty, LLVMType.Float(bits))
case LLVMType.Void():
c.DerefAs(new_ty, LLVMType.Void())
case LLVMType.Label():
c.DerefAs(new_ty, LLVMType.Label())
case LLVMType.Metadata():
c.DerefAs(new_ty, LLVMType.Metadata())
case LLVMType.Ptr(pointee):
c.DerefAs(new_ty, LLVMType.Ptr(_DeepCopyDepth(pool, pointee, depth + 1)))
case LLVMType.Array(elem_ty, count):
c.DerefAs(new_ty, LLVMType.Array(_DeepCopyDepth(pool, elem_ty, depth + 1), count))
case LLVMType.Func(ret, params, pcount):
c.DerefAs(new_ty, LLVMType.Func(
_DeepCopyDepth(pool, ret, depth + 1),
_DeepCopyParamChain(pool, params, depth + 1), pcount))
case LLVMType.Struct(fields, fcount, name):
c.DerefAs(new_ty, LLVMType.Struct(
_DeepCopyParamChain(pool, fields, depth + 1),
fcount, _DeepCopyStr(pool, name)))
case _:
stdlib.free(new_ty)
return None
return new_ty
def _DeepCopyParamChain(pool: memhub.MemBuddy | t.CPtr,
head: ParamNode | t.CPtr, depth: t.CInt) -> ParamNode | t.CPtr:
"""深拷贝 ParamNode 链表到 stdlib"""
if head is None:
return None
first: ParamNode | t.CPtr = None
prev: ParamNode | t.CPtr = None
cur: ParamNode | t.CPtr = head
guard: t.CInt = 0
while cur is not None:
guard += 1
if guard > 512:
break
node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(pool.alloc(PNODE_SIZE))
if node is None:
break
string.memset(node, 0, PNODE_SIZE)
node.Ty = _DeepCopyDepth(pool, paramnode_get_ty(cur), depth + 1)
node.Next = None
if first is None:
first = node
if prev is not None:
prev.Next = node
prev = node
cur = paramnode_get_next(cur)
return first
def _DeepCopyStr(pool: memhub.MemBuddy | t.CPtr, s: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""深拷贝字符串到 stdlib"""
if s is None:
return None
slen: t.CSizeT = string.strlen(s)
copy: t.CChar | t.CPtr = pool.alloc(slen + 1)
if copy is None:
return None
string.strcpy(copy, s)
return copy
+234
View File
@@ -0,0 +1,234 @@
import t, c
from stdint import *
import string
import viperlib
import stdio
import memhub
from linkedlist import GSListNode
from .__types import LLVMType, TypePrint
# ============================================================
# Value: SSA 值表示
#
# 表示一个 LLVM IR 值:SSA 临时值(%0/%result)或常量字面量(42/0)。
# 每个值有类型指针、名字、是否常量标志。
# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr(值池链表)
#
# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。
# ============================================================
@t.NoVTable
class Value(GSListNode[Value]):
Ty: LLVMType | t.CPtr # 值的类型
Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本("42"/"1.5e+00")
IsConst: t.CInt # 1=常量字面量, 0=SSA 临时值
IntVal: t.CInt64T # 整数常量值(当 IsConst=1 时使用)
FloatVal: t.CDouble # 浮点常量值(当 IsConst=1 且 Ty 为 Float 时使用)
# ============================================================
# 工厂函数
# ============================================================
# Value 硬编码大小: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 字节
VALUE_SIZE: t.CDefine = 48
def new_value(pool: memhub.MemBuddy | t.CPtr) -> Value | t.CPtr:
"""从 mpool 分配一个零初始化的 Value"""
ptr: Value | t.CPtr = pool.alloc(VALUE_SIZE)
if ptr:
string.memset(ptr, 0, VALUE_SIZE)
return ptr
def ConstInt(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
val: t.CInt64T, name: t.CChar | t.CPtr) -> Value | t.CPtr:
"""创建整数常量值
参数:
ty: 整数类型(Int1/Int8/Int32/Int64)
val: 整数值
name: 常量文本(如 "42"),由调用方提供
"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 1
v.IntVal = val
return v
def ConstNull(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Value | t.CPtr:
"""创建 null 指针常量"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 1
v.IntVal = 0
return v
def ConstZero(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""创建 zeroinitializer 常量(零初始化聚合类型:结构体/数组)"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = "zeroinitializer"
v.IsConst = 1
v.IntVal = 0
return v
def ConstFloat(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
val: t.CDouble) -> Value | t.CPtr:
"""创建浮点常量值
参数:
ty: 浮点类型(Half/Float/Double/FP128)
val: 浮点数值
名字自动格式化为 LLVM IR 科学计数法文本(如 "1.500000e+00")。
"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.IsConst = 1
v.FloatVal = val
v.IntVal = 0
# 格式化名字: LLVM IR 浮点常量文本用十六进制位模式(0x%016llx / 0x%08x)
# 原因: %.17e 科学计数法文本经 llc 解析对部分值产生 ±1 ulp 误差
# (如 "1.10000000000000000e+01" 解析为 11.000000000000002 而非 11.0,
# 导致 add_scalar[0]==11 等浮点常量比较失败)。位模式无精度损失。
# 原 %e 默认 6 位小数还会截断精度(3.1415926535897931 -> 3.141593e+00)。
# 用 CRT stdio.snprintf: viperlib 自实现 %g 有小数位反转 bug。
f_bits: t.CInt = 64
match ty:
case llvmlite.LLVMType.Float(ftb):
f_bits = ftb
fv_bits: t.CUInt64T = 0
c.Load(c.Addr(fv_bits), c.Addr(val))
name_buf: t.CChar | t.CPtr = pool.alloc(32)
if name_buf is not None:
if f_bits == 32:
stdio.snprintf(name_buf, 32, "0x%08x", t.CUInt32T(fv_bits))
else:
stdio.snprintf(name_buf, 32, "0x%016llx", fv_bits)
v.Name = name_buf
return v
def SSAValue(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Value | t.CPtr:
"""创建 SSA 临时值
参数:
ty: 值类型
name: SSA 名(如 "%0"/"%result"),由调用方提供
"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 0
v.IntVal = 0
return v
# ============================================================
# ValuePrint: 将值序列化为 IR 文本
#
# 示例:
# ConstInt(i32, 42, "42") -> "i32 42"
# SSAValue(i32, "%0") -> "i32 %0"
# ============================================================
def ValuePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
val: Value | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""将值 val 序列化为 IR 文本写入 buf
格式: <type> <name>
pool 用于复杂类型(Array/Struct/Func)递归打印时分配临时缓冲区。
"""
if val is None or buf is None or size == 0:
return
# 先写类型
TypePrint(buf, size, val.Ty, pool)
# 追加空格
pos: t.CSizeT = string.strlen(buf)
if pos + 1 < size:
buf[pos] = ' '
buf[pos + 1] = '\0'
# 追加名字
if val.Name is not None:
pos = string.strlen(buf)
_append_str(buf, size, val.Name)
# ============================================================
# Value 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 Value 的 stub 类型(字段不足或偏移错误),
# 导致 TransPyC 静默跳过字段访问(不生成 GEP,不报错)。
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问所有字段。
# ============================================================
def value_get_ty(val: Value | t.CPtr) -> LLVMType | t.CPtr:
"""获取值的类型"""
if val is None:
return None
return val.Ty
def value_get_next(val: Value | t.CPtr) -> Value | t.CPtr:
"""获取链表下一个值"""
if val is None:
return None
return val.Next
def value_set_ty(val: Value | t.CPtr, ty: LLVMType | t.CPtr):
"""设置值的类型"""
if val is None:
return
val.Ty = ty
def value_set_next(val: Value | t.CPtr, nxt: Value | t.CPtr):
"""设置链表下一个值"""
if val is None:
return
val.Next = nxt
def value_set_name(val: Value | t.CPtr, name: t.CChar | t.CPtr):
"""设置值的名字"""
if val is None:
return
val.Name = name
def value_set_isconst(val: Value | t.CPtr, is_const: t.CInt):
"""设置是否为常量"""
if val is None:
return
val.IsConst = is_const
# ============================================================
# 内部辅助
# ============================================================
def _append_str(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外
if dlen >= dst_size:
return
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
+403
View File
@@ -0,0 +1,403 @@
import t, c
from stdint import *
import string
import viperlib
import memhub
from linkedlist import GSListNode, GSList
from .__function import Function, BasicBlock, Line, Param
from .__module import LLVMModule
# ============================================================
# SSA 验证器
#
# 检查项:
# 1. 块终止: 每个基本块必须以终止指令结尾 (ret/br/switch/unreachable)
# 2. SSA 唯一性: 每个 %name 只能被定义一次
# 3. 未定义引用: 所有 %name 使用必须有对应定义
# 4. Phi 位置: phi 指令只能出现在块首(非 phi 指令之前)
# ============================================================
# 错误码
VERIFY_OK: t.CDefine = 0
VERIFY_ERR_NO_TERMINATOR: t.CDefine = 1
VERIFY_ERR_DUPLICATE_DEF: t.CDefine = 2
VERIFY_ERR_UNDEFINED_USE: t.CDefine = 3
VERIFY_ERR_PHI_NOT_FIRST: t.CDefine = 4
# ============================================================
# NameEntry: 已定义 SSA 名条目(链表节点)
#
# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。
# ============================================================
@t.NoVTable
class NameEntry(GSListNode[NameEntry]):
Name: t.CChar | t.CPtr # SSA 名(如 "%0"/"%result")
# ============================================================
# VerifyResult: 验证结果
# ============================================================
class VerifyResult:
ErrorCount: t.CInt # 错误总数
WarningCount: t.CInt # 警告总数
ErrorCode: t.CInt # 第一个错误码
ErrorBuf: t.CChar | t.CPtr # 错误消息缓冲区
ErrorBufSize: t.CSizeT # 缓冲区大小
# ============================================================
# 辅助函数
# ============================================================
def _new_verify_result(pool: memhub.MemBuddy | t.CPtr,
buf_size: t.CSizeT) -> VerifyResult | t.CPtr:
"""创建验证结果对象"""
ptr: VerifyResult | t.CPtr = pool.alloc(VerifyResult.__sizeof__())
if ptr is None: return None
string.memset(ptr, 0, VerifyResult.__sizeof__())
ptr.ErrorCount = 0
ptr.WarningCount = 0
ptr.ErrorCode = VERIFY_OK
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
if buf is not None:
buf[0] = '\0'
ptr.ErrorBuf = buf
ptr.ErrorBufSize = buf_size
return ptr
def _report_error(result: VerifyResult | t.CPtr, code: t.CInt, msg: t.CChar | t.CPtr):
"""记录一个错误"""
if result is None: return
result.ErrorCount += 1
if result.ErrorCode == VERIFY_OK:
result.ErrorCode = code
if result.ErrorBuf is not None and msg is not None:
_append_cstr(result.ErrorBuf, result.ErrorBufSize, msg)
_append_cstr(result.ErrorBuf, result.ErrorBufSize, "\n")
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外
if dlen >= dst_size:
return
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# SSA 名表操作
# ============================================================
def _new_name_table(pool: memhub.MemBuddy | t.CPtr) -> GSList[NameEntry] | t.CPtr:
"""创建空名表"""
gsl: GSList[NameEntry] | t.CPtr = pool.alloc(24) # GSList: Head+Tail+Count
if gsl is None: return None
string.memset(gsl, 0, 24)
return gsl
# NameEntry 硬编码大小: Next(8) + Name(8) = 16 字节
NENTRY_SIZE: t.CDefine = 16
def _name_table_add(table: GSList[NameEntry] | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
name: t.CChar | t.CPtr) -> t.CInt:
"""添加名到表。返回 1=重复, 0=成功添加"""
if table is None or name is None: return 0
# 检查重复
cur: NameEntry | t.CPtr = table.Head
while cur is not None:
if string.strcmp(cur.Name, name) == 0:
return 1
cur = cur.Next
# 添加新条目
entry: NameEntry | t.CPtr = pool.alloc(NENTRY_SIZE)
if entry is None: return 0
string.memset(entry, 0, NENTRY_SIZE)
entry.Name = name
table.append(entry)
return 0
def _name_table_contains(table: GSList[NameEntry] | t.CPtr,
name: t.CChar | t.CPtr) -> t.CInt:
"""检查名是否在表中。返回 1=存在, 0=不存在"""
if table is None or name is None: return 0
cur: NameEntry | t.CPtr = table.Head
while cur is not None:
if string.strcmp(cur.Name, name) == 0:
return 1
cur = cur.Next
return 0
# ============================================================
# 文本分析辅助
# ============================================================
def _is_char_name(ch: t.CChar) -> t.CInt:
"""判断字符是否为 SSA 名字符 [a-zA-Z0-9._]"""
if ch >= 'a' and ch <= 'z': return 1
if ch >= 'A' and ch <= 'Z': return 1
if ch >= '0' and ch <= '9': return 1
if ch == '.' or ch == '_': return 1
return 0
def _extract_def_name(pool: memhub.MemBuddy | t.CPtr,
text: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""从定义行提取被定义的 SSA 名。
定义行格式: "%<name> = <instruction>"
返回分配的 NUL 结尾名串(如 "%0"),或 None 若非定义行。
"""
if text is None: return None
if text[0] != '%': return None
# 扫描 " = " 模式
i: t.CInt = 1
while text[i] != '\0':
if text[i] == ' ' and text[i + 1] == '=' and text[i + 2] == ' ':
# 找到 " = " 在位置 i
name_len: t.CInt = i
name: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name is None: return None
j: t.CInt = 0
while j < name_len:
name[j] = text[j]
j += 1
name[name_len] = '\0'
return name
i += 1
return None
def _is_terminator(text: t.CChar | t.CPtr) -> t.CInt:
"""判断文本是否为终止指令"""
if text is None: return 0
if string.strncmp(text, "ret", 3) == 0: return 1
if string.strncmp(text, "br ", 3) == 0: return 1
if string.strncmp(text, "switch ", 7) == 0: return 1
if string.strncmp(text, "unreachable", 11) == 0: return 1
if string.strncmp(text, "indirectbr ", 11) == 0: return 1
if string.strncmp(text, "resume ", 7) == 0: return 1
return 0
def _is_phi(text: t.CChar | t.CPtr) -> t.CInt:
"""判断文本是否为 phi 指令"""
if text is None: return 0
if string.strstr(text, " = phi ") is not None: return 1
return 0
def _check_uses_in_line(table: GSList[NameEntry] | t.CPtr,
text: t.CChar | t.CPtr,
def_name: t.CChar | t.CPtr) -> t.CInt:
"""检查行中所有 SSA 名使用是否已定义。
跳过 def_name(定义位置的名字)。
返回未定义使用数量。
"""
if text is None: return 0
i: t.CInt = 0
undef_count: t.CInt = 0
while text[i] != '\0':
if text[i] == '%':
# 提取名
name_start: t.CInt = i
i += 1
while text[i] != '\0' and _is_char_name(text[i]) == 1:
i += 1
name_len: t.CInt = i - name_start
if name_len > 1:
# 构建临时名串进行比较
# 由于无法在栈上分配,用 strstr 进行简化检查
# 这里采用逐字符比较方式
if _name_matches_at(text, name_start, name_len, table) == 0:
# 检查是否是 def_name(定义本身的位置)
if def_name is not None:
if _str_matches_at(text, name_start, name_len, def_name) == 0:
undef_count += 1
else:
undef_count += 1
else:
i += 1
return undef_count
def _name_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt,
table: GSList[NameEntry] | t.CPtr) -> t.CInt:
"""检查 text[start:start+length] 是否匹配名表中的某个条目。
返回 1=匹配, 0=不匹配
"""
if table is None: return 0
cur: NameEntry | t.CPtr = table.Head
while cur is not None:
if cur.Name is not None:
if _str_matches_at(text, start, length, cur.Name) == 1:
return 1
cur = cur.Next
return 0
def _str_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt,
target: t.CChar | t.CPtr) -> t.CInt:
"""检查 text[start:start+length] 是否等于 target 字符串。
返回 1=匹配, 0=不匹配
"""
if text is None or target is None: return 0
# 检查 target 长度
target_len: t.CInt = string.strlen(target)
if target_len != length: return 0
i: t.CInt = 0
while i < length:
if text[start + i] != target[i]: return 0
i += 1
return 1
# ============================================================
# 主验证函数
# ============================================================
def verify_function(pool: memhub.MemBuddy | t.CPtr,
func: Function | t.CPtr,
result: VerifyResult | t.CPtr) -> t.CInt:
"""验证函数的 SSA 正确性。
参数:
pool: 内存池
func: 要验证的函数
result: 验证结果(调用前需用 _new_verify_result 创建)
返回: 错误数量(0 = 验证通过)
"""
if func is None or result is None: return 1
# 创建名表
name_table: GSList[NameEntry] | t.CPtr = _new_name_table(pool)
if name_table is None: return 1
# 1. 将函数参数加入名表(参数是已定义的)
param: Param | t.CPtr = None
if func.Params is not None:
param = func.Params.Head
while param is not None:
if param.Name is not None:
_name_table_add(name_table, pool, param.Name)
param = param.Next
# 1b. 将基本块名加入名表(块标签如 %then 是 br/phi 的合法引用目标)
blk_iter: BasicBlock | t.CPtr = None
if func.Blocks is not None:
blk_iter = func.Blocks.Head
while blk_iter is not None:
if blk_iter.Name is not None:
blk_name_len: t.CSizeT = string.strlen(blk_iter.Name)
blk_ref: t.CChar | t.CPtr = pool.alloc(blk_name_len + 2)
if blk_ref is not None:
# 构造 "%<name>" 字符串
blk_ref[0] = '%'
k: t.CSizeT = 0
while k < blk_name_len:
blk_ref[k + 1] = blk_iter.Name[k]
k += 1
blk_ref[blk_name_len + 1] = '\0'
_name_table_add(name_table, pool, blk_ref)
blk_iter = blk_iter.Next
# 2. 遍历所有块
blk: BasicBlock | t.CPtr = None
if func.Blocks is not None:
blk = func.Blocks.Head
while blk is not None:
# 检查终止指令
if blk.IsTerminated == 0:
# 进一步检查最后一行是否为终止指令
has_term: t.CInt = 0
line_check: Line | t.CPtr = None
if blk.Lines is not None:
line_check = blk.Lines.Head
while line_check is not None:
if line_check.Buf is not None:
if _is_terminator(line_check.Buf) == 1:
has_term = 1
line_check = line_check.Next
if has_term == 0:
blk_name: t.CChar | t.CPtr = "<unnamed>"
if blk.Name is not None:
blk_name = blk.Name
err_buf: t.CChar | t.CPtr = pool.alloc(128)
if err_buf is not None:
viperlib.snprintf(err_buf, 128, "ERROR: block '%s' missing terminator", blk_name)
_report_error(result, VERIFY_ERR_NO_TERMINATOR, err_buf)
# 遍历块内指令行
seen_non_phi: t.CInt = 0
line: Line | t.CPtr = None
if blk.Lines is not None:
line = blk.Lines.Head
while line is not None:
if line.Buf is not None:
text: t.CChar | t.CPtr = line.Buf
# 检查 phi 位置
if _is_phi(text) == 1:
if seen_non_phi == 1:
phi_err: t.CChar | t.CPtr = pool.alloc(128)
if phi_err is not None:
viperlib.snprintf(phi_err, 128, "ERROR: phi not at block start")
_report_error(result, VERIFY_ERR_PHI_NOT_FIRST, phi_err)
else:
# 非空行且非 phi 标记为已见非 phi
if string.strlen(text) > 0:
seen_non_phi = 1
# 提取定义名
def_name: t.CChar | t.CPtr = _extract_def_name(pool, text)
if def_name is not None:
# 检查重复定义
dup: t.CInt = _name_table_add(name_table, pool, def_name)
if dup == 1:
dup_err: t.CChar | t.CPtr = pool.alloc(128)
if dup_err is not None:
viperlib.snprintf(dup_err, 128, "ERROR: duplicate definition '%s'", def_name)
_report_error(result, VERIFY_ERR_DUPLICATE_DEF, dup_err)
# 检查未定义使用
undef: t.CInt = _check_uses_in_line(name_table, text, def_name)
if undef > 0:
use_err: t.CChar | t.CPtr = pool.alloc(128)
if use_err is not None:
viperlib.snprintf(use_err, 128, "ERROR: %d undefined use(s) in: %s", undef, text)
_report_error(result, VERIFY_ERR_UNDEFINED_USE, use_err)
line = line.Next
blk = blk.Next
return result.ErrorCount
def verify_module(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, result: VerifyResult | t.CPtr) -> t.CInt:
"""验证模块中所有函数的 SSA 正确性。
返回: 错误总数
"""
if mod is None or result is None: return 1
func: Function | t.CPtr = mod.FuncHead
while func is not None:
if func.IsDeclared == 0:
# 只验证有函数体的定义,跳过声明
verify_function(pool, func, result)
func = func.Next
return result.ErrorCount
+38
View File
@@ -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))
+823
View File
@@ -0,0 +1,823 @@
import t, c
from stdint import *
import string
import atom
import viperio
import stdio
import stdlib
# ============================================================
# memhub - Unified memory management library
# MemManager (polymorphic base class, vtable)
# ├─ MemPool (arena bump allocator, no support for individual free)
# ├─ MemSlab (fixed-size block pool, alloc/free tracked via bitmap)
# └─ MemBuddy (buddy system, supports alloc/free/realloc with coalescing)
# All subclasses override alloc/free/reset via vtable, invokable polymorphically through MemManager pointer
# ============================================================
MEMHUB_ALIGN: t.CDefine = 8
# MemSlab bitmap constants
MEMSLAB_MIN_BLOCK: t.CDefine = 16
MEMSLAB_BITMAP_BYTES: t.CDefine = 256
# MemBuddy buddy constants
MEMBUDDY_MIN_BLOCK: t.CDefine = 32
MEMBUDDY_MAX_ORDERS: t.CDefine = 32
MEMBUDDY_HEADER_SIZE: t.CDefine = 8
# 块尾 canary:alloc 时在块尾(用户数据区之外)写 8 字节哨兵,
# check_alive_blocks 校验——越界写穿数据区会破坏 canary,把
# "崩溃点漂移/事发地遥远"变成"确定性定位到越界写发生的文件"
MEMBUDDY_CANARY: t.CDefine = 8
def _canary_pattern() -> t.CUInt64T:
"""块尾 canary 值(0xA5A5A5A5A5A5A5A5,64 位)"""
lo: t.CUInt64T = t.CUInt64T(0xA5A5A5A5)
return (lo << 32) | lo
def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT:
if align == 0: return val
return (val + align - 1) & ~(align - 1)
def _largest_pow2_le(val: t.CSizeT) -> t.CSizeT:
if val == 0: return 0
p: t.CSizeT = 1
while p * 2 <= val:
p = p * 2
return p
def _block_size_at_order(order: t.CInt) -> t.CSizeT:
bs: t.CSizeT = MEMBUDDY_MIN_BLOCK
i: t.CInt
for i in range(order):
bs = bs << 1
return bs
# ============================================================
# MemManager - Polymorphic base class
# @t.CVTable explicit annotation to ensure recognition as vtable class during cross-module imports
# (HandlesImports only detects IsCVTable via decorator; automatic inference is unavailable across modules)
# ============================================================
@t.CVTable
class MemManager:
__provides__: list[str] = ['__memmgr__']
base: t.CVoid | t.CPtr # Starting address of memory region
size: t.CSizeT # Total size of memory region
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT):
self.base = base
self.size = size
# === Virtual functions (overridden by subclasses) ===
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
# Default: allocation not supported
return None
def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt:
# Default: no operation
return 0
def reset(self) -> t.CInt:
# Default: no operation
return 0
# === Concrete methods (invoke virtual functions for automatic polymorphic dispatch) ===
def calloc(self, count: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr:
total: t.CSizeT = count * size
ptr: t.CVoid | t.CPtr = self.alloc(total)
if ptr is not None:
string.memset(ptr, 0, total)
return ptr
def realloc(self, ptr: t.CVoid | t.CPtr, new_size: t.CSizeT) -> t.CVoid | t.CPtr:
if ptr is None:
return self.alloc(new_size)
if new_size == 0:
self.free(ptr)
return None
new_ptr: t.CVoid | t.CPtr = self.alloc(new_size)
if new_ptr is None:
return ptr
# Base class cannot track original allocation size; data will not be copied. Subclasses may override to preserve data
self.free(ptr)
return new_ptr
def __enter__(self) -> 'MemManager' | t.CPtr:
return self
def __exit__(self):
self.reset()
def alloc_buf(self, capacity: t.CSizeT) -> viperio.Buf | t.CPtr:
buf: viperio.Buf | t.CPtr = self.alloc(viperio.Buf.__sizeof__())
if buf is None:
return None
data_ptr: t.CVoid | t.CPtr = self.alloc(capacity)
if data_ptr is None:
return None
buf.__before_init__()
buf.__init__(t.CChar(t.CUInt64T(data_ptr), t.CPtr), capacity)
return buf
# ============================================================
# MemPool - Arena bump allocator
# Individual free operations are unsupported; reset reclaims all memory at once
# ============================================================
class MemPool(MemManager):
offset: t.CSizeT # Bump pointer offset
high_water: t.CSizeT # High-water mark
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT):
self.base = base
self.size = size
self.offset = 0
self.high_water = 0
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
if size == 0: return None
aligned: t.CSizeT = _align_up(size, MEMHUB_ALIGN)
if self.offset + aligned > self.size:
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size)
stdio.printf("[OOM] MemPool: total=%zu used=%zu (bump allocator, 无释放)\n",
self.size, self.offset)
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
stdlib.exit(1)
ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.base) + self.offset, t.CPtr)
self.offset += aligned
if self.offset > self.high_water:
self.high_water = self.offset
return ptr
def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt:
# Bump allocator does not support individual free operations
return 1
def reset(self) -> t.CInt:
self.offset = 0
self.high_water = 0
return 1
# ============================================================
# MemSlab - Fixed-size block pool
# Bitmap stored at the start of arena; subsequent area split into block_size units managed by free list
# ============================================================
class MemSlab(MemManager):
block_size: t.CSizeT # Block size (aligned)
block_count: t.CSizeT # Total block count
used_count: t.CSizeT # Used block count
free_list: t.CVoid | t.CPtr # Free list head
alloc_map: t.CUInt8T | t.CPtr # Allocation bitmap (at start of arena)
alloc_map_size: t.CSizeT # Bitmap byte count
usable: t.CVoid | t.CPtr # Usable block area start (after bitmap)
usable_size: t.CSizeT # Usable block area size
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT, block_size: t.CSizeT):
self.base = base
self.size = size
self.block_size = 0
self.block_count = 0
self.used_count = 0
self.free_list = None
self.alloc_map = None
self.alloc_map_size = 0
self.usable = None
self.usable_size = 0
if base is None: return
bs: t.CSizeT = _align_up(block_size, MEMHUB_ALIGN)
if bs < MEMSLAB_MIN_BLOCK: bs = MEMSLAB_MIN_BLOCK
map_bytes: t.CSizeT = _align_up(MEMSLAB_BITMAP_BYTES, MEMHUB_ALIGN)
if size < map_bytes + bs: return
self.alloc_map = base
self.alloc_map_size = map_bytes
self.usable = t.CVoid(t.CUInt64T(base) + map_bytes, t.CPtr)
self.usable_size = size - map_bytes
self.block_size = bs
# Clear bitmap
idx: t.CSizeT = 0
while idx < map_bytes:
self.alloc_map[idx] = 0
idx += 1
self.block_count = self.usable_size / bs
if self.block_count == 0: return
# Construct free list: the first 8 bytes of each block store pointer to next block
self.free_list = None
i: t.CSizeT = 0
while i < self.block_count:
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.usable) + i * bs, t.CPtr)
c.DerefAs(block, self.free_list)
self.free_list = block
i += 1
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
# Slab mode: allocate one block only if requested size <= block_size
if self.free_list is None:
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
stdio.printf("[OOM] 尝试分配: %zu 字节,失败(free_list 已空)\n", size)
stdio.printf("[OOM] MemSlab: block_size=%zu block_count=%zu used=%zu\n",
self.block_size, self.block_count, self.used_count)
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
stdlib.exit(1)
if size > self.block_size:
# 超块大小请求 = 调用方错误:优雅失败返回 NULL(类 malloc 语义,调用方自行判断)。
# 与 free_list 耗尽(真正的 OOM,打印后 exit(1))区分开。
stdio.printf("[WARN] MemSlab: 请求 %zu 字节超过 block_size=%zu,分配失败返回 NULL;应改用 MemBuddy/MemPool。\n",
size, self.block_size)
return None
block: t.CVoid | t.CPtr = self.free_list
self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
self.used_count += 1
idx: t.CSizeT = (t.CUInt64T(block) - t.CUInt64T(self.usable)) / self.block_size
self.alloc_map[idx / 8] = self.alloc_map[idx / 8] | t.CUInt8T(1 << (idx % 8))
return block
def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt:
if ptr is None: return 0
p: t.CUInt64T = t.CUInt64T(ptr)
if p < t.CUInt64T(self.usable): return 0
if p >= t.CUInt64T(self.usable) + self.block_count * self.block_size: return 0
if (p - t.CUInt64T(self.usable)) % self.block_size != 0: return 0
idx: t.CSizeT = (p - t.CUInt64T(self.usable)) / self.block_size
byte_idx: t.CSizeT = idx / 8
bit_idx: t.CInt = t.CInt(idx % 8)
if (self.alloc_map[byte_idx] >> bit_idx) & 1 == 0: return 0
self.alloc_map[byte_idx] = self.alloc_map[byte_idx] & t.CUInt8T(~(1 << bit_idx))
c.DerefAs(ptr, self.free_list)
self.free_list = ptr
self.used_count -= 1
return 1
def reset(self) -> t.CInt:
self.used_count = 0
self.free_list = None
i: t.CSizeT = 0
while i < self.block_count:
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.usable) + i * self.block_size, t.CPtr)
c.DerefAs(block, self.free_list)
self.free_list = block
if i / 8 < self.alloc_map_size:
self.alloc_map[i / 8] = 0
i += 1
return 1
# ============================================================
# MemBuddy - Buddy system allocator
# Free list head array stored at arena start; subsequent memory managed in power-of-two sized blocks
# Thread-safe (spinlock enabled), supports block coalescing
#
# Checkpoint 支持(供编译器等长任务回收阶段性分配):
# mark() → 返回当前分配水位(不分配内存)
# reset_to(m) → 释放水位 m 之后分配的所有块(回收到 free list)
# 记录栈从 usable 顶部预留 _CHK_RESERVE 字节,不参与 buddy 分配。
# ============================================================
class MemBuddy(MemManager):
# Override parent __provides__: MemBuddy provides both __mbuddy__ and __memmgr__.
# Within `with MemBuddy(...)` context, classes (e.g. _str) with __requires__=['__mbuddy__']
# can be automatically injected via _find_provider
__provides__: list[str] = ['__mbuddy__', '__memmgr__']
max_order: t.CInt # Maximum order
free_lists: t.CUInt64T | t.CPtr # Free list head array (located at arena start)
lock_val: t.CVolatile | t.CInt # Spinlock
usable: t.CVoid | t.CPtr # Start of usable memory region (skips free_lists)
usable_size: t.CSizeT # Size of usable memory (power of two)
chk_stack: t.CUInt64T | t.CPtr # Checkpoint 分配记录栈(存 block 地址)
chk_cap: t.CSizeT # 记录栈容量(条目数)
chk_depth: t.CSizeT # 当前记录深度
chk_base: t.CVoid | t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区)
big_alloc_count: t.CSizeT # ≥8KB 大分配计数(OOM 诊断:定位大缓冲反复分配)
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT):
self.base = base
self.size = size
self.max_order = 0
self.free_lists = None
self.lock_val = 0
self.usable = None
self.usable_size = 0
self.chk_stack = None
self.chk_cap = 0
self.chk_depth = 0
self.chk_base = None
self.big_alloc_count = 0
self.lock_val = 0
fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8
self.free_lists = base
# Initialize all free list heads to be 0
i: t.CInt
for i in range(MEMBUDDY_MAX_ORDERS + 1):
self.free_lists[i] = 0
if size <= fl_bytes:
self.usable = None
self.usable_size = 0
self.max_order = 0
return
remaining: t.CSizeT = size - fl_bytes
# 注意:不能在 __init__ 里预留 checkpoint 记录栈!
# 记录栈改为 mark() 时从 buddy 池懒分配(见 mark())。
#
# 非 2 的幂 arena 支持:主池 1.2GB(非 2 幂)不再被
# _largest_pow2_le 砍成 1GB 浪费 0.2GB。整个区域按二进制
# 分解拆成若干个 2 的幂空闲块压入对应 free list;buddy 合并
# 按 offset^bs 匹配,跨分解边界的块因 order 不匹配自然停止
# 合并,不会破坏 buddy 一致性。remaining 恰为 2 的幂时分解
# 结果与原实现(单个 max_order 块)完全等价。
max_blk: t.CSizeT = _largest_pow2_le(remaining)
if max_blk < MEMBUDDY_MIN_BLOCK:
self.usable = None
self.usable_size = 0
self.max_order = 0
return
self.usable = t.CVoid(t.CUInt64T(base) + fl_bytes, t.CPtr)
# 计算 max_order: log2(max_blk / MIN_BLOCK)
self.max_order = 0
bs: t.CSizeT = MEMBUDDY_MIN_BLOCK
while bs < max_blk:
bs = bs << 1
self.max_order += 1
# 二进制分解:把 [usable, usable+remaining) 拆成 2 的幂空闲块。
# 尾部碎片(< MIN_BLOCK)不入 free list;usable_size 记实际
# 可分配字节(used/free 统计不含碎片)。
pos: t.CSizeT = 0
rem: t.CSizeT = remaining
used_area: t.CSizeT = 0
while rem >= MEMBUDDY_MIN_BLOCK:
blk: t.CSizeT = _largest_pow2_le(rem)
o: t.CInt = 0
ob: t.CSizeT = MEMBUDDY_MIN_BLOCK
while ob < blk:
ob = ob << 1
o += 1
self._fl_push(o, t.CVoid(t.CUInt64T(self.usable) + pos, t.CPtr))
pos += blk
used_area += blk
rem -= blk
self.usable_size = used_area
# === Checkpoint support ===
def mark(self) -> t.CSizeT:
"""返回当前分配水位(checkpoint)
记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、
避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。
初始容量 2M 条目(16MB):单文件翻译(parse AST + 生成 IR)可产生
几十万次 alloc,64K 初始容量会在首个大文件就触发 realloc 扩容,
扩容失败时块不再记录 → reset_to 永久 no-op → 所有分配泄漏 →
1GB 主池 OOM(NewAstTest Phase2 根因)。
"""
if self.chk_stack is None:
cap: t.CSizeT = 2 * 1024 * 1024
base: t.CVoid | t.CPtr = t.CVoid(stdlib.malloc(cap * 8), t.CPtr)
if base is None:
return 0
self.chk_base = base
self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(base, t.CPtr))
self.chk_cap = cap
self.chk_depth = 0
return self.chk_depth
def reset_to(self, mark: t.CSizeT):
"""释放水位 mark 之后分配的所有块,回收到 free list
栈中每个 block:若 header 仍标记为已分配(奇数),_coalesce 归还;
若已被单独 free(header==0),跳过避免重复归还。
"""
if self.chk_stack is None:
return
if mark > self.chk_depth:
# mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例),
# reset 将 no-op → 之后分配全泄漏 → 1GB 主池 OOM。fail-fast 暴露。
stdio.printf(
"[MEM] reset_to mark=%zu > chk_depth=%zu(mark 异常,reset 失效,终止)\n",
mark, self.chk_depth)
return
if mark >= self.chk_depth:
return
self._lock()
while self.chk_depth > mark:
self.chk_depth -= 1
block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[self.chk_depth], t.CPtr)
if block is None:
continue
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
stored_val: t.CUInt64T = t.CUInt64T(stored)
if (stored_val & 1) == 0:
continue # 已被单独 free,跳过
order: t.CInt = t.CInt(stored_val >> 1)
if order < 0 or order > self.max_order:
continue
self._coalesce(block, order)
self._unlock()
def reset_all(self):
"""回收全部已分配块(等价 reset_to(0))"""
if self.chk_stack is None:
return
self.reset_to(0)
# === Free list operations ===
def _fl_push(self, order: t.CInt, block: t.CVoid | t.CPtr):
old_head: t.CUInt64T = self.free_lists[order]
c.DerefAs(block, t.CVoid(old_head, t.CPtr))
self.free_lists[order] = t.CUInt64T(block)
def _fl_pop(self, order: t.CInt) -> t.CVoid | t.CPtr:
head_val: t.CUInt64T = self.free_lists[order]
if head_val == 0:
return None
block: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr)
next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
self.free_lists[order] = t.CUInt64T(next_ptr)
return block
def _fl_find_and_remove(self, order: t.CInt, target: t.CVoid | t.CPtr) -> t.CInt:
head_val: t.CUInt64T = self.free_lists[order]
if head_val == 0:
return 0
head: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr)
if t.CUInt64T(head) == t.CUInt64T(target):
next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(head, t.CPtr)), t.CPtr)
self.free_lists[order] = t.CUInt64T(next_ptr)
return 1
prev: t.CVoid | t.CPtr = head
cur: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(head, t.CPtr)), t.CPtr)
while t.CUInt64T(cur) != 0:
if t.CUInt64T(cur) == t.CUInt64T(target):
next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
c.DerefAs(prev, next_ptr)
return 1
prev = cur
cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
return 0
# === Buddy system core ===
def _buddy_of(self, block: t.CVoid | t.CPtr, order: t.CInt) -> t.CVoid | t.CPtr:
offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable)
bs: t.CSizeT = _block_size_at_order(order)
buddy_offset: t.CSizeT = offset ^ bs
return t.CVoid(t.CUInt64T(self.usable) + buddy_offset, t.CPtr)
def _order_for_size(self, size: t.CSizeT) -> t.CInt:
order: t.CInt = 0
bs: t.CSizeT = MEMBUDDY_MIN_BLOCK
while bs < size:
bs = bs << 1
order += 1
return order
def _split_to_order(self, to_order: t.CInt) -> t.CVoid | t.CPtr:
found_order: t.CInt = to_order
while found_order <= self.max_order:
if self.free_lists[found_order] != 0:
break
found_order += 1
if found_order > self.max_order:
return None
block: t.CVoid | t.CPtr = self._fl_pop(found_order)
while found_order > to_order:
found_order -= 1
bs: t.CSizeT = _block_size_at_order(found_order)
buddy: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(block) + bs, t.CPtr)
self._fl_push(found_order, buddy)
return block
def _coalesce(self, block: t.CVoid | t.CPtr, order: t.CInt):
while order < self.max_order:
buddy: t.CVoid | t.CPtr = self._buddy_of(block, order)
found: t.CInt = self._fl_find_and_remove(order, buddy)
if found == 0:
break
if t.CUInt64T(buddy) < t.CUInt64T(block):
block = buddy
order += 1
self._fl_push(order, block)
def _is_valid_ptr(self, ptr: t.CVoid | t.CPtr) -> t.CInt:
if ptr is None: return 0
if self.usable is None: return 0
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr)
if t.CUInt64T(block) < t.CUInt64T(self.usable): return 0
if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size: return 0
offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable)
if offset % MEMBUDDY_MIN_BLOCK != 0: return 0
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
stored_val: t.CUInt64T = t.CUInt64T(stored)
if (stored_val & 1) == 0: return 0
order: t.CInt = t.CInt(stored_val >> 1)
if order < 0: return 0
if order > self.max_order: return 0
# 记录栈一致性校验:分配时(alloc)每个 block 地址都会压入 chk_stack。
# reset_to(mark) 会把 [mark, chk_depth) 的块弹栈并归还 free list,
# 之后这些地址会被重新分配。若一个 header 恰好是合法奇数(假阳性),
# 但地址不在当前 chk_stack[0..chk_depth) 存活区间内,说明已被回收,
# 不能当作有效指针(否则 _format_func_type_str/TypePrint 会沿垃圾链
# 无限分配导致 OOM)。
# 注意:chk_stack 容量满(64K)后 alloc 不再记录新块(chk_depth==chk_cap),
# 此时无法区分,跳过校验(退化到仅 header 校验,避免误判正常 free)。
if self.chk_stack is not None and self.chk_depth < self.chk_cap:
alive: t.CInt = 0
ci: t.CSizeT = 0
while ci < self.chk_depth:
if self.chk_stack[ci] == t.CUInt64T(block):
alive = 1
break
ci += 1
if alive == 0:
return 0
return 1
# === Spinlock ===
def _lock(self): # can use the spinlock library for decoupling
while atom.__atomic_test_and_set(c.Addr(self.lock_val), atom.ATOMIC_ACQUIRE):
pass
def _unlock(self):
atom.__atomic_clear(c.Addr(self.lock_val), atom.ATOMIC_RELEASE)
# === Virtual function overrides ===
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
self._lock()
result: t.CVoid | t.CPtr = None
if size != 0 and self.usable is not None:
# +MEMBUDDY_CANARY:预留块尾 8 字节哨兵(用户数据区之外),越界写定位用
needed: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY
order: t.CInt = self._order_for_size(needed)
if order <= self.max_order:
block: t.CVoid | t.CPtr = self._split_to_order(order)
if block is not None:
c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr))
result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr)
# 写块尾 canary(block + block_size - CANARY)
bs: t.CSizeT = _block_size_at_order(order)
c.DerefAs(t.CVoid(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr),
t.CVoid(_canary_pattern(), t.CPtr))
# 记录到 checkpoint 栈(供 reset_to 回收)
# 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失
# → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题)
if self.chk_stack is not None:
if self.chk_depth >= self.chk_cap:
new_cap: t.CSizeT = self.chk_cap * 2
new_stack: t.CVoid | t.CPtr = t.CVoid(
stdlib.realloc(self.chk_base, new_cap * 8), t.CPtr)
if new_stack is not None:
self.chk_base = new_stack
self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(new_stack, t.CPtr))
self.chk_cap = new_cap
else:
# realloc 失败:块不再记录 → reset_to 无法回收该块 →
# 渐进泄漏最终 1GB 主池 OOM。fail-fast 暴露而非静默。
stdio.printf(
"[MEM] 记录栈 realloc 失败 cap=%zu depth=%zu(reset 将失效,终止)\n",
self.chk_cap, self.chk_depth)
if self.chk_depth < self.chk_cap:
self.chk_stack[self.chk_depth] = t.CUInt64T(block)
self.chk_depth += 1
if result is None:
# 分配失败诊断(定位"异常 size/池耗尽导致 None → 调用方解引用段错误")
if size != 0 and self.usable is not None:
needed2: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY
order2: t.CInt = self._order_for_size(needed2)
stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu\n",
size, needed2, order2, self.max_order, self.used_bytes())
# 越界写诊断:free list 结构损坏(self_check!=0)说明有越界写穿
# 破坏块头/free list next 指针 → alloc 找不到块(used 虚高非真实耗尽)
sc: t.CInt = self.self_check()
stdio.printf("[MEM] alloc 失败 self_check=%d free_bytes=%zu free_count=%zu chk_depth=%zu big=%zu\n",
sc, self.free_bytes(), self.free_count(), self.chk_depth, self.big_alloc_count)
# chk_depth 巨大(数百万)→ 分配次数爆炸(每语句/每调用反复分配);
# chk_depth 不大但 used 巨大 → 单次大分配(缓冲/表扩容)反复发生
if order2 > self.max_order:
stdio.printf("[MEM] 原因:请求 size 超 pool 最大块(order %d > max %d)\n",
order2, self.max_order)
else:
stdio.printf("[MEM] 原因:pool 耗尽(空闲 %zu 字节不足)\n", self.free_bytes())
# 分配失败(alloc(0) 或池耗尽):解锁并返回 None,由调用者决定后续处理。
# 不能 exit——测试依赖 alloc 失败返回 None 后继续 free+重试
# (如 OOM section: 耗尽后 free 一块再 alloc 应成功)。
self._unlock()
return None
self._unlock()
return result
def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt:
self._lock()
if ptr is not None:
if self._is_valid_ptr(ptr) != 0:
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr)
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
stored_val: t.CUInt64T = t.CUInt64T(stored)
order: t.CInt = t.CInt(stored_val >> 1)
c.DerefAs(block, t.CVoid(0, t.CPtr))
self._coalesce(block, order)
self._unlock()
return 1
def _rebuild_free_lists(self):
"""按二进制分解重建空闲链表(reset 恢复初始分配格局)
与 __init__ 的初始化分解一致:非 2 的幂 arena 会拆成多个
2 的幂空闲块(buddy 合并跨分解边界时因 order 不匹配自然
停止,安全);2 的幂 arena 等价于单个 max_order 块。
"""
i: t.CInt
for i in range(MEMBUDDY_MAX_ORDERS + 1):
self.free_lists[i] = 0
pos: t.CSizeT = 0
rem: t.CSizeT = self.usable_size
while rem >= MEMBUDDY_MIN_BLOCK:
blk: t.CSizeT = _largest_pow2_le(rem)
o: t.CInt = 0
ob: t.CSizeT = MEMBUDDY_MIN_BLOCK
while ob < blk:
ob = ob << 1
o += 1
self._fl_push(o, t.CVoid(t.CUInt64T(self.usable) + pos, t.CPtr))
pos += blk
rem -= blk
def reset(self) -> t.CInt:
if self.usable is None:
return 0
self._rebuild_free_lists()
return 1
# realloc override: buddy system reads original order from block header; old_size is not required
def realloc(self, ptr: t.CVoid | t.CPtr, new_size: t.CSizeT) -> t.CVoid | t.CPtr:
if ptr is None:
return self.alloc(new_size)
if new_size == 0:
self.free(ptr)
return None
if self._is_valid_ptr(ptr) == 0:
return None
block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr)
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
stored_val: t.CUInt64T = t.CUInt64T(stored)
old_order: t.CInt = t.CInt(stored_val >> 1)
needed: t.CSizeT = new_size + MEMBUDDY_HEADER_SIZE
new_order: t.CInt = self._order_for_size(needed)
if new_order <= old_order:
return ptr
new_ptr: t.CVoid | t.CPtr = self.alloc(new_size)
if new_ptr is None:
return ptr
old_block_size: t.CSizeT = _block_size_at_order(old_order)
old_data_size: t.CSizeT = old_block_size - MEMBUDDY_HEADER_SIZE
string.memcpy(new_ptr, ptr, old_data_size)
self.free(ptr)
return new_ptr
# === Status Queries ===
@property
def mem_size(self) -> t.CSizeT:
# Total usable region size (power of two). Maximum allocatable size = mem_size - MEMBUDDY_HEADER_SIZE
return self.usable_size
def stats(self) -> t.CSizeT:
# Return total usable region size, for status statistics
return self.usable_size
def free_count(self) -> t.CSizeT:
# Count total blocks in all order lists for status statistics
count: t.CSizeT = 0
i: t.CInt
for i in range(MEMBUDDY_MAX_ORDERS + 1):
head_val: t.CUInt64T = self.free_lists[i]
cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr)
while t.CUInt64T(cur) != 0:
count += 1
cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
return count
def free_bytes(self) -> t.CSizeT:
# Count total bytes in all free blocks for status statistics
total: t.CSizeT = 0
i: t.CInt
for i in range(MEMBUDDY_MAX_ORDERS + 1):
head_val: t.CUInt64T = self.free_lists[i]
cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr)
while t.CUInt64T(cur) != 0:
total += _block_size_at_order(i)
cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
return total
def used_bytes(self) -> t.CSizeT:
# Used bytes = total usable region size - free bytes in all free blocks
return self.usable_size - self.free_bytes()
def dump_stats(self, label: t.CChar | t.CPtr):
# Print memory usage statistics
fb: t.CSizeT = self.free_bytes()
ub: t.CSizeT = self.usable_size - fb
stdio.printf("[MEM] %s: total=%zu used=%zu (%zu%%) free=%zu free_blocks=%zu\n",
label, self.usable_size, ub,
(ub * 100) / self.usable_size if self.usable_size > 0 else 0,
fb, self.free_count())
def self_check(self) -> t.CInt:
# Validate buddy allocator internal consistency, return 0=OK, non-0=damage
if self.usable is None:
return 0
# 环检测:free list 被越界写破坏 next 指针后可能成环,
# 无步数上限会导致无限循环(崩溃点漂移排查哨兵必须能终止)。
max_steps: t.CSizeT = self.usable_size / MEMBUDDY_MIN_BLOCK + 2
i: t.CInt
for i in range(MEMBUDDY_MAX_ORDERS + 1):
head_val: t.CUInt64T = self.free_lists[i]
cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr)
steps: t.CSizeT = 0
while t.CUInt64T(cur) != 0:
steps += 1
if steps > max_steps:
return 4 # free list 成环或节点数超上限(next 指针被破坏)
# Check pointer is in usable region range
if t.CUInt64T(cur) < t.CUInt64T(self.usable):
return 1
if t.CUInt64T(cur) >= t.CUInt64T(self.usable) + self.usable_size:
return 2
# Check alignment: order i blocks must be aligned to size _block_size_at_order(i)
offset: t.CSizeT = t.CUInt64T(cur) - t.CUInt64T(self.usable)
bs: t.CSizeT = _block_size_at_order(i)
if offset % bs != 0:
return 3
cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
return 0
def check_alive_blocks(self, from_mark: t.CSizeT) -> t.CInt:
# 检查 [from_mark, chk_depth) 记录的所有已分配块 header 完整性。
# 越界写(参数错位/下标 GEP 越界)会破坏相邻块 header(奇偶位/order 错乱),
# 返回 0=OK,非 0=损坏(rc 语义见调用方注释)。
# 用于 reset_to 前哨兵:把"崩溃点漂移"变成"确定性定位到损坏发生的文件"。
if self.chk_stack is None:
return
if from_mark > self.chk_depth:
# from_mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例),
# 校验将 no-op → 越界写漏检。fail-fast 暴露。
stdio.printf(
"[MEM] check_alive_blocks from_mark=%zu > chk_depth=%zu(mark 异常)\n",
from_mark, self.chk_depth)
return
if from_mark >= self.chk_depth:
return 0
if self.usable is None:
return 0
ci: t.CSizeT = from_mark
while ci < self.chk_depth:
block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[ci], t.CPtr)
if block is not None:
if t.CUInt64T(block) < t.CUInt64T(self.usable):
return 1
if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size:
return 2
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
stored_val: t.CUInt64T = t.CUInt64T(stored)
if (stored_val & 1) != 0:
# 活块:header 必须是 (order<<1)|1,order 合法且块对齐到该 order 大小
order: t.CInt = t.CInt(stored_val >> 1)
if order < 0:
return 3
if order > self.max_order:
return 4
offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable)
bs: t.CSizeT = _block_size_at_order(order)
if offset % bs != 0:
return 5
# 块尾 canary 校验:越界写穿数据区会破坏块尾哨兵,
# 立即定位到越界写发生的文件(崩溃点漂移的关键哨兵)
can_stored: t.CVoid | t.CPtr = t.CVoid(
c.Deref(t.CUInt64T(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), t.CPtr),
t.CPtr)
if t.CUInt64T(can_stored) != _canary_pattern():
return 6
ci += 1
return 0
+1163
View File
File diff suppressed because it is too large. Load diff
+134
View File
@@ -0,0 +1,134 @@
import t, c
from stdint import *
import platmacro
import memhub
import os.path
import os._win32
import os._posix
# os package entry point
# Dispatches to _win32 or _posix backend based on platmacro.IS_WINDOWS
# os.path is for cross-platform pure string operations, can be used directly
# Module-level global MBuddy pointer (initialized by the user in main)
_mbuddy: memhub.MemBuddy | t.CPtr
# =============================================================================
# File/Directory Attribute Query
# =============================================================================
def exists(path: str) -> bool:
"""Check if the file/directory exists"""
if platmacro.IS_WINDOWS:
return os._win32.exists(path)
return os._posix.exists(path)
def isdir(path: str) -> bool:
"""Check if the path is a directory"""
if platmacro.IS_WINDOWS:
return os._win32.isdir(path)
return os._posix.isdir(path)
def isfile(path: str) -> bool:
"""Check if the path is a regular file"""
if platmacro.IS_WINDOWS:
return os._win32.isfile(path)
return os._posix.isfile(path)
def getsize(path: str) -> t.CInt64T:
"""Returns the file size (in bytes). Returns -1 on failure."""
if platmacro.IS_WINDOWS:
return os._win32.getsize(path)
return os._posix.getsize(path)
# =============================================================================
# Working Directory
# =============================================================================
def getcwd() -> str:
"""Return the current working directory (memory allocated via _mbuddy)"""
if platmacro.IS_WINDOWS:
return os._win32.getcwd()
return os._posix.getcwd_impl()
def chdir(path: str) -> int:
"""Switch the current working directory. Returns 0 if successful, -1 if it fails."""
if platmacro.IS_WINDOWS:
return os._win32.chdir(path)
return os._posix.chdir_impl(path)
# =============================================================================
# File/Directory Operations
# =============================================================================
def mkdir(path: str) -> int:
"""Create a directory. Returns 0 on success, -1 on failure."""
if platmacro.IS_WINDOWS:
return os._win32.mkdir(path)
return os._posix.mkdir_impl(path)
def remove(path: str) -> int:
"""Delete the file. Returns 0 if successful, -1 if it fails."""
if platmacro.IS_WINDOWS:
return os._win32.remove(path)
return os._posix.remove(path)
def rmdir(path: str) -> int:
"""Delete empty directories. Returns 0 if successful, -1 if it fails."""
if platmacro.IS_WINDOWS:
return os._win32.rmdir(path)
return os._posix.rmdir_impl(path)
def rename(old_path: str, new_path: str) -> int:
"""Rename/move a file or directory. Returns 0 on success, -1 on failure."""
if platmacro.IS_WINDOWS:
return os._win32.rename(old_path, new_path)
return os._posix.rename_impl(old_path, new_path)
def chmod(path: str, mode: int) -> int:
"""Modify file permissions. Returns 0 on success, -1 on failure.
On Windows, only the read-only bit (S_IWUSR) is handled;
On POSIX, full permission bits are used."""
if platmacro.IS_WINDOWS:
return os._win32.chmod(path, mode)
return os._posix.chmod_impl(path, mode)
# =============================================================================
# Table of Contents Listing
# =============================================================================
def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
"""列举目录下的文件/子目录名。
out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。
文件名通过 _mbuddy 分配内存。
max_count 为 out_names 数组最大容量。
返回实际列举的条目数。失败返回 0。"""
if platmacro.IS_WINDOWS:
return os._win32.listdir(path, out_names, max_count)
return os._posix.listdir(path, out_names, max_count)
# =============================================================================
# 命令执行
# =============================================================================
def system(cmd: str) -> int:
"""执行命令行命令(通过 C 运行时 system())。
命令输出直接到终端(继承父进程 stdout/stderr)。
返回命令的退出码(0 表示成功)。"""
if platmacro.IS_WINDOWS:
return os._win32.system(cmd)
return os._posix.system_impl(cmd)
+190
View File
@@ -0,0 +1,190 @@
import t, c
from stdint import *
import posix
import memhub
import stdlib
# POSIX 路径最大长度
MAX_PATH_LEN: t.CDefine = 4096
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
_mbuddy: memhub.MemBuddy | t.CPtr
# =============================================================================
# 文件/目录属性查询
# =============================================================================
def _stat(path: str) -> posix.Stat | t.CPtr:
"""调用 stat 并返回 Stat 结构体指针。失败返回 None。
注意:Stat 结构体通过 _mbuddy 分配,调用者负责释放。"""
st: posix.Stat = posix.Stat()
result: INT = posix.stat(path, t.CPtr(c.Addr(st)))
if result != 0:
return None
return t.CPtr(c.Addr(st))
def exists(path: str) -> bool:
"""检查文件/目录是否存在"""
result: INT = posix.access(path, posix.F_OK)
if result == 0:
return True
return False
def isdir(path: str) -> bool:
"""检查路径是否为目录"""
st: posix.Stat = posix.Stat()
result: INT = posix.stat(path, t.CPtr(c.Addr(st)))
if result != 0:
return False
if posix.S_ISDIR(st.st_mode):
return True
return False
def isfile(path: str) -> bool:
"""检查路径是否为普通文件"""
st: posix.Stat = posix.Stat()
result: INT = posix.stat(path, t.CPtr(c.Addr(st)))
if result != 0:
return False
if posix.S_ISREG(st.st_mode):
return True
return False
def getsize(path: str) -> t.CInt64T:
"""返回文件大小(字节)。失败返回 -1。"""
st: posix.Stat = posix.Stat()
result: INT = posix.stat(path, t.CPtr(c.Addr(st)))
if result != 0:
return -1
return st.st_size
# =============================================================================
# 工作目录
# =============================================================================
def getcwd_impl() -> str:
"""返回当前工作目录(通过 _mbuddy 分配内存)"""
buf: bytes = _mbuddy.alloc(MAX_PATH_LEN)
if buf == None: return None
result: CHARPTR = posix.getcwd(buf, MAX_PATH_LEN)
if result == None:
return None
return str(buf)
def chdir_impl(path: str) -> int:
"""切换当前工作目录。成功返回 0,失败返回 -1。"""
result: INT = posix.chdir(path)
if result != 0:
return -1
return 0
# =============================================================================
# 文件/目录操作
# =============================================================================
def mkdir_impl(path: str) -> int:
"""创建目录。成功返回 0,失败返回 -1。
默认权限 0o755(rwxr-xr-x)。"""
result: INT = posix.mkdir(path, 0o755)
if result != 0:
return -1
return 0
def remove(path: str) -> int:
"""删除文件。成功返回 0,失败返回 -1。"""
result: INT = posix.unlink(path)
if result != 0:
return -1
return 0
def rmdir_impl(path: str) -> int:
"""删除空目录。成功返回 0,失败返回 -1。"""
result: INT = posix.rmdir(path)
if result != 0:
return -1
return 0
def rename_impl(old_path: str, new_path: str) -> int:
"""重命名/移动文件或目录。成功返回 0,失败返回 -1。"""
result: INT = posix.rename(old_path, new_path)
if result != 0:
return -1
return 0
def chmod_impl(path: str, mode: int) -> int:
"""修改文件权限。成功返回 0,失败返回 -1。
mode 为 POSIX 权限位(如 0o755)。"""
result: INT = posix.chmod(path, posix.mode_t(mode))
if result != 0:
return -1
return 0
# =============================================================================
# 目录列举(opendir / readdir / closedir)
# =============================================================================
def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
"""列举目录下的文件/子目录名。
out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。
文件名通过 _mbuddy 分配内存。
max_count 为 out_names 数组最大容量。
返回实际列举的条目数。失败返回 0。"""
dirp: posix.DIR | t.CPtr = posix.opendir(path)
if dirp == None:
return 0
count: ULONG = 0
while count < max_count:
entry: posix.Dirent | t.CPtr = posix.readdir(dirp)
if entry == None:
break
# 读取 d_name 字段
name: str = entry.d_name
if name[0] == '.':
if name[1] == 0:
# "."
continue
if name[1] == '.' and name[2] == 0:
# ".."
continue
# 复制文件名到新分配的内存
name_len: t.CSizeT = len(name)
name_buf: bytes = _mbuddy.alloc(name_len + 1)
if name_buf == None: break
i: t.CSizeT = 0
for ch in name:
name_buf[i] = ch
i += 1
name_buf[name_len] = 0
out_names[count] = str(name_buf)
count += 1
posix.closedir(dirp)
return count
# =============================================================================
# 命令执行
# =============================================================================
def system_impl(cmd: str) -> int:
"""执行命令行命令(通过 C 运行时 system())。
命令输出直接到子进程的终端(继承父进程 stdout/stderr)。
返回命令的退出码(0 表示成功)。"""
return stdlib.system(cmd)
+234
View File
@@ -0,0 +1,234 @@
import t, c
from stdint import *
import w32.win32base
import w32.win32file
import memhub
import stdlib
# Windows 路径最大长度
MAX_PATH_LEN: t.CDefine = 260
# INVALID_FILE_ATTRIBUTES
INVALID_FILE_ATTRIBUTES: t.CDefine = 0xFFFFFFFF
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
_mbuddy: memhub.MemBuddy | t.CPtr
# =============================================================================
# 文件/目录属性查询
# =============================================================================
def _get_attrs(path: str) -> ULONG:
"""获取文件属性。失败返回 INVALID_FILE_ATTRIBUTES。"""
return w32.win32file.GetFileAttributesA(path)
def exists(path: str) -> bool:
"""检查文件/目录是否存在"""
attrs: ULONG = _get_attrs(path)
if attrs == INVALID_FILE_ATTRIBUTES:
return False
return True
def isdir(path: str) -> bool:
"""检查路径是否为目录"""
attrs: ULONG = _get_attrs(path)
if attrs == INVALID_FILE_ATTRIBUTES:
return False
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
return True
return False
def isfile(path: str) -> bool:
"""检查路径是否为普通文件"""
attrs: ULONG = _get_attrs(path)
if attrs == INVALID_FILE_ATTRIBUTES:
return False
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
return False
return True
def getsize(path: str) -> t.CInt64T:
"""返回文件大小(字节)。失败返回 -1。"""
handle: w32.win32base.HANDLE = w32.win32file.CreateFileA(
path, w32.win32file.GENERIC_READ, w32.win32file.FILE_SHARE_READ,
t.CPtr(0), w32.win32file.OPEN_EXISTING, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0)
)
if handle == w32.win32base.INVALID_HANDLE_VALUE:
return -1
li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
result: BOOL = w32.win32file.GetFileSizeEx(handle, t.CPtr(c.Addr(li)))
w32.win32base.CloseHandle(handle)
if result == 0:
return -1
return li.QuadPart
# =============================================================================
# 工作目录
# =============================================================================
def getcwd() -> str:
"""返回当前工作目录(通过 _mbuddy 分配内存)"""
buf: bytes = _mbuddy.alloc(MAX_PATH_LEN + 1)
if buf == None: return None
length: ULONG = w32.win32file.GetCurrentDirectoryA(MAX_PATH_LEN + 1, buf)
if length == 0:
return None
if length > MAX_PATH_LEN:
# 缓冲区不够,重新分配
buf2: bytes = _mbuddy.alloc(length + 1)
if buf2 == None: return None
w32.win32file.GetCurrentDirectoryA(length + 1, buf2)
buf2[length] = 0
return str(buf2)
buf[length] = 0
return str(buf)
def chdir(path: str) -> int:
"""切换当前工作目录。成功返回 0,失败返回 -1。"""
result: BOOL = w32.win32file.SetCurrentDirectoryA(path)
if result == 0:
return -1
return 0
# =============================================================================
# 文件/目录操作
# =============================================================================
def mkdir(path: str) -> int:
"""创建目录。成功返回 0,失败返回 -1。"""
result: BOOL = w32.win32file.CreateDirectoryA(path, t.CPtr(0))
if result == 0:
return -1
return 0
def remove(path: str) -> int:
"""删除文件。成功返回 0,失败返回 -1。"""
result: BOOL = w32.win32file.DeleteFileA(path)
if result == 0:
return -1
return 0
def rmdir(path: str) -> int:
"""删除空目录。成功返回 0,失败返回 -1。"""
result: BOOL = w32.win32file.RemoveDirectoryA(path)
if result == 0:
return -1
return 0
def rename(old_path: str, new_path: str) -> int:
"""重命名/移动文件或目录。成功返回 0,失败返回 -1。"""
result: BOOL = w32.win32file.MoveFileExA(
old_path, new_path,
w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED
)
if result == 0:
return -1
return 0
def chmod(path: str, mode: int) -> int:
"""修改文件属性(Windows 简化版:只处理只读位)。
mode 的 S_IWUSR 位(0o200)为 0 时设为只读,为 1 时设为可写。
成功返回 0,失败返回 -1。"""
if (mode & 0o200) != 0:
# 可写:清除只读属性
result: BOOL = w32.win32file.SetFileAttributesA(
path, w32.win32file.FILE_ATTRIBUTE_NORMAL
)
else:
# 只读:设置只读属性
result: BOOL = w32.win32file.SetFileAttributesA(
path, w32.win32file.FILE_ATTRIBUTE_READONLY
)
if result == 0:
return -1
return 0
# =============================================================================
# 目录列举(FindFirstFile / FindNextFile)
# =============================================================================
def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
"""列举目录下的文件/子目录名。
out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。
文件名通过 _mbuddy 分配内存。
max_count 为 out_names 数组最大容量。
返回实际列举的条目数。失败返回 0。"""
# 构造搜索模式:path\*
path_len: t.CSizeT = len(path)
pattern: bytes = _mbuddy.alloc(path_len + 3)
if pattern == None: return 0
i: t.CSizeT = 0
for ch in path:
pattern[i] = ch
i += 1
# 添加 \* 后缀
if path[path_len - 1] != '\\' and path[path_len - 1] != '/':
pattern[i] = '\\'
i += 1
pattern[i] = '*'
i += 1
pattern[i] = 0
find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA()
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data)))
if handle == w32.win32base.INVALID_HANDLE_VALUE:
return 0
count: ULONG = 0
while count < max_count:
# 跳过 . 和 ..
name: str = find_data.cFileName
if name[0] == '.':
if name[1] == 0:
# "."
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
break
continue
if name[1] == '.' and name[2] == 0:
# ".."
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
break
continue
# 复制文件名到新分配的内存
name_len: t.CSizeT = len(name)
name_buf: bytes = _mbuddy.alloc(name_len + 1)
if name_buf == None: break
j: t.CSizeT = 0
for ch in name:
name_buf[j] = ch
j += 1
name_buf[name_len] = 0
out_names[count] = str(name_buf)
count += 1
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
break
w32.win32file.FindClose(handle)
return count
# =============================================================================
# 命令执行
# =============================================================================
def system(cmd: str) -> int:
"""执行命令行命令(通过 C 运行时 system())。
命令输出直接到子进程的终端(继承父进程 stdout/stderr)。
返回命令的退出码(0 表示成功)。"""
return stdlib.system(cmd)
+316
View File
@@ -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)
+57
View File
@@ -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
+265
View File
@@ -0,0 +1,265 @@
import t, c
from stdint import *
# =============================================================================
# POSIX Type Alias
# Note: ssize_t has already been defined as t.CPtrDiffT in stdint.py, so we won’t repeat it here.
# =============================================================================
DIR: t.CTypedef = t.CVoid | t.CPtr # Opaque directory stream handle
mode_t: t.CTypedef = t.CUInt32T # File mode/permission bits
pid_t: t.CTypedef = t.CInt32T # Process ID
off_t: t.CTypedef = t.CInt64T # File offset (Linux x86_64)
dev_t: t.CTypedef = t.CUInt64T # Device number
ino_t: t.CTypedef = t.CUInt64T # inode number
nlink_t: t.CTypedef = t.CUInt64T # Hard link count
uid_t: t.CTypedef = t.CUInt32T # User ID
gid_t: t.CTypedef = t.CUInt32T # Group ID
blksize_t: t.CTypedef = t.CInt64T # File I/O block size
blkcnt_t: t.CTypedef = t.CInt64T # Allocated block count
time_t: t.CTypedef = t.CInt64T # Calendar time seconds
# =============================================================================
# open() Flags
# =============================================================================
O_RDONLY: t.CDefine = 0
O_WRONLY: t.CDefine = 1
O_RDWR: t.CDefine = 2
O_CREAT: t.CDefine = 0o100
O_EXCL: t.CDefine = 0o200
O_TRUNC: t.CDefine = 0o1000
O_APPEND: t.CDefine = 0o2000
O_NONBLOCK: t.CDefine = 0o4000
O_CLOEXEC: t.CDefine = 0o2000000
# =============================================================================
# access() Test Flags
# =============================================================================
F_OK: t.CDefine = 0 # File exists
R_OK: t.CDefine = 4 # Read permission
W_OK: t.CDefine = 2 # Write permission
X_OK: t.CDefine = 1 # Execute permission
# =============================================================================
# stat struct st_mode Mask and Type Bits
# =============================================================================
S_IFMT: t.CDefine = 0o170000 # Type mask bits
S_IFSOCK: t.CDefine = 0o140000 # Socket
S_IFLNK: t.CDefine = 0o120000 # Symbolic link
S_IFREG: t.CDefine = 0o100000 # Regular file
S_IFBLK: t.CDefine = 0o060000 # Block device
S_IFDIR: t.CDefine = 0o040000 # Directory
S_IFCHR: t.CDefine = 0o020000 # Character device
S_IFIFO: t.CDefine = 0o010000 # FIFO/pipe
# Permission Bits
S_ISUID: t.CDefine = 0o4000 # Set-user-ID
S_ISGID: t.CDefine = 0o2000 # Set-group-ID
S_ISVTX: t.CDefine = 0o1000 # Sticky bit
S_IRWXU: t.CDefine = 0o700 # Read/write/execute permission
S_IRUSR: t.CDefine = 0o400 # User read permission
S_IWUSR: t.CDefine = 0o200 # User write permission
S_IXUSR: t.CDefine = 0o100 # User execute permission
S_IRWXG: t.CDefine = 0o070 # Read/write/execute permission
S_IRGRP: t.CDefine = 0o040 # Read permission
S_IWGRP: t.CDefine = 0o020 # Write
S_IXGRP: t.CDefine = 0o010 # Execute
S_IRWXO: t.CDefine = 0o007 # Read/write/execute permission
S_IROTH: t.CDefine = 0o004 # Other read permission
S_IWOTH: t.CDefine = 0o002 # Other write permission
S_IXOTH: t.CDefine = 0o001 # Other execute permission
# =============================================================================
# lseek() whence values
# =============================================================================
SEEK_SET: t.CDefine = 0
SEEK_CUR: t.CDefine = 1
SEEK_END: t.CDefine = 2
# =============================================================================
# Path/name length limits
# =============================================================================
PATH_MAX: t.CDefine = 4096
NAME_MAX: t.CDefine = 255
# =============================================================================
# sysconf() parameters
# =============================================================================
_SC_NPROCESSORS_ONLN: t.CDefine = 84
_SC_PAGESIZE: t.CDefine = 30
_SC_CLK_TCK: t.CDefine = 2
# =============================================================================
# dirent struct d_type values
# =============================================================================
DT_UNKNOWN: t.CDefine = 0
DT_FIFO: t.CDefine = 1
DT_CHR: t.CDefine = 2
DT_DIR: t.CDefine = 4
DT_BLK: t.CDefine = 6
DT_REG: t.CDefine = 8
DT_LNK: t.CDefine = 10
DT_SOCK: t.CDefine = 12
DT_WHT: t.CDefine = 14
# =============================================================================
# waitpid() options
# =============================================================================
WNOHANG: t.CDefine = 1
WUNTRACED: t.CDefine = 2
WCONTINUED: t.CDefine = 8
# =============================================================================
# Struct: Linux x86_64 Layout
# =============================================================================
# struct stat (144 bytes, Linux x86_64 glibc layout)
# Note: st_atim/st_mtim/st_ctim in C are struct timespec { tv_sec; tv_nsec; }
# Here split into _sec/_nsec two LONGLONG fields to maintain binary compatibility
class Stat():
st_dev: dev_t # @ 0
st_ino: ino_t # @ 8
st_nlink: nlink_t # @ 16
st_mode: mode_t # @ 24
st_uid: uid_t # @ 28
st_gid: gid_t # @ 32
__pad0: INT # @ 36
st_rdev: dev_t # @ 40
st_size: off_t # @ 48
st_blksize: blksize_t # @ 56
st_blocks: blkcnt_t # @ 64
st_atim_sec: time_t # @ 72
st_atim_nsec: LONGLONG # @ 80
st_mtim_sec: time_t # @ 88
st_mtim_nsec: LONGLONG # @ 96
st_ctim_sec: time_t # @ 104
st_ctim_nsec: LONGLONG # @ 112
__unused0: LONGLONG # @ 120
__unused1: LONGLONG # @ 128
__unused2: LONGLONG # @ 136
# struct dirent (Linux x86_64, d_name is char[256])
# Note: d_name is actually a fixed-length char[256], TransPyC uses CHARPTR as a placeholder (8 bytes).
# Users usually access it via the read-only pointer returned by readdir, not by directly allocating a Dirent structure.
class Dirent():
d_ino: ino_t # @ 0
d_off: off_t # @ 8
d_reclen: USHORT # @ 16
d_type: BYTE # @ 18
d_name: CHARPTR # @ 19 (actually char[256], this is a placeholder)
# =============================================================================
# File operations (10)
# =============================================================================
def open(path: t.CConst | str, oflag: INT, *args) -> INT | t.State: pass
def close(fd: INT) -> INT | t.State: pass
def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t | t.State: pass
def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t | t.State: pass
def lseek(fd: INT, offset: off_t, whence: INT) -> off_t | t.State: pass
def unlink(path: t.CConst | str) -> INT | t.State: pass
def access(path: t.CConst | str, amode: INT) -> INT | t.State: pass
def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR | t.State: pass
def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT | t.State: pass
def chmod(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass
# =============================================================================
# stat series (2)
# =============================================================================
def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT | t.State: pass
def fstat(fd: INT, buf: Stat | t.CPtr) -> INT | t.State: pass
# =============================================================================
# Directory operations (6)
# =============================================================================
def opendir(name: t.CConst | str) -> DIR | t.CPtr | t.State: pass
def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr | t.State: pass
def closedir(dirp: DIR | t.CPtr) -> INT | t.State: pass
def mkdir(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass
def rmdir(path: t.CConst | str) -> INT | t.State: pass
def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR | t.State: pass
def chdir(path: t.CConst | str) -> INT | t.State: pass
# =============================================================================
# Process operations (8)
# =============================================================================
def fork() -> pid_t | t.State: pass
def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass
def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass
def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t | t.State: pass
def pipe(fds: INT | t.CPtr) -> INT | t.State: pass
def dup2(oldfd: INT, newfd: INT) -> INT | t.State: pass
def _exit(status: INT) -> t.CVoid | t.State: pass
def getpid() -> pid_t | t.State: pass
# =============================================================================
# Environment operations (4)
# =============================================================================
def getenv(name: t.CConst | str) -> CHARPTR | t.State: pass
def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT | t.State: pass
def sysconf(name: INT) -> LONG | t.State: pass
def isatty(fd: INT) -> INT | t.State: pass
# =============================================================================
# Inline macros (C macros, implemented as normal functions, not marked as t.CExtern)
# =============================================================================
# st_mode type determination
def S_ISREG(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFREG
def S_ISDIR(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFDIR
def S_ISLNK(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFLNK
def S_ISCHR(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFCHR
def S_ISBLK(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFBLK
def S_ISFIFO(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFIFO
def S_ISSOCK(mode: mode_t) -> bool:
return (mode & S_IFMT) == S_IFSOCK
# waitpid status parsing
def WIFEXITED(status: INT) -> bool:
return (status & 0x7F) == 0
def WEXITSTATUS(status: INT) -> INT:
return (status >> 8) & 0xFF
def WIFSIGNALED(status: INT) -> bool:
return ((status & 0x7F) != 0) and ((status & 0x7F) != 0x7F)
def WTERMSIG(status: INT) -> INT:
return status & 0x7F
+360
View File
@@ -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))
+46
View File
@@ -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()
+283
View File
@@ -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
+454
View File
@@ -0,0 +1,454 @@
import t, c
from stdint import *
import string
import platmacro
import stdio
import w32.winsock2
# ============================================================
# socket.py — Cross-platform wrapper for Socket
# Python-style OOP API + Compatibility with legacy procedural functions
#
# Example:
# sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM)
# sock.connect("example.com", 80)
# sock.send(data, length)
# n = sock.recv(buf, bufsize)
# sock.close()
#
# Only 3 platform differences (via platmacro.IS_WINDOWS branch):
# 1. WSAStartup() / WSACleanup()
# 2. closesocket() vs close()
# 3. WSAGetLastError() vs errno
# ============================================================
# ============================================================
# Constants
# ============================================================
AF_INET: t.CDefine = 2
AF_INET6: t.CDefine = 10
SOCK_STREAM: t.CDefine = 1
SOCK_DGRAM: t.CDefine = 2
SOCK_RAW: t.CDefine = 3
IPPROTO_TCP: t.CDefine = 6
IPPROTO_UDP: t.CDefine = 17
SOL_SOCKET: t.CDefine = 1
SO_RCVTIMEO: t.CDefine = 20
SO_SNDTIMEO: t.CDefine = 21
SO_REUSEADDR: t.CDefine = 2
INADDR_ANY: t.CDefine = 0
SOCKET_ERROR: t.CDefine = -1
INVALID_SOCKET: t.CDefine = -1
SOCKET_DEFAULT_TIMEOUT: t.CDefine = 0
# ============================================================
# Structures
# ============================================================
class SocketAddr:
"""sockaddr_in — IPv4 address (16 bytes layout)"""
family: u16
port: u16
addr: u32
zero: u64
class HostEnt:
"""struct hostent — DNS resolution result"""
h_name: CHARPTR
h_aliases: CHARPTR
h_addrtype: INT
h_length: INT
h_addr_list: CHARPTR
class timeval:
"""struct timeval — Timeout setting"""
tv_sec: INT
tv_usec: INT
# ============================================================
# External C Functions — Using u64 Handle, Cross-platform Compatibility
# (Windows SOCKET=u64, POSIX fd=int → u64 Zero-Extension Compatible)
# ============================================================
def socket(family: INT, type: INT, protocol: INT) -> u64 | t.CExtern | t.CExport: pass
def connect(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT) -> INT | t.CExtern | t.CExport: pass
def send(fd: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.CExtern | t.CExport: pass
def recv(fd: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.CExtern | t.CExport: pass
def bind(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT) -> INT | t.CExtern | t.CExport: pass
def listen(fd: u64, backlog: INT) -> INT | t.CExtern | t.CExport: pass
def accept(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT | t.CPtr) -> u64 | t.CExtern | t.CExport: pass
def setsockopt(fd: u64, level: INT, optname: INT, optval: t.CVoid | t.CPtr, optlen: INT) -> INT | t.CExtern | t.CExport: pass
def gethostbyname(name: t.CChar | t.CConst | t.CPtr) -> HostEnt | t.CPtr | t.CExtern | t.CExport: pass
def ntohs(netshort: u16) -> u16 | t.CExtern | t.CExport: pass
def htons(hostshort: u16) -> u16 | t.CExtern | t.CExport: pass
def close(fd: u64) -> INT | t.CExtern | t.CExport: pass
# ============================================================
# Internal Auxiliary Functions
# ============================================================
def _CloseFd(fd: INT) -> INT:
"""Platform differences: Windows uses closesocket, POSIX uses close。"""
if platmacro.IS_WINDOWS:
return w32.winsock2.closesocket(u64(fd))
return close(fd)
def _MakeAddr(host: str, port: INT) -> SocketAddr:
"""Build SocketAddr. First try decimal IP, then DNS resolution.
If decimal IP fails, try DNS resolution.
If DNS resolution fails, return INADDR_ANY."""
addr: SocketAddr
string.memset(c.Addr(addr), 0, 16)
addr.family = u16(AF_INET)
addr.port = htons(u16(port))
ip: u32 = 0
if _ParseIPv4(host, c.Addr(ip)):
addr.addr = ip
return addr
# DNS resolution — gethostbyname returns struct hostent*
# h_addr_list is char** → h_addr_list[0] is char* → *(uint32_t*)h_addr_list[0] is IP
if platmacro.IS_WINDOWS:
he_raw: w32.winsock2.WSAHostEnt | t.CPtr = w32.winsock2.gethostbyname(host)
if he_raw is not None:
# he_raw.h_addr_list → he_raw->h_addr_list (char**)
# c.Deref(t.CUInt64T(he_raw.h_addr_list, t.CPtr)) → *(uint64_t*)(he_raw->h_addr_list) → h_addr_list[0]
ip_ptr: u64 = u64(c.Deref(t.CUInt64T(he_raw.h_addr_list, t.CPtr)))
if ip_ptr != 0:
addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr)))
else:
he: HostEnt | t.CPtr = gethostbyname(host)
if he is not None:
ip_ptr: u64 = u64(c.Deref(t.CUInt64T(he.h_addr_list, t.CPtr)))
if ip_ptr != 0:
addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr)))
return addr
def _ParseIPv4(ip_str: str, out_addr: u32 | t.CPtr) -> bool:
"""Parse IPv4 address."""
if ip_str is None or out_addr is None: return False
parts: t.CArray[INT, 4]
part_count: INT = 0
current: INT = 0
started: bool = False
for ch in ip_str:
if ch >= '0' and ch <= '9':
if not started: started = True
current = current * 10 + INT(ch - '0')
if current > 255: return False
elif ch == '.':
if not started: return False
if part_count >= 4: return False
parts[part_count] = current
part_count += 1
current = 0
started = False
else:
break
if started and part_count < 4:
parts[part_count] = current
part_count += 1
if part_count != 4: return False
result: u32 = 0
result = result | (u32(parts[0]) << 24)
result = result | (u32(parts[1]) << 16)
result = result | (u32(parts[2]) << 8)
result = result | u32(parts[3])
c.DerefAs(out_addr, result)
return True
# ============================================================
# Socket class — Python OOP API
# ============================================================
class Socket:
"""Cross-platform Socket class, similar to Python socket.socket.
Usage:
sock = Socket(AF_INET, SOCK_STREAM)
sock.connect("example.com", 80)
sock.send(data, length)
n = sock.recv(buf, bufsize)
sock.close()
"""
fd: INT
family: INT
type: INT
protocol: INT
def __init__(self, family: INT, type: INT, protocol: INT = 0):
"""Create Socket.
Args:
family: Address family (AF_INET)
type: Socket type (SOCK_STREAM)
protocol: Protocol (default 0, auto-match)
"""
self.family = family
self.type = type
self.protocol = protocol
if platmacro.IS_WINDOWS:
self.fd = INT(w32.winsock2.socket(family, type, protocol))
else:
self.fd = socket(family, type, protocol)
def connect(self, host: str, port: INT) -> INT:
"""Connect to remote host.
Args:
host: Hostname or IP
port: Port number
Returns:
0 success, non 0 otherwise
"""
if self.fd == INVALID_SOCKET: return -1
addr: SocketAddr = _MakeAddr(host, port)
result: INT = 0
if platmacro.IS_WINDOWS:
result = w32.winsock2.connect(u64(self.fd), c.Addr(addr), 16)
if result != 0:
err: INT = w32.winsock2.WSAGetLastError()
else:
result = connect(self.fd, c.Addr(addr), 16)
return result
def send(self, data: t.CVoid | t.CPtr, length: INT) -> INT:
"""Send data.
Returns:
Sent bytes, SOCKET_ERROR on error
"""
if self.fd == INVALID_SOCKET: return SOCKET_ERROR
if data is None or length <= 0: return 0
if platmacro.IS_WINDOWS:
return w32.winsock2.send(u64(self.fd), data, length, 0)
return send(self.fd, data, length, 0)
def recv(self, buf: t.CVoid | t.CPtr, bufsize: INT) -> INT:
"""Receive data.
Returns:
Received bytes, SOCKET_ERROR on error, 0 on connection close
"""
if self.fd == INVALID_SOCKET: return SOCKET_ERROR
if buf is None or bufsize <= 0: return 0
if platmacro.IS_WINDOWS:
return w32.winsock2.recv(u64(self.fd), buf, bufsize, 0)
return recv(self.fd, buf, bufsize, 0)
def sendall(self, data: t.CVoid | t.CPtr, length: INT) -> INT:
"""Send all data.
Returns:
0 success, SOCKET_ERROR on error
"""
if self.fd == INVALID_SOCKET: return SOCKET_ERROR
if data is None or length <= 0: return 0
total: INT = 0
while total < length:
n: INT = self.send(t.CVoid(t.CUInt64T(data) + total, t.CPtr), length - total)
if n <= 0: return SOCKET_ERROR
total += n
return 0
def close(self) -> INT:
"""Close Socket."""
if self.fd == INVALID_SOCKET: return 0
result: INT = _CloseFd(self.fd)
self.fd = INVALID_SOCKET
return result
def bind(self, host: str, port: INT) -> INT:
"""Bind address and port (server-side).
Returns:
0 success, non 0 otherwise
"""
if self.fd == INVALID_SOCKET: return -1
addr: SocketAddr = _MakeAddr(host, port)
if platmacro.IS_WINDOWS:
return w32.winsock2.bind(u64(self.fd), c.Addr(addr), 16)
return bind(self.fd, c.Addr(addr), 16)
def listen(self, backlog: INT) -> INT:
"""Start for incoming connections (server-side).
Returns:
0 success, non 0 otherwise
"""
if self.fd == INVALID_SOCKET: return -1
if platmacro.IS_WINDOWS:
return w32.winsock2.listen(u64(self.fd), backlog)
return listen(self.fd, backlog)
def accept(self, out_client: 'Socket' | t.CPtr) -> INT:
"""Accept a client connection.
Args:
out_client: Output parameter, receives client Socket
Returns:
Client fd (>= 0 on success), SOCKET_ERROR on error
"""
if self.fd == INVALID_SOCKET: return SOCKET_ERROR
if out_client is None: return SOCKET_ERROR
addr: SocketAddr
string.memset(c.Addr(addr), 0, 16)
addrlen: INT = 16
if platmacro.IS_WINDOWS:
client_fd: u64 = w32.winsock2.accept(u64(self.fd), c.Addr(addr), c.Addr(addrlen))
if client_fd == w32.winsock2.INVALID_SOCKET:
return SOCKET_ERROR
out_client.fd = INT(client_fd)
out_client.family = self.family
out_client.type = self.type
out_client.protocol = self.protocol
return INT(client_fd)
client_fd: INT = accept(self.fd, c.Addr(addr), c.Addr(addrlen))
if client_fd == SOCKET_ERROR:
return SOCKET_ERROR
out_client.fd = client_fd
out_client.family = self.family
out_client.type = self.type
out_client.protocol = self.protocol
return client_fd
def settimeout(self, timeout_ms: INT) -> INT:
"""Set timeout for receive and send operations (milliseconds).
Returns:
0 success, non 0 otherwise
"""
if self.fd == INVALID_SOCKET: return -1
tv: timeval
tv.tv_sec = timeout_ms / 1000
tv.tv_usec = (timeout_ms % 1000) * 1000
optlen: INT = 8
if platmacro.IS_WINDOWS:
r1: INT = w32.winsock2.setsockopt(u64(self.fd), SOL_SOCKET, SO_RCVTIMEO, c.Addr(tv), optlen)
r2: INT = w32.winsock2.setsockopt(u64(self.fd), SOL_SOCKET, SO_SNDTIMEO, c.Addr(tv), optlen)
else:
r1 = setsockopt(self.fd, SOL_SOCKET, SO_RCVTIMEO, c.Addr(tv), optlen)
r2 = setsockopt(self.fd, SOL_SOCKET, SO_SNDTIMEO, c.Addr(tv), optlen)
if r1 != 0: return r1
return r2
def fileno(self) -> INT:
"""Return underlying file descriptor / SOCKET handle."""
return self.fd
# ============================================================
# Platform initialization
# ============================================================
def SocketInit() -> INT:
"""Initialize the Socket library. On Windows, call WSAStartup; on POSIX, do nothing."""
if platmacro.IS_WINDOWS:
wsa_data: t.CArray[BYTE, 400]
string.memset(c.Addr(wsa_data), 0, 400)
return w32.winsock2.WSAStartup(w32.winsock2.WINSOCK_VERSION, c.Addr(wsa_data))
return 0
def SocketCleanup() -> INT:
"""Cleanup the Socket library."""
if platmacro.IS_WINDOWS:
return w32.winsock2.WSACleanup()
return 0
# ============================================================
# Compatibility with old procedural API (delegates to Socket methods)
# ============================================================
def SocketCreate(family: INT, type: INT, protocol: INT, out_sock: Socket | t.CPtr) -> INT:
"""Create a Socket handle (compatible with old API). It is recommended to use Socket(...) constructor."""
if out_sock is None: return -1
out_sock.family = family
out_sock.type = type
out_sock.protocol = protocol
if platmacro.IS_WINDOWS:
fd: u64 = w32.winsock2.socket(family, type, protocol)
out_sock.fd = INT(fd)
if fd == w32.winsock2.INVALID_SOCKET: return -1
else:
fd: INT = socket(family, type, protocol)
out_sock.fd = fd
if fd == INVALID_SOCKET: return -1
return 0
# But maybe using OOP would be better, though that can be wrapped up later.
def SocketConnect(sock: Socket | t.CPtr, host: str, port: INT) -> INT:
return sock.connect(host, port)
def SocketSend(sock: Socket | t.CPtr, data: t.CVoid | t.CPtr, length: INT) -> INT:
return sock.send(data, length)
def SocketRecv(sock: Socket | t.CPtr, buf: t.CVoid | t.CPtr, bufsize: INT) -> INT:
return sock.recv(buf, bufsize)
def SocketClose(sock: Socket | t.CPtr) -> INT:
return sock.close()
def SocketBind(sock: Socket | t.CPtr, host: str, port: INT) -> INT:
return sock.bind(host, port)
def SocketListen(sock: Socket | t.CPtr, backlog: INT) -> INT:
return sock.listen(backlog)
def SocketAccept(sock: Socket | t.CPtr, out_client: Socket | t.CPtr) -> INT:
return sock.accept(out_client)
def SocketSetTimeout(sock: Socket | t.CPtr, timeout_ms: INT) -> INT:
return sock.settimeout(timeout_ms)
def SocketIsValid(sock: Socket | t.CPtr) -> bool:
"""Check if a Socket is valid."""
if sock is None: return False
return sock.fd != INVALID_SOCKET
+16
View File
@@ -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)
+9
View File
@@ -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
+133
View File
@@ -0,0 +1,133 @@
import t
# =============================================================================
# 大写别名(Win32/TransPyC 风格)
# 注意:INTPTR/UINTPTR 在此模块中是 int*/unsigned int* 指针类型(历史命名)。
# 它们与 C 标准的 intptr_t/uintptr_t 整数类型不同,后者见下方小写 _t 区域。
# =============================================================================
INT: t.CTypedef = t.CInt
INTPTR: t.CTypedef = t.CInt | t.CPtr
BOOL: t.CTypedef = t.CInt
UINT: t.CTypedef = t.CUnsignedInt
UINTPTR: t.CTypedef = UINT | t.CPtr
BYTE: t.CTypedef = t.CUnsignedChar
BYTEPTR: t.CTypedef = BYTE | t.CPtr
WORD: t.CTypedef = t.CUInt16T
DWORD: t.CTypedef = t.CUInt32T
QWORD: t.CTypedef = t.CUInt64T
TCHAR: t.CTypedef = t.CChar
CHARLIST: t.CTypedef = str | t.CPtr
VOID: t.CTypedef = t.CVoid
SHORT: t.CTypedef = t.CShort
SHORTPTR: t.CTypedef = t.CShort | t.CPtr
USHORT: t.CTypedef = t.CUnsignedShort
USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr
LONGLONG: t.CTypedef = t.CLongLong
ULONGLONG: t.CTypedef = t.CUnsignedLongLong
LONG: t.CTypedef = t.CLong
ULONG: t.CTypedef = t.CUnsignedLong
WCHAR: t.CTypedef = WORD
WCHARPTR: t.CTypedef = WORD | t.CPtr
CHARPTR: t.CTypedef = t.CChar | t.CPtr
FSIZE_t: t.CTypedef = DWORD
LBA_t: t.CTypedef = DWORD
VOIDPTR: t.CTypedef = t.CVoid | t.CPtr
FLOAT: t.CTypedef = t.CFloat
DOUBLE: t.CTypedef = t.CDouble
FLOAT8: t.CTypedef = t.CFloat8T
FLOAT16: t.CTypedef = t.CFloat16T
FLOAT32: t.CTypedef = t.CFloat32T
FLOAT64: t.CTypedef = t.CFloat64T
FLOAT128: t.CTypedef = t.CFloat128T
# =============================================================================
# 定长整数大写别名
# =============================================================================
INT8: t.CTypedef = t.CInt8T
INT16: t.CTypedef = t.CInt16T
INT32: t.CTypedef = t.CInt32T
INT64: t.CTypedef = t.CInt64T
UINT8: t.CTypedef = t.CUInt8T
UINT16: t.CTypedef = t.CUInt16T
UINT32: t.CTypedef = t.CUInt32T
UINT64: t.CTypedef = t.CUInt64T
INT8PTR: t.CTypedef = t.CInt8T | t.CPtr
INT16PTR: t.CTypedef = t.CInt16T | t.CPtr
INT32PTR: t.CTypedef = t.CInt32T | t.CPtr
INT64PTR: t.CTypedef = t.CInt64T | t.CPtr
UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr
UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr
UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr
UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr
CHAR8: t.CTypedef = t.CChar8T
CHAR16: t.CTypedef = t.CChar16T
CHAR32: t.CTypedef = t.CChar32T
CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr
CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr
CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr
i8: t.CTypedef = t.CInt8T
i16: t.CTypedef = t.CInt16T
i32: t.CTypedef = t.CInt32T
i64: t.CTypedef = t.CInt64T
u8: t.CTypedef = t.CUInt8T
u16: t.CTypedef = t.CUInt16T
u32: t.CTypedef = t.CUInt32T
u64: t.CTypedef = t.CUInt64T
SIZE_T: t.CTypedef = t.CSizeT
SSIZE_T: t.CTypedef = t.CPtrDiffT
PTRDIFF_T: t.CTypedef = t.CPtrDiffT
# =============================================================================
# C 标准库 <stdint.h> 类型名(小写 _t 后缀)
# 这些是 C 语言标准类型名,从 _CNAME_ALIAS 挪到此处作为 typedef 提供。
# 用户 `from stdint import *` 后即可直接使用 int8_t / size_t 等。
# =============================================================================
int8_t: t.CTypedef = t.CInt8T
int16_t: t.CTypedef = t.CInt16T
int32_t: t.CTypedef = t.CInt32T
int64_t: t.CTypedef = t.CInt64T
uint8_t: t.CTypedef = t.CUInt8T
uint16_t: t.CTypedef = t.CUInt16T
uint32_t: t.CTypedef = t.CUInt32T
uint64_t: t.CTypedef = t.CUInt64T
size_t: t.CTypedef = t.CSizeT
ssize_t: t.CTypedef = t.CPtrDiffT
ptrdiff_t: t.CTypedef = t.CPtrDiffT
# intptr_t/uintptr_t 是足以容纳指针的整数类型(不是指针!)
# 与上方的 INTPTR/UINTPTR(int 指针)语义不同。
intptr_t: t.CTypedef = t.CIntPtrT
uintptr_t: t.CTypedef = t.CUIntPtrT
# 宽字符 / 字符类型
wchar_t: t.CTypedef = t.CWCharT
char8_t: t.CTypedef = t.CChar8T
char16_t: t.CTypedef = t.CChar16T
char32_t: t.CTypedef = t.CChar32T
# 浮点特化类型
float8_t: t.CTypedef = t.CFloat8T
float16_t: t.CTypedef = t.CFloat16T
float32_t: t.CTypedef = t.CFloat32T
float64_t: t.CTypedef = t.CFloat64T
float128_t: t.CTypedef = t.CFloat128T
_Bool: t.CTypedef = t.CBool
+11
View File
@@ -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
+10
View File
@@ -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
+417
View File
@@ -0,0 +1,417 @@
from stdint import *
import t, c
import stdio
# String copy function
def strcpy(dest: str, src: str) -> str:
if dest == None or src == None: return None
original_dest: str = dest
for s in src:
dest[0] = s
dest += 1
dest[0] = 0
return original_dest
# String concatenate function
def strcat(dest: str, src: str) -> str:
if dest == None or src == None: return dest
original_dest: str = dest
# Find end of dest
while dest[0] != '\0':
dest += 1
# Copy src
for s in src:
dest[0] = s
dest += 1
dest[0] = 0
return original_dest
# String copy function with limited length
def strncpy(dest: str, src: str, n: t.CSizeT) -> str:
if dest == None or src == None or n == 0: return dest
original_dest: str = dest
i: t.CSizeT = 0
for s in src:
if i >= n: break
dest[0] = s
dest += 1
i += 1
# Fill remaining space with '\0'
while i < n:
dest[0] = 0
dest += 1
i += 1
return original_dest
# String concatenate function with limited length
def strncat(dest: str, src: str, n: t.CSizeT) -> str:
if dest == None or src == None or n == 0: return dest
original_dest: str = dest
# Find end of dest
while dest[0] != '\0':
dest += 1
# Copy up to n chars from src
i: t.CSizeT = 0
for s in src:
if i >= n: break
dest[0] = s
dest += 1
i += 1
dest[0] = 0
return original_dest
# String length function
def strlen(src: str) -> t.CSizeT | t.CExport:
length: t.CSizeT = 0
for _ in src:
length += 1
return length
# String comparison function
def strcmp(str1: str, str2: str) -> t.CInt:
while str1[0] != '\0' and str2[0] != '\0':
if str1[0] != str2[0]:
return str1[0] - str2[0]
str1 += 1
str2 += 1
return str1[0] - str2[0]
def samestr(str1: str, str2: str) -> bool:
return strcmp(str1, str2) == 0
# String compare function with limited length
def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt:
i: t.CSizeT = 0
while str1[0] != '\0' and str2[0] != '\0' and i < n:
if str1[0] != str2[0]:
return str1[0] - str2[0]
str1 += 1
str2 += 1
i += 1
if i < n:
return str1[0] - str2[0]
return 0
# Memory compare function
def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt:
p1: BYTEPTR = BYTEPTR(ptr1)
p2: BYTEPTR = BYTEPTR(ptr2)
i: t.CSizeT = 0
while i < n:
if p1[i] != p2[i]:
return t.CInt(p1[i]) - t.CInt(p2[i])
i += 1
return 0
# String find function
def strchr(s: str, cr: t.CInt) -> str:
while s[0] != '\0':
if s[0] == t.CChar(cr):
return str(s)
s += 1
if cr == '\0':
return str(s)
return None
# String reverse find function (find last occurrence of character)
def strrchr(s: str, cr: t.CInt) -> str:
last: str = None
while s[0] != '\0':
if s[0] == t.CChar(cr):
last = s
s += 1
if cr == '\0': return s
return last
# Substring search function (find first occurrence of needle in s, return pointer to that position, or None if not found)
def strstr(s: str, needle: str) -> str:
if needle[0] == 0:
return s
needle_len: t.CSizeT = strlen(needle)
if needle_len == 0:
return s
i: t.CSizeT = 0
s_len: t.CSizeT = strlen(s)
while i + needle_len <= s_len:
if strncmp(s + i, needle, needle_len) == 0:
return s + i
i += 1
return None
# String skip function
def strspn(s: str, skip: str = " ") -> int:
si: int = 0
while s[si] != 0:
found: int = 0
sj: int = 0
while skip[sj] != 0:
if s[si] == skip[sj]:
found = 1
break
sj += 1
if found == 0:
break
si += 1
return si
# Memory set function
def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
# Original implementation:
# p: BYTEPTR = BYTEPTR(ptr)
# i: t.CSizeT
# for i in range(num):
# p[i] = t.CUnsignedChar(value)
if num == 0: return ptr
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
rep stosb""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
return ptr
def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr:
# Original implementation:
# p: UINT32PTR = UINT32PTR(ptr)
# i: t.CSizeT
# for i in range(count):
# p[i] = value
if count == 0: return ptr
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(count, t.ASM_DESCR.REG_ANY)}
rep stosd""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
return ptr
# Memory copy function
def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
# Original implementation:
# d: BYTEPTR = BYTEPTR(dest)
# s: BYTEPTR = BYTEPTR(src)
# i: t.CSizeT
# for i in range(num):
# d[i] = s[i]
if num == 0: return dest
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
rep movsb""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
return dest
# 内存移动函数
def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr:
# 原始实现:
# d: BYTEPTR = BYTEPTR(dest)
# s: BYTEPTR = BYTEPTR(src)
# i: t.CSizeT
# if d < s:
# for i in range(num):
# d[i] = s[i]
# elif d > s:
# for i in range(num, 0, -1):
# d[i - 1] = s[i - 1]
if num == 0: return dest
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
cmp rdi, rsi
jb 2f
std
add rdi, rcx
dec rdi
add rsi, rcx
dec rsi
rep movsb
cld
jmp 3f
2:
rep movsb
3:""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
return dest
def atoi(src: str) -> t.CInt:
num: t.CInt = 0
sign: t.CInt = 1
s: str = src
if s == None: return 0
# 跳过空白
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
s += 1
# 符号
if s[0] == '-':
sign = -1
s += 1
elif s[0] == '+':
s += 1
for ch in s:
if ch < '0' or ch > '9': break
digit: t.CInt = ch - '0'
num = num * 10 + digit
return num * sign
def atoll(src: str) -> t.CInt64T:
num: t.CInt64T = 0
sign: t.CInt64T = 1
s: str = src
if s == None: return 0
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
s += 1
if s[0] == '-':
sign = -1
s += 1
elif s[0] == '+':
s += 1
# 十六进制前缀 0x / 0X
is_hex: t.CInt = 0
if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'):
is_hex = 1
s += 2
if is_hex:
for ch in s:
d: t.CInt = 0
if ch >= '0' and ch <= '9':
d = ch - '0'
elif ch >= 'a' and ch <= 'f':
d = ch - 'a' + 10
elif ch >= 'A' and ch <= 'F':
d = ch - 'A' + 10
else:
break
digit: t.CInt64T = t.CInt64T(d)
num = num * 16 + digit
else:
for ch in s:
if ch < '0' or ch > '9': break
d: t.CInt = ch - '0'
digit: t.CInt64T = t.CInt64T(d)
num = num * 10 + digit
return num * sign
def atof(src: str) -> t.CDouble:
s: str = src
if s == None: return 0.0
# 跳过空白
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
s += 1
# 符号
sign: t.CDouble = 1.0
if s[0] == '-':
sign = -1.0
s += 1
elif s[0] == '+':
s += 1
# 整数部分
int_part: t.CDouble = 0.0
for ch in s:
if ch < '0' or ch > '9': break
d1: t.CInt = ch - '0'
int_part = int_part * 10.0 + t.CDouble(d1)
s += 1
# 小数部分
frac_part: t.CDouble = 0.0
frac_div: t.CDouble = 1.0
if s[0] == '.':
s += 1
for ch in s:
if ch < '0' or ch > '9': break
d2: t.CInt = ch - '0'
frac_div = frac_div * 10.0
frac_part = frac_part * 10.0 + t.CDouble(d2)
s += 1
# 指数部分
exp: t.CInt = 0
exp_sign: t.CInt = 1
if s[0] == 'e' or s[0] == 'E':
s += 1
if s[0] == '-':
exp_sign = -1
s += 1
elif s[0] == '+':
s += 1
for ch in s:
if ch < '0' or ch > '9': break
d3: t.CInt = ch - '0'
exp = exp * 10 + d3
s += 1
exp = exp * exp_sign
result: t.CDouble = sign * (int_part + frac_part / frac_div)
# 应用指数
if exp > 0:
while exp > 0:
result = result * 10.0
exp -= 1
elif exp < 0:
while exp < 0:
result = result / 10.0
exp += 1
return result
def atof_out(src: str, out: t.CDouble | t.CPtr) -> t.CInt:
"""atof 结果写入 out[0](输出参数方式,避免跨模块 double 返回值传递 bug)
返回值仅表示成功与否(1=成功,0=失败),结果值通过 out 指针传递,
不依赖 double 返回值的跨模块传递。
"""
if out is None:
return 0
v: t.CDouble = atof(src)
out[0] = v
return 1
def split(s: str, delim: str, result: t.CArray[str]) -> int:
count: int = 0
start: str = s
if not s or not delim or not result:
return 0
d: t.CChar = delim[0] # 单分隔符
while start[0]:
# 跳过分隔符
while start[0] == d: start += 1
if not start[0]: break
# 记录token起始
result[count] = start
count += 1
# 找到下一个分隔符,截断
while start[0] and start[0] != d: start += 1
if start[0]:
start[0] = '\0'
start += 1
result[count] = None # 结尾标记
return count
ascii_lowercase: str = "abcdefghijklmnopqrstuvwxyz"
ascii_uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ascii_letters: str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
digits: str = "0123456789"
hexdigits: str = "0123456789abcdefABCDEF"
octdigits: str = "01234567"
punctuation: str = "!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~"
whitespace: str = " \t\n\r\f\v"
printable: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\f\v"
+196
View File
@@ -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)
+200
View File
@@ -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]
+71
View File
@@ -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
+39
View File
@@ -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")
+65
View File
@@ -0,0 +1,65 @@
import t, c
from stdint import *
import memhub
class Vector[T]():
data: t.CVoid | t.CPtr
length: t.CSizeT
capacity: t.CSizeT
elem_size: t.CSizeT
pool: memhub.MemManager | t.CPtr
def __init__(self, pool: memhub.MemManager | t.CPtr, capacity: t.CSizeT, _hint: T):
self.elem_size = T.__sizeof__()
self.capacity = capacity
self.length = 0
self.pool = pool
self.data = pool.alloc(capacity * self.elem_size)
def push(self, value: T):
if self.data == None: return
if self.length >= self.capacity:
self._grow()
if self.length >= self.capacity: return
offset: t.CUInt64T = t.CUInt64T(self.data) + self.length * self.elem_size
dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr)
c.DerefAs(dst, value)
self.length += 1
def _grow(self):
if self.pool == None: return
new_capacity: t.CSizeT = self.capacity * 2
if new_capacity == 0: new_capacity = 4
new_size: t.CSizeT = new_capacity * self.elem_size
new_data: t.CVoid | t.CPtr = self.pool.realloc(self.data, new_size)
if new_data == None: return
self.data = new_data
self.capacity = new_capacity
def get(self, index: t.CSizeT) -> T:
if self.data == None: return T(0)
offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size
typed_ptr = T(offset, t.CPtr)
return c.Deref(typed_ptr)
def set(self, index: t.CSizeT, value: T):
if index >= self.length: return
if self.data == None: return
offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size
dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr)
c.DerefAs(dst, value)
def len(self) -> t.CSizeT:
return self.length
def clear(self):
self.length = 0
def free(self):
if self.data != None:
if self.pool != None:
self.pool.free(self.data)
self.data = None
self.length = 0
self.capacity = 0
+59
View File
@@ -0,0 +1,59 @@
import t, c
from stdint import *
class Buf:
data: t.CChar | t.CPtr
length: t.CSizeT
capacity: t.CSizeT
owned: bool
def __init__(self, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT = 0, owned: bool = False):
self.data = data
self.capacity = capacity
self.length = length
self.owned = owned
def clear(self):
self.length = 0
if self.data != None and self.capacity > 0:
self.data[0] = 0
def write(self, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT:
if self.data == None: return 0
if src == None: return 0
if count == 0: return 0
avail: t.CSizeT = self.capacity - self.length
if avail <= 0: return 0
n: t.CSizeT = count if count < avail else avail
i: t.CSizeT = 0
while i < n:
self.data[self.length + i] = src[i]
i += 1
self.length += n
# 恰好写满(n==avail)时 data[capacity] 越界 1 字节,加保护
if self.length < self.capacity:
self.data[self.length] = 0
return n
def cstr(self) -> t.CChar | t.CPtr:
return self.data
def reset(self):
self.length = 0
if self.data != None and self.capacity > 0:
self.data[0] = 0
def __enter__(self) -> 'Buf' | t.CPtr:
return self
def __exit__(self):
self.reset()
def free(self):
if self.owned and self.data != None:
self.data[0] = 0
self.owned = False
self.data = None
self.length = 0
self.capacity = 0
+1375
View File
File diff suppressed because it is too large. Load diff
+544
View File
@@ -0,0 +1,544 @@
import t, c
U_M_PI: t.CDefine = 3.14159265358979323846
U_M_E: t.CDefine = 2.71828182845904523536
U_M_PI_2: t.CDefine = 1.57079632679489661923
U_M_PI_4: t.CDefine = 0.78539816339744830962
U_M_1_PI: t.CDefine = 0.31830988618379067154
U_M_2_PI: t.CDefine = 0.63661977236758134308
U_M_LN2: t.CDefine = 0.69314718055994530942
U_M_LN10: t.CDefine = 2.30258509299404568402
U_M_2_SQRT_PI: t.CDefine = 1.77245385090551602730
def radians(degrees: t.CDouble) -> t.CDouble:
return degrees * (U_M_PI / t.CDouble(180.0))
def degrees(radians: t.CDouble) -> t.CDouble:
return radians * (t.CDouble(180.0) / U_M_PI)
def sin(x: t.CDouble) -> t.CDouble:
while x > U_M_PI:
x -= t.CDouble(2.0) * U_M_PI
while x < -U_M_PI:
x += t.CDouble(2.0) * U_M_PI
x2: t.CDouble = x * x
result: t.CDouble = x
term: t.CDouble = x
term = term * x2 / t.CDouble(6.0)
result = result - term
term = term * x2 / t.CDouble(20.0)
result = result + term
term = term * x2 / t.CDouble(42.0)
result = result - term
term = term * x2 / t.CDouble(72.0)
result = result + term
term = term * x2 / t.CDouble(110.0)
result = result - term
term = term * x2 / t.CDouble(156.0)
result = result + term
term = term * x2 / t.CDouble(210.0)
result = result - term
term = term * x2 / t.CDouble(272.0)
result = result + term
return result
def cos(x: t.CDouble) -> t.CDouble:
while x > U_M_PI:
x -= t.CDouble(2.0) * U_M_PI
while x < -U_M_PI:
x += t.CDouble(2.0) * U_M_PI
x2: t.CDouble = x * x
result: t.CDouble = t.CDouble(1.0)
term: t.CDouble = t.CDouble(1.0)
term = term * x2 / t.CDouble(2.0)
result = result - term
term = term * x2 / t.CDouble(12.0)
result = result + term
term = term * x2 / t.CDouble(30.0)
result = result - term
term = term * x2 / t.CDouble(56.0)
result = result + term
term = term * x2 / t.CDouble(90.0)
result = result - term
term = term * x2 / t.CDouble(132.0)
result = result + term
term = term * x2 / t.CDouble(182.0)
result = result - term
term = term * x2 / t.CDouble(240.0)
result = result + term
return result
def tan(x: t.CDouble) -> t.CDouble:
return sin(x) / cos(x)
def asin(x: t.CDouble) -> t.CDouble:
if x > t.CDouble(1.0):
x = t.CDouble(1.0)
if x < t.CDouble(-1.0):
x = t.CDouble(-1.0)
x2: t.CDouble = x * x
result: t.CDouble = x
result += x * x2 / t.CDouble(6.0)
result += t.CDouble(3.0) * x * x2 * x2 / t.CDouble(40.0)
result += t.CDouble(5.0) * x * x2 * x2 * x2 / t.CDouble(112.0)
result += t.CDouble(35.0) * x * x2 * x2 * x2 * x2 / t.CDouble(1152.0)
result += t.CDouble(63.0) * x * x2 * x2 * x2 * x2 * x2 / t.CDouble(2816.0)
return result
def acos(x: t.CDouble) -> t.CDouble:
return U_M_PI / t.CDouble(2.0) - asin(x)
def _atan_core(x: t.CDouble) -> t.CDouble:
x2: t.CDouble = x * x
result: t.CDouble = x
term: t.CDouble = x
term = term * x2 / t.CDouble(3.0)
result = result - term
term = term * x2 / t.CDouble(5.0)
result = result + term
term = term * x2 / t.CDouble(7.0)
result = result - term
term = term * x2 / t.CDouble(9.0)
result = result + term
term = term * x2 / t.CDouble(11.0)
result = result - term
term = term * x2 / t.CDouble(13.0)
result = result + term
term = term * x2 / t.CDouble(15.0)
result = result - term
term = term * x2 / t.CDouble(17.0)
result = result + term
term = term * x2 / t.CDouble(19.0)
result = result - term
term = term * x2 / t.CDouble(21.0)
result = result + term
return result
def atan(x: t.CDouble) -> t.CDouble:
ax: t.CDouble = x
if ax < t.CDouble(0.0):
ax = -ax
if ax > t.CDouble(1.0):
return t.CDouble(0.0) - _atan_core(t.CDouble(1.0) / ax) + U_M_PI_2 if x > t.CDouble(0.0) else _atan_core(t.CDouble(1.0) / ax) - U_M_PI_2
return _atan_core(x) if x >= t.CDouble(0.0) else t.CDouble(0.0) - _atan_core(ax)
def atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble:
if x > t.CDouble(0.0):
return atan(y / x)
elif x < t.CDouble(0.0):
if y >= t.CDouble(0.0):
return atan(y / x) + U_M_PI
else:
return atan(y / x) - U_M_PI
else:
if y > t.CDouble(0.0):
return U_M_PI_2
elif y < t.CDouble(0.0):
return t.CDouble(0.0) - U_M_PI_2
else:
return t.CDouble(0.0)
def sinh(x: t.CDouble) -> t.CDouble:
ex: t.CDouble = exp(x)
e_negx: t.CDouble = exp(-x)
return (ex - e_negx) / t.CDouble(2.0)
def cosh(x: t.CDouble) -> t.CDouble:
ex: t.CDouble = exp(x)
e_negx: t.CDouble = exp(-x)
return (ex + e_negx) / t.CDouble(2.0)
def tanh(x: t.CDouble) -> t.CDouble:
ex: t.CDouble = exp(x)
e_negx: t.CDouble = exp(-x)
return (ex - e_negx) / (ex + e_negx)
def exp(x: t.CDouble) -> t.CDouble:
if x > t.CDouble(709.0):
return t.CDouble(1.7976931348623157e308)
if x < t.CDouble(-709.0):
return t.CDouble(0.0)
result: t.CDouble = t.CDouble(1.0)
term: t.CDouble = t.CDouble(1.0)
term = term * x / t.CDouble(1.0)
result = result + term
term = term * x / t.CDouble(2.0)
result = result + term
term = term * x / t.CDouble(3.0)
result = result + term
term = term * x / t.CDouble(4.0)
result = result + term
term = term * x / t.CDouble(5.0)
result = result + term
term = term * x / t.CDouble(6.0)
result = result + term
term = term * x / t.CDouble(7.0)
result = result + term
term = term * x / t.CDouble(8.0)
result = result + term
term = term * x / t.CDouble(9.0)
result = result + term
term = term * x / t.CDouble(10.0)
result = result + term
term = term * x / t.CDouble(11.0)
result = result + term
term = term * x / t.CDouble(12.0)
result = result + term
term = term * x / t.CDouble(13.0)
result = result + term
term = term * x / t.CDouble(14.0)
result = result + term
term = term * x / t.CDouble(15.0)
result = result + term
term = term * x / t.CDouble(16.0)
result = result + term
term = term * x / t.CDouble(17.0)
result = result + term
term = term * x / t.CDouble(18.0)
result = result + term
return result
def log(x: t.CDouble) -> t.CDouble:
if x <= t.CDouble(0.0):
return t.CDouble(-1e308)
exponent: t.CInt = 0
while x >= t.CDouble(2.0):
x /= t.CDouble(2.0)
exponent += 1
while x < t.CDouble(1.0):
x *= t.CDouble(2.0)
exponent -= 1
y: t.CDouble = (x - t.CDouble(1.0)) / (x + t.CDouble(1.0))
y2: t.CDouble = y * y
result: t.CDouble = t.CDouble(2.0) * y
term: t.CDouble = t.CDouble(2.0) * y
term = term * y2
result = result + term / t.CDouble(3.0)
term = term * y2
result = result + term / t.CDouble(5.0)
term = term * y2
result = result + term / t.CDouble(7.0)
term = term * y2
result = result + term / t.CDouble(9.0)
term = term * y2
result = result + term / t.CDouble(11.0)
term = term * y2
result = result + term / t.CDouble(13.0)
term = term * y2
result = result + term / t.CDouble(15.0)
term = term * y2
result = result + term / t.CDouble(17.0)
term = term * y2
result = result + term / t.CDouble(19.0)
term = term * y2
result = result + term / t.CDouble(21.0)
result += t.CDouble(exponent) * U_M_LN2
return result
def sqrt(x: t.CDouble) -> t.CDouble:
if x < t.CDouble(0.0):
return t.CDouble(0.0)
if x == t.CDouble(0.0):
return t.CDouble(0.0)
guess: t.CDouble = x / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
guess = (guess + x / guess) / t.CDouble(2.0)
return guess
def abs(x: t.CInt) -> t.CInt:
return x if x >= 0 else -x
def fabs(x: t.CDouble) -> t.CDouble:
return x if x >= t.CDouble(0.0) else -x
def labs(x: t.CLong) -> t.CLong:
return x if x >= 0 else -x
def factorial(n: t.CInt) -> t.CDouble:
if n < 0: return t.CDouble(0.0)
if n == 0 or n == 1: return t.CDouble(1.0)
result: t.CDouble = t.CDouble(1.0)
for i in range(2, n + 1):
result *= i
return result
def combination(n: t.CInt, k: t.CInt) -> t.CDouble:
if k < 0 or k > n: return t.CDouble(0.0)
if k == 0 or k == n: return t.CDouble(1.0)
k = k if k < n - k else n - k
result: t.CDouble = t.CDouble(1.0)
for i in range(1, k + 1):
result = result * (n - k + i) / i
return result
def permutation(n: t.CInt, k: t.CInt) -> t.CDouble:
if k < 0 or k > n: return t.CDouble(0.0)
result: t.CDouble = t.CDouble(1.0)
for i in range(0, k):
result *= (n - i)
return result
def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble:
if x == t.CDouble(0.0):
if y > t.CDouble(0.0):
return t.CDouble(0.0)
return t.CDouble(1.0)
if x < t.CDouble(0.0):
iy: t.CDouble = y * log(-x)
return exp(iy)
return exp(y * log(x))
def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble:
return pow(x, y)
def cbrt(x: t.CDouble) -> t.CDouble:
return pow(x, t.CDouble(1.0) / t.CDouble(3.0))
def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble:
return sqrt(x * x + y * y)
def floor(x: t.CDouble) -> t.CDouble:
if x >= t.CDouble(0.0):
return t.CDouble(t.CInt(x))
i: t.CInt = t.CInt(x)
if x < t.CDouble(i):
return t.CDouble(i - 1)
else:
return t.CDouble(i)
def ceil(x: t.CDouble) -> t.CDouble:
if x < t.CDouble(0.0):
return t.CDouble(t.CInt(x))
i: t.CInt = t.CInt(x)
if x > t.CDouble(i):
return t.CDouble(i + 1)
else:
return t.CDouble(i)
def round(x: t.CDouble) -> t.CDouble:
return floor(x + t.CDouble(0.5))
def trunc(x: t.CDouble) -> t.CDouble:
if x >= t.CDouble(0.0):
return floor(x)
else:
return ceil(x)
def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble:
if y == t.CDouble(0.0):
return t.CDouble(0.0)
result: t.CDouble = x - y * floor(x / y)
if result < t.CDouble(0.0):
result += y
return result
def fmodf(x: float, y: float) -> float:
if y == float(0.0):
return float(0.0)
result: float = x - y * floorf(x / y)
if result < float(0.0):
result += y
return result
def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble:
int_part: t.CDouble = floor(x)
# c.Set(a, b) = a = b:a 为 c.Deref(iptr) 左值表达式 → *iptr = int_part
# TPV 的 c.Deref 立即 load 返回右值,故 c.Set 需识别 Deref 左值形态(translate_c_set 形态 1)
c.Set(c.Deref(iptr), int_part)
return x - int_part
def log10(x: t.CDouble) -> t.CDouble:
return log(x) / U_M_LN10
def log2(x: t.CDouble) -> t.CDouble:
return log(x) / U_M_LN2
def exp2(x: t.CDouble) -> t.CDouble:
return pow(t.CDouble(2.0), x)
def expm1(x: t.CDouble) -> t.CDouble:
return exp(x) - t.CDouble(1.0)
def log1p(x: t.CDouble) -> t.CDouble:
return log(t.CDouble(1.0) + x)
def asinh(x: t.CDouble) -> t.CDouble:
return log(x + sqrt(x * x + t.CDouble(1.0)))
def acosh(x: t.CDouble) -> t.CDouble:
return log(x + sqrt(x * x - t.CDouble(1.0)))
def atanh(x: t.CDouble) -> t.CDouble:
return (log(t.CDouble(1.0) + x) - log(t.CDouble(1.0) - x)) / t.CDouble(2.0)
def gamma(x: t.CDouble) -> t.CDouble:
if x <= t.CDouble(0.0): return t.CDouble(0.0)
if x == t.CDouble(1.0) or x == t.CDouble(2.0): return t.CDouble(1.0)
ln_gamma: t.CDouble = t.CDouble(0.5) * log(t.CDouble(2.0) * U_M_PI / x) + x * log(x / U_M_E)
return exp(ln_gamma)
def erf(x: t.CDouble) -> t.CDouble:
sign: t.CDouble = t.CDouble(1.0) if x >= t.CDouble(0.0) else t.CDouble(-1.0)
abs_x: t.CDouble = fabs(x)
t0: t.CDouble = t.CDouble(4.0) * abs_x * abs_x / U_M_PI
exp_term: t.CDouble = exp(-t0)
return sign * sqrt(t.CDouble(1.0) - exp_term)
def erfc(x: t.CDouble) -> t.CDouble:
return t.CDouble(1.0) - erf(x)
def sqrtf(x: t.CFloat) -> t.CFloat:
if x < t.CFloat(0.0):
return t.CFloat(0.0)
if x == t.CFloat(0.0):
return t.CFloat(0.0)
guess: t.CFloat = x / t.CFloat(2.0)
for i in range(10):
guess = (guess + x / guess) / t.CFloat(2.0)
return guess
def sinf(x: t.CFloat) -> t.CFloat:
while x > t.CFloat(3.14159265):
x -= t.CFloat(6.28318530)
while x < t.CFloat(-3.14159265):
x += t.CFloat(6.28318530)
x2: t.CFloat = x * x
result: t.CFloat = x
term: t.CFloat = x
term = term * x2 / t.CFloat(6.0)
result = result - term
term = term * x2 / t.CFloat(20.0)
result = result + term
term = term * x2 / t.CFloat(42.0)
result = result - term
term = term * x2 / t.CFloat(72.0)
result = result + term
term = term * x2 / t.CFloat(110.0)
result = result - term
term = term * x2 / t.CFloat(156.0)
result = result + term
term = term * x2 / t.CFloat(210.0)
result = result - term
term = term * x2 / t.CFloat(272.0)
result = result + term
return result
def cosf(x: t.CFloat) -> t.CFloat:
while x > t.CFloat(3.14159265):
x -= t.CFloat(6.28318530)
while x < t.CFloat(-3.14159265):
x += t.CFloat(6.28318530)
x2: t.CFloat = x * x
result: t.CFloat = t.CFloat(1.0)
term: t.CFloat = t.CFloat(1.0)
term = term * x2 / t.CFloat(2.0)
result = result - term
term = term * x2 / t.CFloat(12.0)
result = result + term
term = term * x2 / t.CFloat(30.0)
result = result - term
term = term * x2 / t.CFloat(56.0)
result = result + term
term = term * x2 / t.CFloat(90.0)
result = result - term
term = term * x2 / t.CFloat(132.0)
result = result + term
term = term * x2 / t.CFloat(182.0)
result = result - term
term = term * x2 / t.CFloat(240.0)
result = result + term
return result
def tanf(x: t.CFloat) -> t.CFloat:
c: t.CFloat = cosf(x)
if c == t.CFloat(0.0):
return t.CFloat(0.0)
return sinf(x) / c
def fabsf(x: t.CFloat) -> t.CFloat:
return x if x >= t.CFloat(0.0) else -x
def floorf(x: t.CFloat) -> t.CFloat:
if x >= t.CFloat(0.0):
return t.CFloat(t.CInt(x))
i: t.CInt = t.CInt(x)
if x < t.CFloat(i):
return t.CFloat(i - 1)
else:
return t.CFloat(i)
def ceilf(x: t.CFloat) -> t.CFloat:
if x < t.CFloat(0.0):
return t.CFloat(t.CInt(x))
i: t.CInt = t.CInt(x)
if x > t.CFloat(i):
return t.CFloat(i + 1)
else:
return t.CFloat(i)
class _U(t.CUnion):
d: t.CDouble
u: t.CUInt64T
def isnan(x: t.CDouble) -> t.CStatic | t.CInt:
u: t.CUInt64T = t.CUInt64T(x)
exp_part: t.CUInt64T = (u >> 52) & 0x7FF
mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF
if exp_part == 0x7FF:
if mantissa_part != 0:
return 1
return 0
def isinf(x: t.CDouble) -> t.CStatic | t.CInt:
u: t.CUInt64T = t.CUInt64T(x)
exp_part: t.CUInt64T = (u >> 52) & 0x7FF
mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF
if exp_part == 0x7FF:
if mantissa_part == 0:
return 1
return 0
+492
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
from .string import *
+110
View File
@@ -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()
+90
View File
@@ -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 示例验证
+208
View File
@@ -0,0 +1,208 @@
# ============================================================
# vqt6 — Viper 的 Qt6 绑定包
#
# 公共 Pythonic API(基于 C 桥接层)
# 用户用法:
# import vqt6
# app = vqt6.QApplication([])
# win = vqt6.QWidget()
# win.setWindowTitle("Hello")
# win.show()
# app.exec()
# ============================================================
import t
from stdint import *
from vqt6._types import *
from vqt6._qtcore import *
from vqt6._qtwidgets import *
from vqt6._qtgui import *
from vqt6._qtnetwork import *
# ============================================================
# 高级 API 类(Pythonic 包装,不透明指针)
# ============================================================
@t.NoVTable
class QApplication:
"""QApplication 包装(不透明指针)"""
_ptr: QtAppPtr
def __init__(self, argv: list[str] | t.CPtr):
# 把 argv 转换为 argc/argv 数组
argc: t.CInt = 1
# Viper 端 argv 是 c_char_p 指针数组
# 这里仅传空 argv,避免 C ABI 复杂性
argv_ptr: t.CPtr = t.CPtr(0)
self._ptr = vqt6_qapplication_create(argc, argv_ptr)
if self._ptr is None:
raise RuntimeError("Failed to create QApplication")
def exec(self) -> int:
return vqt6_qapplication_exec(self._ptr)
def quit(self):
vqt6_qapplication_quit(self._ptr)
def exit(self, code: int):
vqt6_qapplication_exit(self._ptr, code)
def process_events(self):
vqt6_qapplication_process_events(self._ptr)
def desktop_width(self) -> int:
return vqt6_qapplication_desktop_width(self._ptr)
def desktop_height(self) -> int:
return vqt6_qapplication_desktop_height(self._ptr)
@t.NoVTable
class QWidget:
"""QWidget 包装"""
_ptr: QtWidgetPtr
def __init__(self, parent: "QWidget | None" = None):
if parent is not None and parent._ptr is not None:
self._ptr = vqt6_qwidget_create_with_parent(parent._ptr)
else:
self._ptr = vqt6_qwidget_create()
if self._ptr is None:
raise RuntimeError("Failed to create QWidget")
def show(self):
vqt6_qwidget_show(self._ptr)
def hide(self):
vqt6_qwidget_hide(self._ptr)
def close(self) -> int:
return vqt6_qwidget_close(self._ptr)
def setWindowTitle(self, title: str):
title_qs: QtStringPtr = vqt6_qstring_create(title)
vqt6_qwidget_set_window_title(self._ptr, title_qs)
vqt6_qstring_free(title_qs)
def windowTitle(self) -> str:
result: QtStringPtr = vqt6_qwidget_window_title(self._ptr)
buf: bytes = stdlib.malloc(1024)
vqt6_qstring_to_utf8(result, buf, 1024)
s: str = string.strndup(buf, 1024)
vqt6_qstring_free(result)
return s
def resize(self, w: int, h: int):
vqt6_qwidget_resize(self._ptr, w, h)
def move(self, x: int, y: int):
vqt6_qwidget_move(self._ptr, x, y)
def setGeometry(self, x: int, y: int, w: int, h: int):
vqt6_qwidget_set_geometry(self._ptr, x, y, w, h)
def setEnabled(self, enabled: int):
vqt6_qwidget_set_enabled(self._ptr, enabled)
def setVisible(self, visible: int):
vqt6_qwidget_set_visible(self._ptr, visible)
def isVisible(self) -> int:
return vqt6_qwidget_is_visible(self._ptr)
def setToolTip(self, tip: str):
tip_qs: QtStringPtr = vqt6_qstring_create(tip)
vqt6_qwidget_set_tool_tip(self._ptr, tip_qs)
vqt6_qstring_free(tip_qs)
@t.NoVTable
class QLabel:
"""QLabel 包装"""
_ptr: QtLabelPtr
def __init__(self, text: str = "", parent: "QWidget | None" = None):
text_qs: QtStringPtr = vqt6_qstring_create(text)
if parent is not None and parent._ptr is not None:
self._ptr = vqt6_qlabel_create_with_text_parent(text_qs, parent._ptr)
elif text_qs is not None:
self._ptr = vqt6_qlabel_create_with_text(text_qs)
else:
self._ptr = vqt6_qlabel_create()
vqt6_qstring_free(text_qs)
if self._ptr is None:
raise RuntimeError("Failed to create QLabel")
def setText(self, text: str):
text_qs: QtStringPtr = vqt6_qstring_create(text)
vqt6_qlabel_set_text(self._ptr, text_qs)
vqt6_qstring_free(text_qs)
def text(self) -> str:
result: QtStringPtr = vqt6_qlabel_text(self._ptr)
buf: bytes = stdlib.malloc(1024)
vqt6_qstring_to_utf8(result, buf, 1024)
s: str = string.strndup(buf, 1024)
vqt6_qstring_free(result)
return s
def setAlignment(self, alignment: int):
vqt6_qlabel_set_alignment(self._ptr, alignment)
@t.NoVTable
class QPushButton:
"""QPushButton 包装"""
_ptr: QtPushButtonPtr
def __init__(self, text: str = "", parent: "QWidget | None" = None):
text_qs: QtStringPtr = vqt6_qstring_create(text)
if parent is not None and parent._ptr is not None:
self._ptr = vqt6_qpushbutton_create_with_text_parent(text_qs, parent._ptr)
elif text_qs is not None:
self._ptr = vqt6_qpushbutton_create_with_text(text_qs)
else:
self._ptr = vqt6_qpushbutton_create()
vqt6_qstring_free(text_qs)
if self._ptr is None:
raise RuntimeError("Failed to create QPushButton")
def setText(self, text: str):
text_qs: QtStringPtr = vqt6_qstring_create(text)
vqt6_qpushbutton_set_text(self._ptr, text_qs)
vqt6_qstring_free(text_qs)
def text(self) -> str:
result: QtStringPtr = vqt6_qpushbutton_text(self._ptr)
buf: bytes = stdlib.malloc(1024)
vqt6_qstring_to_utf8(result, buf, 1024)
s: str = string.strndup(buf, 1024)
vqt6_qstring_free(result)
return s
def click(self):
vqt6_qpushbutton_click(self._ptr)
def setEnabled(self, enabled: int):
vqt6_qwidget_set_enabled(self._ptr, enabled)
# ============================================================
# 模块导出
# ============================================================
__all__ = [
# 高层类
"QApplication", "QWidget", "QLabel", "QPushButton",
# 类型
"QtObjectPtr", "QtStringPtr", "QtByteArrayPtr", "QtWidgetPtr", "QtAppPtr",
"QtLabelPtr", "QtPushButtonPtr",
"QtColorPtr", "QtFontPtr", "QtPixmapPtr", "QtImagePtr", "QtPainterPtr",
"QtTcpSocketPtr", "QtHostAddressPtr", "QtNetworkRequestPtr", "QtNetworkReplyPtr",
# 常量
"QT_KEY_ESCAPE", "QT_KEY_RETURN", "QT_KEY_A", "QT_KEY_Z",
"QT_LEFT_BUTTON", "QT_RIGHT_BUTTON", "QT_MID_BUTTON",
"QT_HORIZONTAL", "QT_VERTICAL",
"QT_ALIGN_LEFT", "QT_ALIGN_CENTER", "QT_ALIGN_RIGHT",
"QT_PORT_HTTP", "QT_PORT_HTTPS", "QT_PORT_FTP",
"QT_OK", "QT_CANCEL", "QT_YES", "QT_NO", "QT_CLOSE",
]
+151
View File
@@ -0,0 +1,151 @@
// ============================================================
// vqt6/_bridge.h — C 桥接层头文件
//
// 作用: 把 Qt6 C++ API 包装成 extern "C" 函数,供 Viper FFI 调用
// 编译: 作为静态库 libvqt6_bridge.a 或动态库 vqt6_bridge.dll
// ============================================================
#ifndef VQT6_BRIDGE_H
#define VQT6_BRIDGE_H
#include <stddef.h>
#include <stdint.h>
#if defined(_WIN32)
# if defined(VQT6_BRIDGE_STATIC)
# define VQT6_API
# elif defined(VQT6_BRIDGE_BUILD)
# define VQT6_API __declspec(dllexport)
# else
# define VQT6_API __declspec(dllimport)
# endif
#else
# if defined(__GNUC__) && (__GNUC__ >= 4)
# define VQT6_API __attribute__((visibility("default")))
# else
# define VQT6_API
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
// ============================================================
// QString
// ============================================================
VQT6_API void* vqt6_qstring_create(const char* utf8);
VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size);
VQT6_API void vqt6_qstring_free(void* qstr);
VQT6_API int vqt6_qstring_length(void* qstr);
VQT6_API int vqt6_qstring_is_empty(void* qstr);
VQT6_API int vqt6_qstring_equals(void* qstr, void* other);
VQT6_API void* vqt6_qstring_append(void* qstr, void* other);
// ============================================================
// QByteArray
// ============================================================
VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size);
VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size);
VQT6_API size_t vqt6_qbytearray_size(void* qba);
VQT6_API void vqt6_qbytearray_free(void* qba);
// ============================================================
// QObject
// ============================================================
VQT6_API void vqt6_qobject_delete(void* obj);
VQT6_API void vqt6_qobject_delete_later(void* obj);
VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name);
VQT6_API void* vqt6_qobject_object_name(void* obj);
VQT6_API void vqt6_qobject_set_parent(void* child, void* parent);
VQT6_API void* vqt6_qobject_parent(void* obj);
VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name,
void* receiver, const char* slot_name);
VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name,
void* receiver, const char* slot_name);
VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter);
VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter);
// ============================================================
// QCoreApplication
// ============================================================
VQT6_API void* vqt6_qcoreapp_create(const char* app_name);
VQT6_API void* vqt6_qcoreapp_instance(void);
VQT6_API int vqt6_qcoreapp_exec(void* app);
VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code);
VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code);
VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags);
VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event);
VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event);
VQT6_API void* vqt6_qcoreapp_organization_name(void* app);
VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name);
VQT6_API void* vqt6_qcoreapp_application_name(void* app);
VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name);
// ============================================================
// QTimer
// ============================================================
VQT6_API void* vqt6_qtimer_create(void);
VQT6_API void* vqt6_qtimer_create_with_parent(void* parent);
VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms);
VQT6_API void vqt6_qtimer_stop(void* timer);
VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms);
VQT6_API int vqt6_qtimer_interval(void* timer);
VQT6_API int vqt6_qtimer_is_active(void* timer);
VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot);
VQT6_API int vqt6_qtimer_is_single_shot(void* timer);
// ============================================================
// QVariant
// ============================================================
VQT6_API void* vqt6_qvariant_create_int(int value);
VQT6_API void* vqt6_qvariant_create_double(double value);
VQT6_API void* vqt6_qvariant_create_bool(int value);
VQT6_API void* vqt6_qvariant_create_string(void* s);
VQT6_API int vqt6_qvariant_to_int(void* v, int* ok);
VQT6_API double vqt6_qvariant_to_double(void* v, int* ok);
VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok);
VQT6_API void* vqt6_qvariant_to_string(void* v);
VQT6_API int vqt6_qvariant_type_id(void* v);
VQT6_API int vqt6_qvariant_is_valid(void* v);
VQT6_API void vqt6_qvariant_free(void* v);
// ============================================================
// QEvent
// ============================================================
VQT6_API int vqt6_qevent_type(void* event);
VQT6_API void vqt6_qevent_accept(void* event);
VQT6_API void vqt6_qevent_ignore(void* event);
VQT6_API int vqt6_qevent_is_accepted(void* event);
// ============================================================
// QStringList
// ============================================================
VQT6_API void* vqt6_qstringlist_create(void);
VQT6_API void vqt6_qstringlist_append(void* list, void* str);
VQT6_API int vqt6_qstringlist_size(void* list);
VQT6_API void* vqt6_qstringlist_at(void* list, int index);
VQT6_API void vqt6_qstringlist_free(void* list);
// ============================================================
// QByteArrayList
// ============================================================
VQT6_API void* vqt6_qbytearraylist_create(void);
VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba);
VQT6_API int vqt6_qbytearraylist_size(void* list);
VQT6_API void* vqt6_qbytearraylist_at(void* list, int index);
VQT6_API void vqt6_qbytearraylist_free(void* list);
// ============================================================
// 全局回调注册表
// ============================================================
typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data);
VQT6_API void vqt6_register_slot(int slot_id, void* user_data);
VQT6_API void vqt6_unregister_slot(int slot_id);
VQT6_API void vqt6_trigger_slot(int slot_id);
#ifdef __cplusplus
}
#endif
#endif // VQT6_BRIDGE_H
+433
View File
@@ -0,0 +1,433 @@
// ============================================================
// vqt6/_bridge_core.cpp — QtCore C 桥接层实现
// ============================================================
#include "_bridge.h"
#include <QString>
#include <QByteArray>
#include <QObject>
#include <QCoreApplication>
#include <QTimer>
#include <QVariant>
#include <QEvent>
#include <QStringList>
#include <QList>
#include <QHash>
#include <QMutex>
#include <cstring>
// 全局回调表(线程安全)
namespace {
QMutex g_slot_mutex;
QHash<int, QPair<vqt6_slot_callback_t, void*>> g_slots;
}
// ============================================================
// QString
// ============================================================
extern "C" VQT6_API void* vqt6_qstring_create(const char* utf8) {
if (utf8 == nullptr) return nullptr;
return new QString(QString::fromUtf8(utf8));
}
extern "C" VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size) {
if (qstr == nullptr || buf == nullptr || buf_size == 0) return 0;
QString* s = static_cast<QString*>(qstr);
QByteArray ba = s->toUtf8();
size_t len = static_cast<size_t>(ba.size());
if (len >= buf_size) len = buf_size - 1;
std::memcpy(buf, ba.constData(), len);
buf[len] = '\0';
return len;
}
extern "C" VQT6_API void vqt6_qstring_free(void* qstr) {
delete static_cast<QString*>(qstr);
}
extern "C" VQT6_API int vqt6_qstring_length(void* qstr) {
if (qstr == nullptr) return 0;
return static_cast<QString*>(qstr)->length();
}
extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) {
if (qstr == nullptr) return 1;
return static_cast<QString*>(qstr)->isEmpty() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qstring_equals(void* qstr, void* other) {
if (qstr == nullptr || other == nullptr) return 0;
return *static_cast<QString*>(qstr) == *static_cast<QString*>(other) ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qstring_append(void* qstr, void* other) {
if (qstr == nullptr || other == nullptr) return nullptr;
return new QString(*static_cast<QString*>(qstr) + *static_cast<QString*>(other));
}
// ============================================================
// QByteArray
// ============================================================
extern "C" VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size) {
if (data == nullptr) return new QByteArray();
return new QByteArray(static_cast<const char*>(data), static_cast<int>(size));
}
extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) {
if (qba == nullptr) return nullptr;
QByteArray* ba = static_cast<QByteArray*>(qba);
if (out_size != nullptr) *out_size = static_cast<size_t>(ba->size());
return ba->data();
}
extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) {
if (qba == nullptr) return 0;
return static_cast<size_t>(static_cast<QByteArray*>(qba)->size());
}
extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) {
delete static_cast<QByteArray*>(qba);
}
// ============================================================
// QObject
// ============================================================
extern "C" VQT6_API void vqt6_qobject_delete(void* obj) {
if (obj == nullptr) return;
delete static_cast<QObject*>(obj);
}
extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) {
if (obj == nullptr) return;
static_cast<QObject*>(obj)->deleteLater();
}
extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) {
if (obj == nullptr || name == nullptr) return;
static_cast<QObject*>(obj)->setObjectName(*static_cast<QString*>(name));
}
extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) {
if (obj == nullptr) return nullptr;
return new QString(static_cast<QObject*>(obj)->objectName());
}
extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) {
if (child == nullptr) return;
static_cast<QObject*>(child)->setParent(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) {
if (obj == nullptr) return nullptr;
return static_cast<QObject*>(obj)->parent();
}
extern "C" VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name,
void* receiver, const char* slot_name) {
if (sender == nullptr || receiver == nullptr || signal_name == nullptr || slot_name == nullptr)
return 0;
return QObject::connect(
static_cast<QObject*>(sender), signal_name,
static_cast<QObject*>(receiver), slot_name
) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name,
void* receiver, const char* slot_name) {
if (sender == nullptr || receiver == nullptr) return 0;
return QObject::disconnect(
static_cast<QObject*>(sender), signal_name,
static_cast<QObject*>(receiver), slot_name
) ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter) {
if (watched == nullptr || filter == nullptr) return;
static_cast<QObject*>(watched)->installEventFilter(static_cast<QObject*>(filter));
}
extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) {
if (watched == nullptr || filter == nullptr) return;
static_cast<QObject*>(watched)->removeEventFilter(static_cast<QObject*>(filter));
}
// ============================================================
// QCoreApplication
// ============================================================
extern "C" VQT6_API void* vqt6_qcoreapp_create(const char* app_name) {
if (app_name == nullptr) return nullptr;
int argc = 1;
static char app_name_copy[1024];
std::strncpy(app_name_copy, app_name, sizeof(app_name_copy) - 1);
app_name_copy[sizeof(app_name_copy) - 1] = '\0';
char* argv[] = { app_name_copy, nullptr };
return new QCoreApplication(argc, argv);
}
extern "C" VQT6_API void* vqt6_qcoreapp_instance(void) {
return QCoreApplication::instance();
}
extern "C" VQT6_API int vqt6_qcoreapp_exec(void* app) {
if (app == nullptr) return -1;
return static_cast<QCoreApplication*>(app)->exec();
}
extern "C" VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code) {
if (app == nullptr) return;
// 优先使用 exit_code 重载
QCoreApplication* a = static_cast<QCoreApplication*>(app);
if (a == QCoreApplication::instance()) {
a->exit(exit_code);
}
}
extern "C" VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code) {
if (app == nullptr) return;
static_cast<QCoreApplication*>(app)->exit(exit_code);
}
extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) {
if (app == nullptr) return;
static_cast<QCoreApplication*>(app)->processEvents(static_cast<QEventLoop::ProcessEventsFlag>(flags));
}
extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) {
if (receiver == nullptr || event == nullptr) return;
QCoreApplication::postEvent(static_cast<QObject*>(receiver), static_cast<QEvent*>(event));
}
extern "C" VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event) {
if (receiver == nullptr || event == nullptr) return 0;
return QCoreApplication::sendEvent(static_cast<QObject*>(receiver), static_cast<QEvent*>(event)) ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qcoreapp_organization_name(void* app) {
if (app == nullptr) return nullptr;
return new QString(QCoreApplication::organizationName());
}
extern "C" VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name) {
if (app == nullptr || name == nullptr) return;
QCoreApplication::setOrganizationName(*static_cast<QString*>(name));
}
extern "C" VQT6_API void* vqt6_qcoreapp_application_name(void* app) {
if (app == nullptr) return nullptr;
return new QString(QCoreApplication::applicationName());
}
extern "C" VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name) {
if (app == nullptr || name == nullptr) return;
QCoreApplication::setApplicationName(*static_cast<QString*>(name));
}
// ============================================================
// QTimer
// ============================================================
extern "C" VQT6_API void* vqt6_qtimer_create(void) {
return new QTimer();
}
extern "C" VQT6_API void* vqt6_qtimer_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QTimer(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->start(interval_ms);
}
extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->stop();
}
extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->setInterval(interval_ms);
}
extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) {
if (timer == nullptr) return 0;
return static_cast<QTimer*>(timer)->interval();
}
extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) {
if (timer == nullptr) return 0;
return static_cast<QTimer*>(timer)->isActive() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->setSingleShot(single_shot != 0);
}
extern "C" VQT6_API int vqt6_qtimer_is_single_shot(void* timer) {
if (timer == nullptr) return 0;
return static_cast<QTimer*>(timer)->isSingleShot() ? 1 : 0;
}
// ============================================================
// QVariant
// ============================================================
extern "C" VQT6_API void* vqt6_qvariant_create_int(int value) {
return new QVariant(value);
}
extern "C" VQT6_API void* vqt6_qvariant_create_double(double value) {
return new QVariant(value);
}
extern "C" VQT6_API void* vqt6_qvariant_create_bool(int value) {
return new QVariant(value != 0);
}
extern "C" VQT6_API void* vqt6_qvariant_create_string(void* s) {
if (s == nullptr) return new QVariant();
return new QVariant(*static_cast<QString*>(s));
}
extern "C" VQT6_API int vqt6_qvariant_to_int(void* v, int* ok) {
if (v == nullptr) return 0;
bool bok = false;
int val = static_cast<QVariant*>(v)->toInt(&bok);
if (ok != nullptr) *ok = bok ? 1 : 0;
return val;
}
extern "C" VQT6_API double vqt6_qvariant_to_double(void* v, int* ok) {
if (v == nullptr) return 0.0;
bool bok = false;
double val = static_cast<QVariant*>(v)->toDouble(&bok);
if (ok != nullptr) *ok = bok ? 1 : 0;
return val;
}
extern "C" VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok) {
if (v == nullptr) return 0;
bool bok = false;
bool val = static_cast<QVariant*>(v)->toBool();
if (ok != nullptr) *ok = 1;
return val ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qvariant_to_string(void* v) {
if (v == nullptr) return nullptr;
return new QString(static_cast<QVariant*>(v)->toString());
}
extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) {
if (v == nullptr) return 0;
return static_cast<int>(static_cast<QVariant*>(v)->typeId());
}
extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) {
if (v == nullptr) return 0;
return static_cast<QVariant*>(v)->isValid() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qvariant_free(void* v) {
delete static_cast<QVariant*>(v);
}
// ============================================================
// QEvent
// ============================================================
extern "C" VQT6_API int vqt6_qevent_type(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QEvent*>(event)->type());
}
extern "C" VQT6_API void vqt6_qevent_accept(void* event) {
if (event == nullptr) return;
static_cast<QEvent*>(event)->accept();
}
extern "C" VQT6_API void vqt6_qevent_ignore(void* event) {
if (event == nullptr) return;
static_cast<QEvent*>(event)->ignore();
}
extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) {
if (event == nullptr) return 0;
return static_cast<QEvent*>(event)->isAccepted() ? 1 : 0;
}
// ============================================================
// QStringList
// ============================================================
extern "C" VQT6_API void* vqt6_qstringlist_create(void) {
return new QStringList();
}
extern "C" VQT6_API void vqt6_qstringlist_append(void* list, void* str) {
if (list == nullptr || str == nullptr) return;
static_cast<QStringList*>(list)->append(*static_cast<QString*>(str));
}
extern "C" VQT6_API int vqt6_qstringlist_size(void* list) {
if (list == nullptr) return 0;
return static_cast<QStringList*>(list)->size();
}
extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) {
if (list == nullptr) return nullptr;
QStringList* sl = static_cast<QStringList*>(list);
if (index < 0 || index >= sl->size()) return nullptr;
return new QString(sl->at(index));
}
extern "C" VQT6_API void vqt6_qstringlist_free(void* list) {
delete static_cast<QStringList*>(list);
}
// ============================================================
// QByteArrayList
// ============================================================
extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) {
return new QList<QByteArray>();
}
extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) {
if (list == nullptr || qba == nullptr) return;
static_cast<QList<QByteArray>*>(list)->append(*static_cast<QByteArray*>(qba));
}
extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) {
if (list == nullptr) return 0;
return static_cast<QList<QByteArray>*>(list)->size();
}
extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) {
if (list == nullptr) return nullptr;
QList<QByteArray>* qbl = static_cast<QList<QByteArray>*>(list);
if (index < 0 || index >= qbl->size()) return nullptr;
return new QByteArray(qbl->at(index));
}
extern "C" VQT6_API void vqt6_qbytearraylist_free(void* list) {
delete static_cast<QList<QByteArray>*>(list);
}
// ============================================================
// 全局回调注册表
// ============================================================
extern "C" VQT6_API void vqt6_register_slot(int slot_id, void* user_data) {
QMutexLocker locker(&g_slot_mutex);
g_slots.insert(slot_id, QPair<vqt6_slot_callback_t, void*>(nullptr, user_data));
}
extern "C" VQT6_API void vqt6_unregister_slot(int slot_id) {
QMutexLocker locker(&g_slot_mutex);
g_slots.remove(slot_id);
}
extern "C" VQT6_API void vqt6_trigger_slot(int slot_id) {
QMutexLocker locker(&g_slot_mutex);
auto it = g_slots.find(slot_id);
if (it != g_slots.end() && it.value().first != nullptr) {
it.value().first(slot_id, it.value().second);
}
}
+868
View File
@@ -0,0 +1,868 @@
// ============================================================
// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现
// ============================================================
#include "_bridge.h"
#include "_bridge_gui.h"
#include <QColor>
#include <QFont>
#include <QFontMetrics>
#include <QPixmap>
#include <QImage>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QIcon>
#include <QCursor>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QPaintEvent>
#include <QCloseEvent>
#include <QPainterPath>
#include <QPolygon>
#include <QPoint>
#include <QPointF>
#include <QRect>
#include <QRectF>
#include <QGuiApplication>
#include <QScreen>
#include <QImageReader>
#include <QBuffer>
#include <QStyle>
#include <QStringList>
// ============================================================
// QColor
// ============================================================
extern "C" VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b) {
return new QColor(r, g, b);
}
extern "C" VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a) {
return new QColor(r, g, b, a);
}
extern "C" VQT6_API void* vqt6_qcolor_create_name(void* name) {
if (name == nullptr) return new QColor();
return new QColor(*static_cast<QString*>(name));
}
extern "C" VQT6_API void* vqt6_qcolor_create_hex(void* hex_str) {
if (hex_str == nullptr) return new QColor();
return new QColor(*static_cast<QString*>(hex_str));
}
extern "C" VQT6_API int vqt6_qcolor_red(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->red();
}
extern "C" VQT6_API int vqt6_qcolor_green(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->green();
}
extern "C" VQT6_API int vqt6_qcolor_blue(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->blue();
}
extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) {
if (c == nullptr) return 255;
return static_cast<QColor*>(c)->alpha();
}
extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setRed(r);
}
extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setGreen(g);
}
extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setBlue(b);
}
extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setAlpha(a);
}
extern "C" VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setRgb(r, g, b);
}
extern "C" VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setRgba(r, g, b, a);
}
extern "C" VQT6_API void* vqt6_qcolor_name(void* c) {
if (c == nullptr) return nullptr;
return new QString(static_cast<QColor*>(c)->name());
}
extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->isValid() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qcolor_free(void* c) {
delete static_cast<QColor*>(c);
}
// ============================================================
// QFont
// ============================================================
extern "C" VQT6_API void* vqt6_qfont_create(void) {
return new QFont();
}
extern "C" VQT6_API void* vqt6_qfont_create_with_family(void* family) {
if (family == nullptr) return new QFont();
return new QFont(*static_cast<QString*>(family));
}
extern "C" VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size) {
if (family == nullptr) return new QFont();
return new QFont(*static_cast<QString*>(family), point_size);
}
extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) {
if (font == nullptr || family == nullptr) return;
static_cast<QFont*>(font)->setFamily(*static_cast<QString*>(family));
}
extern "C" VQT6_API void* vqt6_qfont_family(void* font) {
if (font == nullptr) return nullptr;
return new QString(static_cast<QFont*>(font)->family());
}
extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setPointSize(point_size);
}
extern "C" VQT6_API int vqt6_qfont_point_size(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->pointSize();
}
extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setPixelSize(pixel_size);
}
extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->pixelSize();
}
extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setBold(bold != 0);
}
extern "C" VQT6_API int vqt6_qfont_bold(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->bold() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setItalic(italic != 0);
}
extern "C" VQT6_API int vqt6_qfont_italic(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->italic() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setUnderline(underline != 0);
}
extern "C" VQT6_API int vqt6_qfont_underline(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->underline() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setStrikeOut(strike_out != 0);
}
extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->strikeOut() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setWeight(static_cast<QFont::Weight>(weight));
}
extern "C" VQT6_API int vqt6_qfont_weight(void* font) {
if (font == nullptr) return 0;
return static_cast<int>(static_cast<QFont*>(font)->weight());
}
extern "C" VQT6_API void vqt6_qfont_free(void* font) {
delete static_cast<QFont*>(font);
}
// ============================================================
// QFontMetrics
// ============================================================
extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) {
if (font == nullptr) return nullptr;
return new QFontMetrics(*static_cast<QFont*>(font));
}
extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) {
if (fm == nullptr || text == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->horizontalAdvance(*static_cast<QString*>(text));
}
extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) {
if (fm == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->height();
}
extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) {
if (fm == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->ascent();
}
extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) {
if (fm == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->descent();
}
extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) {
delete static_cast<QFontMetrics*>(fm);
}
// ============================================================
// QPixmap
// ============================================================
extern "C" VQT6_API void* vqt6_qpixmap_create(void) {
return new QPixmap();
}
extern "C" VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h) {
return new QPixmap(w, h);
}
extern "C" VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name) {
if (pm == nullptr || file_name == nullptr) return 0;
return static_cast<QPixmap*>(pm)->load(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size) {
if (pm == nullptr || data == nullptr) return 0;
return static_cast<QPixmap*>(pm)->loadFromData(static_cast<const uchar*>(data), static_cast<uint>(size)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name) {
if (pm == nullptr || file_name == nullptr) return 0;
return static_cast<QPixmap*>(pm)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) {
if (pm == nullptr) return 0;
return static_cast<QPixmap*>(pm)->width();
}
extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) {
if (pm == nullptr) return 0;
return static_cast<QPixmap*>(pm)->height();
}
extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) {
if (pm == nullptr) return 0;
return static_cast<QPixmap*>(pm)->isNull() ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h) {
if (pm == nullptr) return nullptr;
return new QPixmap(static_cast<QPixmap*>(pm)->scaled(w, h));
}
extern "C" VQT6_API void vqt6_qpixmap_fill(void* pm, void* color) {
if (pm == nullptr) return;
if (color != nullptr) {
static_cast<QPixmap*>(pm)->fill(*static_cast<QColor*>(color));
} else {
static_cast<QPixmap*>(pm)->fill();
}
}
extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) {
delete static_cast<QPixmap*>(pm);
}
// ============================================================
// QImage
// ============================================================
extern "C" VQT6_API void* vqt6_qimage_create(void) {
return new QImage();
}
extern "C" VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format) {
return new QImage(w, h, static_cast<QImage::Format>(format));
}
extern "C" VQT6_API int vqt6_qimage_load(void* img, void* file_name) {
if (img == nullptr || file_name == nullptr) return 0;
return static_cast<QImage*>(img)->load(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qimage_save(void* img, void* file_name) {
if (img == nullptr || file_name == nullptr) return 0;
return static_cast<QImage*>(img)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qimage_width(void* img) {
if (img == nullptr) return 0;
return static_cast<QImage*>(img)->width();
}
extern "C" VQT6_API int vqt6_qimage_height(void* img) {
if (img == nullptr) return 0;
return static_cast<QImage*>(img)->height();
}
extern "C" VQT6_API int vqt6_qimage_format(void* img) {
if (img == nullptr) return 0;
return static_cast<int>(static_cast<QImage*>(img)->format());
}
extern "C" VQT6_API int vqt6_qimage_is_null(void* img) {
if (img == nullptr) return 0;
return static_cast<QImage*>(img)->isNull() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qimage_fill(void* img, void* color) {
if (img == nullptr) return;
if (color != nullptr) {
static_cast<QImage*>(img)->fill(*static_cast<QColor*>(color));
}
}
extern "C" VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h) {
if (img == nullptr) return nullptr;
return new QImage(static_cast<QImage*>(img)->scaled(w, h));
}
extern "C" VQT6_API void vqt6_qimage_free(void* img) {
delete static_cast<QImage*>(img);
}
// ============================================================
// QPainter
// ============================================================
extern "C" VQT6_API void* vqt6_qpainter_create(void) {
return new QPainter();
}
extern "C" VQT6_API int vqt6_qpainter_begin(void* p, void* device) {
if (p == nullptr || device == nullptr) return 0;
return static_cast<QPainter*>(p)->begin(static_cast<QPixmap*>(device)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpainter_end(void* p) {
if (p == nullptr) return 0;
return static_cast<QPainter*>(p)->end() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) {
if (p == nullptr) return 0;
return static_cast<QPainter*>(p)->isActive() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen) {
if (p == nullptr || pen == nullptr) return;
static_cast<QPainter*>(p)->setPen(*static_cast<QPen*>(pen));
}
extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) {
if (p == nullptr || brush == nullptr) return;
static_cast<QPainter*>(p)->setBrush(*static_cast<QBrush*>(brush));
}
extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) {
if (p == nullptr || font == nullptr) return;
static_cast<QPainter*>(p)->setFont(*static_cast<QFont*>(font));
}
extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) {
if (p == nullptr) return nullptr;
return new QPen(static_cast<QPainter*>(p)->pen());
}
extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) {
if (p == nullptr) return nullptr;
return new QBrush(static_cast<QPainter*>(p)->brush());
}
extern "C" VQT6_API void* vqt6_qpainter_font(void* p) {
if (p == nullptr) return nullptr;
return new QFont(static_cast<QPainter*>(p)->font());
}
extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->setOpacity(opacity);
}
extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) {
if (p == nullptr) return 1.0;
return static_cast<QPainter*>(p)->opacity();
}
extern "C" VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawLine(x1, y1, x2, y2);
}
extern "C" VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawRect(x, y, w, h);
}
extern "C" VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color) {
if (p == nullptr || color == nullptr) return;
static_cast<QPainter*>(p)->fillRect(x, y, w, h, *static_cast<QColor*>(color));
}
extern "C" VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawEllipse(x, y, w, h);
}
extern "C" VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawArc(x, y, w, h, start_angle, span_angle);
}
extern "C" VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawChord(x, y, w, h, start_angle, span_angle);
}
extern "C" VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawPie(x, y, w, h, start_angle, span_angle);
}
extern "C" VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count) {
if (p == nullptr || points == nullptr || point_count < 1) return;
QPolygon polygon;
for (int i = 0; i < point_count; ++i) {
polygon << QPoint(points[i*2], points[i*2+1]);
}
static_cast<QPainter*>(p)->drawPolygon(polygon);
}
extern "C" VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count) {
if (p == nullptr || points == nullptr || point_count < 1) return;
QPolygon polyline;
for (int i = 0; i < point_count; ++i) {
polyline << QPoint(points[i*2], points[i*2+1]);
}
static_cast<QPainter*>(p)->drawPolyline(polyline);
}
extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawPoint(x, y);
}
extern "C" VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count) {
if (p == nullptr || points == nullptr || point_count < 1) return;
QPolygon pts;
for (int i = 0; i < point_count; ++i) {
pts << QPoint(points[i*2], points[i*2+1]);
}
static_cast<QPainter*>(p)->drawPoints(pts);
}
extern "C" VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text) {
if (p == nullptr || text == nullptr) return;
static_cast<QPainter*>(p)->drawText(x, y, *static_cast<QString*>(text));
}
extern "C" VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text) {
if (p == nullptr || text == nullptr) return;
static_cast<QPainter*>(p)->drawText(x, y, w, h, flags, *static_cast<QString*>(text));
}
extern "C" VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap) {
if (p == nullptr || pixmap == nullptr) return;
static_cast<QPainter*>(p)->drawPixmap(x, y, *static_cast<QPixmap*>(pixmap));
}
extern "C" VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image) {
if (p == nullptr || image == nullptr) return;
static_cast<QPainter*>(p)->drawImage(x, y, *static_cast<QImage*>(image));
}
extern "C" VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap) {
if (p == nullptr || pixmap == nullptr) return;
static_cast<QPainter*>(p)->drawTiledPixmap(x, y, w, h, *static_cast<QPixmap*>(pixmap));
}
extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->translate(dx, dy);
}
extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->rotate(angle);
}
extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->scale(sx, sy);
}
extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->resetTransform();
}
extern "C" VQT6_API void vqt6_qpainter_save(void* p) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->save();
}
extern "C" VQT6_API void vqt6_qpainter_restore(void* p) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->restore();
}
extern "C" VQT6_API void vqt6_qpainter_free(void* p) {
delete static_cast<QPainter*>(p);
}
// ============================================================
// QPen
// ============================================================
extern "C" VQT6_API void* vqt6_qpen_create(void) {
return new QPen();
}
extern "C" VQT6_API void* vqt6_qpen_create_with_color(void* color) {
if (color == nullptr) return new QPen();
return new QPen(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width) {
if (color == nullptr) return new QPen();
return new QPen(*static_cast<QColor*>(color), width);
}
extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) {
if (pen == nullptr || color == nullptr) return;
static_cast<QPen*>(pen)->setColor(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qpen_color(void* pen) {
if (pen == nullptr) return nullptr;
return new QColor(static_cast<QPen*>(pen)->color());
}
extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) {
if (pen == nullptr) return;
static_cast<QPen*>(pen)->setWidth(width);
}
extern "C" VQT6_API int vqt6_qpen_width(void* pen) {
if (pen == nullptr) return 0;
return static_cast<QPen*>(pen)->width();
}
extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) {
if (pen == nullptr) return;
static_cast<QPen*>(pen)->setStyle(static_cast<Qt::PenStyle>(style));
}
extern "C" VQT6_API int vqt6_qpen_style(void* pen) {
if (pen == nullptr) return 0;
return static_cast<int>(static_cast<QPen*>(pen)->style());
}
extern "C" VQT6_API void vqt6_qpen_free(void* pen) {
delete static_cast<QPen*>(pen);
}
// ============================================================
// QBrush
// ============================================================
extern "C" VQT6_API void* vqt6_qbrush_create(void) {
return new QBrush();
}
extern "C" VQT6_API void* vqt6_qbrush_create_with_color(void* color) {
if (color == nullptr) return new QBrush();
return new QBrush(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) {
return new QBrush(static_cast<Qt::BrushStyle>(style));
}
extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) {
if (brush == nullptr || color == nullptr) return;
static_cast<QBrush*>(brush)->setColor(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) {
if (brush == nullptr) return nullptr;
return new QColor(static_cast<QBrush*>(brush)->color());
}
extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) {
if (brush == nullptr) return;
static_cast<QBrush*>(brush)->setStyle(static_cast<Qt::BrushStyle>(style));
}
extern "C" VQT6_API int vqt6_qbrush_style(void* brush) {
if (brush == nullptr) return 0;
return static_cast<int>(static_cast<QBrush*>(brush)->style());
}
extern "C" VQT6_API void vqt6_qbrush_free(void* brush) {
delete static_cast<QBrush*>(brush);
}
// ============================================================
// QIcon
// ============================================================
extern "C" VQT6_API void* vqt6_qicon_create(void) {
return new QIcon();
}
extern "C" VQT6_API void* vqt6_qicon_create_with_file(void* file_name) {
if (file_name == nullptr) return new QIcon();
return new QIcon(*static_cast<QString*>(file_name));
}
extern "C" VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name) {
if (icon == nullptr || file_name == nullptr) return;
static_cast<QIcon*>(icon)->addFile(*static_cast<QString*>(file_name));
}
extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) {
if (icon == nullptr || pixmap == nullptr) return;
static_cast<QIcon*>(icon)->addPixmap(*static_cast<QPixmap*>(pixmap));
}
extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) {
if (icon == nullptr) return 0;
return static_cast<QIcon*>(icon)->isNull() ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h) {
if (icon == nullptr) return nullptr;
return new QPixmap(static_cast<QIcon*>(icon)->pixmap(w, h));
}
extern "C" VQT6_API void vqt6_qicon_free(void* icon) {
delete static_cast<QIcon*>(icon);
}
// ============================================================
// QCursor
// ============================================================
extern "C" VQT6_API void* vqt6_qcursor_create(void) {
return new QCursor();
}
extern "C" VQT6_API void* vqt6_qcursor_create_with_shape(int shape) {
return new QCursor(static_cast<Qt::CursorShape>(shape));
}
extern "C" VQT6_API void vqt6_qcursor_pos(int* x, int* y) {
QPoint p = QCursor::pos();
if (x != nullptr) *x = p.x();
if (y != nullptr) *y = p.y();
}
extern "C" VQT6_API void vqt6_qcursor_set_pos(int x, int y) {
QCursor::setPos(x, y);
}
extern "C" VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape) {
if (cursor == nullptr) return;
static_cast<QCursor*>(cursor)->setShape(static_cast<Qt::CursorShape>(shape));
}
extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) {
if (cursor == nullptr) return 0;
return static_cast<int>(static_cast<QCursor*>(cursor)->shape());
}
extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) {
delete static_cast<QCursor*>(cursor);
}
// ============================================================
// QKeyEvent
// ============================================================
extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) {
QString* t = static_cast<QString*>(text);
return new QKeyEvent(static_cast<QEvent::Type>(type), key, static_cast<Qt::KeyboardModifiers>(modifiers),
t != nullptr ? *t : QString());
}
extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) {
if (event == nullptr) return 0;
return static_cast<QKeyEvent*>(event)->key();
}
extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) {
if (event == nullptr) return nullptr;
return new QString(static_cast<QKeyEvent*>(event)->text());
}
extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QKeyEvent*>(event)->modifiers());
}
extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) {
if (event == nullptr) return 0;
return static_cast<QKeyEvent*>(event)->isAutoRepeat() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) {
delete static_cast<QKeyEvent*>(event);
}
// ============================================================
// QMouseEvent
// ============================================================
extern "C" VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers) {
QPointF* lp = static_cast<QPointF*>(local_pos);
return new QMouseEvent(
static_cast<QEvent::Type>(type),
lp != nullptr ? *lp : QPointF(0, 0),
Qt::NoButton,
static_cast<Qt::MouseButton>(button),
static_cast<Qt::KeyboardModifiers>(modifiers)
);
}
extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->button());
}
extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->buttons());
}
extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().x());
}
extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().y());
}
extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().x());
}
extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().y());
}
extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->modifiers());
}
extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) {
delete static_cast<QMouseEvent*>(event);
}
// ============================================================
// QResizeEvent / QPaintEvent / QCloseEvent
// ============================================================
extern "C" VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height) {
return new QResizeEvent(QSize(width, height), QSize(old_width, old_height));
}
extern "C" VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h) {
if (event == nullptr) return;
QSize s = static_cast<QResizeEvent*>(event)->size();
if (w != nullptr) *w = s.width();
if (h != nullptr) *h = s.height();
}
extern "C" VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h) {
if (event == nullptr) return;
QSize s = static_cast<QResizeEvent*>(event)->oldSize();
if (w != nullptr) *w = s.width();
if (h != nullptr) *h = s.height();
}
extern "C" VQT6_API void vqt6_qresizeevent_free(void* event) {
delete static_cast<QResizeEvent*>(event);
}
extern "C" VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h) {
return new QPaintEvent(QRect(rect_x, rect_y, rect_w, rect_h));
}
extern "C" VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h) {
if (event == nullptr) return;
QRect r = static_cast<QPaintEvent*>(event)->rect();
if (x != nullptr) *x = r.x();
if (y != nullptr) *y = r.y();
if (w != nullptr) *w = r.width();
if (h != nullptr) *h = r.height();
}
extern "C" VQT6_API void vqt6_qpaintevent_free(void* event) {
delete static_cast<QPaintEvent*>(event);
}
extern "C" VQT6_API void* vqt6_qcloseevent_create(void) {
return new QCloseEvent();
}
extern "C" VQT6_API int vqt6_qcloseevent_is_accepted(void* event) {
if (event == nullptr) return 0;
return static_cast<QCloseEvent*>(event)->isAccepted() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) {
if (event == nullptr) return;
static_cast<QCloseEvent*>(event)->accept();
}
extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) {
if (event == nullptr) return;
static_cast<QCloseEvent*>(event)->ignore();
}
extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) {
delete static_cast<QCloseEvent*>(event);
}
+231
View File
@@ -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
+519
View File
@@ -0,0 +1,519 @@
// ============================================================
// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现
// ============================================================
#include "_bridge.h"
#include "_bridge_network.h"
#include <QHostAddress>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QHttpHeaders>
#include <QHttp2Configuration>
#include <QNetworkCookieJar>
// ============================================================
// QHostAddress
// ============================================================
extern "C" VQT6_API void* vqt6_qhostaddress_create(void) {
return new QHostAddress();
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4) {
return new QHostAddress(static_cast<quint32>(ipv4));
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) {
if (address == nullptr) return new QHostAddress();
return new QHostAddress(*static_cast<QString*>(address));
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_host(void) {
return new QHostAddress(QHostAddress::LocalHost);
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void) {
return new QHostAddress(QHostAddress::LocalHostIPv4);
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void) {
return new QHostAddress(QHostAddress::Broadcast);
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void) {
return new QHostAddress(QHostAddress::AnyIPv4);
}
extern "C" VQT6_API void* vqt6_qhostaddress_to_string(void* addr) {
if (addr == nullptr) return nullptr;
return new QString(static_cast<QHostAddress*>(addr)->toString());
}
extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) {
if (addr == nullptr) return 0;
return static_cast<uint32_t>(static_cast<QHostAddress*>(addr)->toIPv4Address());
}
extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) {
if (addr == nullptr) return 0;
return static_cast<QHostAddress*>(addr)->isNull() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) {
if (addr == nullptr) return 0;
return static_cast<QHostAddress*>(addr)->isLoopback() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) {
if (addr == nullptr) return 0;
return static_cast<QHostAddress*>(addr)->isBroadcast() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) {
if (addr == nullptr) return 0;
return static_cast<int>(static_cast<QHostAddress*>(addr)->protocol());
}
extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) {
delete static_cast<QHostAddress*>(addr);
}
// ============================================================
// QAbstractSocket
// ============================================================
extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) {
if (socket == nullptr) return 0;
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->state());
}
extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) {
if (socket == nullptr) return 0;
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->error());
}
extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) {
if (socket == nullptr) return nullptr;
return new QString(static_cast<QAbstractSocket*>(socket)->errorString());
}
extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port) {
if (socket == nullptr || host_name == nullptr) return;
static_cast<QAbstractSocket*>(socket)->connectToHost(*static_cast<QString*>(host_name), port);
}
extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port) {
if (socket == nullptr || address == nullptr) return;
static_cast<QAbstractSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port);
}
extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) {
if (socket == nullptr) return;
static_cast<QAbstractSocket*>(socket)->disconnectFromHost();
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForConnected(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForReadyRead(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForBytesWritten(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForDisconnected(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_is_valid(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->isValid() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->isOpen() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->flush() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) {
if (socket == nullptr) return;
static_cast<QAbstractSocket*>(socket)->close();
}
extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) {
if (socket == nullptr) return;
static_cast<QAbstractSocket*>(socket)->abort();
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size) {
if (socket == nullptr || buf == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->read(static_cast<char*>(buf), static_cast<qint64>(max_size)));
}
extern "C" VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size) {
if (socket == nullptr) return nullptr;
QByteArray ba = static_cast<QAbstractSocket*>(socket)->readAll();
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size) {
if (socket == nullptr || data == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->write(static_cast<const char*>(data), static_cast<qint64>(size)));
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) {
if (socket == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesAvailable());
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) {
if (socket == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesToWrite());
}
extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) {
if (socket == nullptr) return nullptr;
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->peerAddress());
}
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) {
if (socket == nullptr) return 0;
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(socket)->peerPort());
}
extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) {
if (socket == nullptr) return nullptr;
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->localAddress());
}
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) {
if (socket == nullptr) return 0;
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(socket)->localPort());
}
// ============================================================
// QTcpSocket
// ============================================================
extern "C" VQT6_API void* vqt6_qtcpsocket_create(void) {
return new QTcpSocket();
}
extern "C" VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QTcpSocket(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode) {
if (socket == nullptr || host_name == nullptr) return;
static_cast<QTcpSocket*>(socket)->connectToHost(*static_cast<QString*>(host_name), port,
static_cast<QIODevice::OpenMode>(mode));
}
extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode) {
if (socket == nullptr || address == nullptr) return;
static_cast<QTcpSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port,
static_cast<QIODevice::OpenMode>(mode));
}
extern "C" VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor) {
if (socket == nullptr) return 0;
return static_cast<QTcpSocket*>(socket)->setSocketDescriptor(static_cast<qintptr>(socket_descriptor)) ? 1 : 0;
}
extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) {
if (socket == nullptr) return -1;
return static_cast<intptr_t>(static_cast<QTcpSocket*>(socket)->socketDescriptor());
}
extern "C" VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type) {
Q_UNUSED(socket);
Q_UNUSED(proxy_type);
// QNetworkProxy 配置在更高层
}
extern "C" VQT6_API void vqt6_qtcpsocket_abort(void* socket) {
if (socket == nullptr) return;
static_cast<QTcpSocket*>(socket)->abort();
}
// ============================================================
// QUdpSocket
// ============================================================
extern "C" VQT6_API void* vqt6_qudpsocket_create(void) {
return new QUdpSocket();
}
extern "C" VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QUdpSocket(static_cast<QObject*>(parent));
}
extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) {
if (socket == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->bind(port) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port) {
if (socket == nullptr || address == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->bind(*static_cast<QHostAddress*>(address), port) ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) {
if (socket == nullptr) return;
static_cast<QUdpSocket*>(socket)->close();
}
extern "C" VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port) {
if (socket == nullptr || data == nullptr || host == nullptr) return 0;
return static_cast<size_t>(static_cast<QUdpSocket*>(socket)->writeDatagram(
static_cast<const char*>(data), static_cast<qint64>(size),
*static_cast<QHostAddress*>(host), port));
}
extern "C" VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port) {
if (socket == nullptr || data == nullptr) return 0;
QHostAddress sender;
quint16 sender_port = 0;
qint64 n = static_cast<QUdpSocket*>(socket)->readDatagram(
static_cast<char*>(data), static_cast<qint64>(max_size), &sender, &sender_port);
if (host != nullptr) {
QHostAddress* dst = static_cast<QHostAddress*>(host);
*dst = sender;
}
if (port != nullptr) {
*port = sender_port;
}
return static_cast<size_t>(n);
}
extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->hasPendingDatagrams() ? 1 : 0;
}
extern "C" VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket) {
if (socket == nullptr) return 0;
return static_cast<size_t>(static_cast<QUdpSocket*>(socket)->pendingDatagramSize());
}
extern "C" VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address) {
if (socket == nullptr || group_address == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->joinMulticastGroup(*static_cast<QHostAddress*>(group_address)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address) {
if (socket == nullptr || group_address == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->leaveMulticastGroup(*static_cast<QHostAddress*>(group_address)) ? 1 : 0;
}
// ============================================================
// QNetworkRequest
// ============================================================
extern "C" VQT6_API void* vqt6_qnetworkrequest_create(void) {
return new QNetworkRequest();
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url) {
if (url == nullptr) return new QNetworkRequest();
return new QNetworkRequest(QUrl(*static_cast<QString*>(url)));
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) {
if (req == nullptr || url == nullptr) return;
static_cast<QNetworkRequest*>(req)->setUrl(QUrl(*static_cast<QString*>(url)));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) {
if (req == nullptr) return nullptr;
return new QString(static_cast<QNetworkRequest*>(req)->url().toString());
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value) {
if (req == nullptr || value == nullptr) return;
static_cast<QNetworkRequest*>(req)->setHeader(static_cast<QNetworkRequest::KnownHeaders>(header_type),
*static_cast<QVariant*>(value));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) {
if (req == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkRequest*>(req)->header(static_cast<QNetworkRequest::KnownHeaders>(header_type)));
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size) {
if (req == nullptr || header_name == nullptr) return;
static_cast<QNetworkRequest*>(req)->setRawHeader(QByteArray(header_name),
QByteArray(static_cast<const char*>(value), static_cast<int>(value_size)));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size) {
if (req == nullptr || header_name == nullptr) return nullptr;
QByteArray ba = static_cast<QNetworkRequest*>(req)->rawHeader(QByteArray(header_name));
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value) {
if (req == nullptr || value == nullptr) return;
static_cast<QNetworkRequest*>(req)->setAttribute(static_cast<QNetworkRequest::Attribute>(attr_type),
*static_cast<QVariant*>(value));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) {
if (req == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkRequest*>(req)->attribute(static_cast<QNetworkRequest::Attribute>(attr_type)));
}
extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) {
delete static_cast<QNetworkRequest*>(req);
}
// ============================================================
// QNetworkAccessManager
// ============================================================
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create(void) {
return new QNetworkAccessManager();
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QNetworkAccessManager(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) {
if (nam == nullptr || req == nullptr) return nullptr;
return static_cast<QNetworkAccessManager*>(nam)->get(*static_cast<QNetworkRequest*>(req));
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size) {
if (nam == nullptr || req == nullptr) return nullptr;
QByteArray payload;
if (data != nullptr && size > 0) {
payload = QByteArray(static_cast<const char*>(data), static_cast<int>(size));
}
return static_cast<QNetworkAccessManager*>(nam)->post(*static_cast<QNetworkRequest*>(req), payload);
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size) {
if (nam == nullptr || req == nullptr) return nullptr;
QByteArray payload;
if (data != nullptr && size > 0) {
payload = QByteArray(static_cast<const char*>(data), static_cast<int>(size));
}
return static_cast<QNetworkAccessManager*>(nam)->put(*static_cast<QNetworkRequest*>(req), payload);
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req) {
if (nam == nullptr || req == nullptr) return nullptr;
return static_cast<QNetworkAccessManager*>(nam)->deleteResource(*static_cast<QNetworkRequest*>(req));
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) {
if (nam == nullptr || req == nullptr) return nullptr;
return static_cast<QNetworkAccessManager*>(nam)->head(*static_cast<QNetworkRequest*>(req));
}
extern "C" VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store) {
if (nam == nullptr || store == nullptr) return;
QNetworkCookieJar* jar = qobject_cast<QNetworkCookieJar*>(static_cast<QObject*>(store));
if (jar != nullptr) {
static_cast<QNetworkAccessManager*>(nam)->setCookieJar(jar);
}
}
// ============================================================
// QNetworkReply
// ============================================================
extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) {
if (reply == nullptr) return nullptr;
return new QString(static_cast<QNetworkReply*>(reply)->url().toString());
}
extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) {
if (reply == nullptr) return nullptr;
return new QNetworkRequest(static_cast<QNetworkReply*>(reply)->request());
}
extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) {
if (reply == nullptr) return 0;
return static_cast<int>(static_cast<QNetworkReply*>(reply)->error());
}
extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) {
if (reply == nullptr) return nullptr;
return new QString(static_cast<QNetworkReply*>(reply)->errorString());
}
extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) {
if (reply == nullptr) return 0;
return static_cast<QNetworkReply*>(reply)->isFinished() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) {
if (reply == nullptr) return 0;
return static_cast<QNetworkReply*>(reply)->isRunning() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) {
if (reply == nullptr) return;
static_cast<QNetworkReply*>(reply)->abort();
}
extern "C" VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size) {
if (reply == nullptr || buf == nullptr) return 0;
return static_cast<size_t>(static_cast<QNetworkReply*>(reply)->read(static_cast<char*>(buf), static_cast<qint64>(max_size)));
}
extern "C" VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size) {
if (reply == nullptr) return nullptr;
QByteArray ba = static_cast<QNetworkReply*>(reply)->readAll();
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply) {
if (reply == nullptr) return 0;
return static_cast<size_t>(static_cast<QNetworkReply*>(reply)->bytesAvailable());
}
extern "C" VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type) {
if (reply == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkReply*>(reply)->header(static_cast<QNetworkRequest::KnownHeaders>(header_type)));
}
extern "C" VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size) {
if (reply == nullptr || header_name == nullptr) return nullptr;
QByteArray ba = static_cast<QNetworkReply*>(reply)->rawHeader(QByteArray(header_name));
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code) {
if (reply == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(attribute_code)));
}
extern "C" VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value) {
if (reply == nullptr) return default_value;
return static_cast<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(attribute_code)).toInt(default_value);
}
extern "C" VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size) {
if (reply == nullptr || header_name == nullptr) return;
static_cast<QNetworkReply*>(reply)->setRawHeader(QByteArray(header_name),
QByteArray(static_cast<const char*>(value), static_cast<int>(value_size)));
}
+137
View File
@@ -0,0 +1,137 @@
// ============================================================
// vqt6/_bridge_network.h — QtNetwork C 桥接函数声明
// ============================================================
#ifndef VQT6_BRIDGE_NETWORK_H
#define VQT6_BRIDGE_NETWORK_H
#include "_bridge.h"
#ifdef __cplusplus
extern "C" {
#endif
// ============================================================
// QHostAddress
// ============================================================
VQT6_API void* vqt6_qhostaddress_create(void);
VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4);
VQT6_API void* vqt6_qhostaddress_create_with_string(void* address);
VQT6_API void* vqt6_qhostaddress_create_with_local_host(void);
VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void);
VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void);
VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void);
VQT6_API void* vqt6_qhostaddress_to_string(void* addr);
VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr);
VQT6_API int vqt6_qhostaddress_is_null(void* addr);
VQT6_API int vqt6_qhostaddress_is_loopback(void* addr);
VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr);
VQT6_API int vqt6_qhostaddress_protocol(void* addr);
VQT6_API void vqt6_qhostaddress_free(void* addr);
// ============================================================
// QAbstractSocket
// ============================================================
VQT6_API int vqt6_qabstractsocket_state(void* socket);
VQT6_API int vqt6_qabstractsocket_error(void* socket);
VQT6_API void* vqt6_qabstractsocket_error_string(void* socket);
VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port);
VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port);
VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket);
VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_is_valid(void* socket);
VQT6_API int vqt6_qabstractsocket_is_open(void* socket);
VQT6_API int vqt6_qabstractsocket_flush(void* socket);
VQT6_API void vqt6_qabstractsocket_close(void* socket);
VQT6_API void vqt6_qabstractsocket_abort(void* socket);
VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size);
VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size);
VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size);
VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket);
VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket);
VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket);
VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket);
VQT6_API void* vqt6_qabstractsocket_local_address(void* socket);
VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket);
// ============================================================
// QTcpSocket
// ============================================================
VQT6_API void* vqt6_qtcpsocket_create(void);
VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent);
VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode);
VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode);
VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor);
VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket);
VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type);
VQT6_API void vqt6_qtcpsocket_abort(void* socket);
// ============================================================
// QUdpSocket
// ============================================================
VQT6_API void* vqt6_qudpsocket_create(void);
VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent);
VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port);
VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port);
VQT6_API void vqt6_qudpsocket_close(void* socket);
VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port);
VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port);
VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket);
VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket);
VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address);
VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address);
// ============================================================
// QNetworkRequest
// ============================================================
VQT6_API void* vqt6_qnetworkrequest_create(void);
VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url);
VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url);
VQT6_API void* vqt6_qnetworkrequest_url(void* req);
VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value);
VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type);
VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size);
VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size);
VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value);
VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type);
VQT6_API void vqt6_qnetworkrequest_free(void* req);
// ============================================================
// QNetworkAccessManager
// ============================================================
VQT6_API void* vqt6_qnetworkaccessmanager_create(void);
VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent);
VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req);
VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size);
VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size);
VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req);
VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req);
VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store);
// ============================================================
// QNetworkReply
// ============================================================
VQT6_API void* vqt6_qnetworkreply_url(void* reply);
VQT6_API void* vqt6_qnetworkreply_request(void* reply);
VQT6_API int vqt6_qnetworkreply_error(void* reply);
VQT6_API void* vqt6_qnetworkreply_error_string(void* reply);
VQT6_API int vqt6_qnetworkreply_is_finished(void* reply);
VQT6_API int vqt6_qnetworkreply_is_running(void* reply);
VQT6_API void vqt6_qnetworkreply_abort(void* reply);
VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size);
VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size);
VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply);
VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type);
VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size);
VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code);
VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value);
VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size);
#ifdef __cplusplus
}
#endif
#endif // VQT6_BRIDGE_NETWORK_H
File diff suppressed because it is too large. Load diff
+432
View File
@@ -0,0 +1,432 @@
// ============================================================
// vqt6/_bridge_widgets.h — QtWidgets C 桥接函数声明
// ============================================================
#ifndef VQT6_BRIDGE_WIDGETS_H
#define VQT6_BRIDGE_WIDGETS_H
#include "_bridge.h"
#ifdef __cplusplus
extern "C" {
#endif
// ============================================================
// QApplication
// ============================================================
VQT6_API void* vqt6_qapplication_create(int argc, char** argv);
VQT6_API void* vqt6_qapplication_instance(void);
VQT6_API int vqt6_qapplication_exec(void* app);
VQT6_API void vqt6_qapplication_quit(void* app);
VQT6_API void vqt6_qapplication_exit(void* app, int exit_code);
VQT6_API void vqt6_qapplication_process_events(void* app);
VQT6_API int vqt6_qapplication_desktop_width(void* app);
VQT6_API int vqt6_qapplication_desktop_height(void* app);
VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit);
VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app);
// ============================================================
// QWidget
// ============================================================
VQT6_API void* vqt6_qwidget_create(void);
VQT6_API void* vqt6_qwidget_create_with_parent(void* parent);
VQT6_API void vqt6_qwidget_show(void* widget);
VQT6_API void vqt6_qwidget_hide(void* widget);
VQT6_API int vqt6_qwidget_close(void* widget);
VQT6_API int vqt6_qwidget_is_visible(void* widget);
VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible);
VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h);
VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h);
VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h);
VQT6_API void vqt6_qwidget_move(void* widget, int x, int y);
VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y);
VQT6_API int vqt6_qwidget_width(void* widget);
VQT6_API int vqt6_qwidget_height(void* widget);
VQT6_API int vqt6_qwidget_x(void* widget);
VQT6_API int vqt6_qwidget_y(void* widget);
VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title);
VQT6_API void* vqt6_qwidget_window_title(void* widget);
VQT6_API void vqt6_qwidget_set_text(void* widget, void* text);
VQT6_API void* vqt6_qwidget_text(void* widget);
VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled);
VQT6_API int vqt6_qwidget_is_enabled(void* widget);
VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent);
VQT6_API void* vqt6_qwidget_parent_widget(void* widget);
VQT6_API void vqt6_qwidget_set_focus(void* widget);
VQT6_API void vqt6_qwidget_clear_focus(void* widget);
VQT6_API int vqt6_qwidget_has_focus(void* widget);
VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy);
VQT6_API void vqt6_qwidget_update(void* widget);
VQT6_API void vqt6_qwidget_repaint(void* widget);
VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled);
VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags);
VQT6_API int vqt6_qwidget_window_flags(void* widget);
VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor);
VQT6_API void* vqt6_qwidget_cursor(void* widget);
VQT6_API void vqt6_qwidget_unset_cursor(void* widget);
VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip);
VQT6_API void* vqt6_qwidget_tool_tip(void* widget);
VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip);
VQT6_API void* vqt6_qwidget_status_tip(void* widget);
VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h);
VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h);
// ============================================================
// QDialog
// ============================================================
VQT6_API void* vqt6_qdialog_create(void);
VQT6_API void* vqt6_qdialog_create_with_parent(void* parent);
VQT6_API int vqt6_qdialog_exec(void* dialog);
VQT6_API void vqt6_qdialog_done(void* dialog, int result);
VQT6_API void vqt6_qdialog_accept(void* dialog);
VQT6_API void vqt6_qdialog_reject(void* dialog);
VQT6_API void vqt6_qdialog_set_result(void* dialog, int result);
VQT6_API int vqt6_qdialog_result(void* dialog);
VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal);
VQT6_API int vqt6_qdialog_is_modal(void* dialog);
// ============================================================
// QMainWindow
// ============================================================
VQT6_API void* vqt6_qmainwindow_create(void);
VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent);
VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget);
VQT6_API void* vqt6_qmainwindow_central_widget(void* mw);
VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw);
VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar);
VQT6_API void* vqt6_qmainwindow_status_bar(void* mw);
VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar);
VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar);
VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw);
// ============================================================
// QLabel
// ============================================================
VQT6_API void* vqt6_qlabel_create(void);
VQT6_API void* vqt6_qlabel_create_with_text(void* text);
VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qlabel_set_text(void* label, void* text);
VQT6_API void* vqt6_qlabel_text(void* label);
VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment);
VQT6_API int vqt6_qlabel_alignment(void* label);
VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap);
VQT6_API void* vqt6_qlabel_pixmap(void* label);
VQT6_API void vqt6_qlabel_set_indent(void* label, int indent);
VQT6_API void vqt6_qlabel_set_margin(void* label, int margin);
VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap);
VQT6_API int vqt6_qlabel_word_wrap(void* label);
// ============================================================
// QPushButton
// ============================================================
VQT6_API void* vqt6_qpushbutton_create(void);
VQT6_API void* vqt6_qpushbutton_create_with_text(void* text);
VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text);
VQT6_API void* vqt6_qpushbutton_text(void* btn);
VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon);
VQT6_API void* vqt6_qpushbutton_icon(void* btn);
VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default);
VQT6_API int vqt6_qpushbutton_is_default(void* btn);
VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat);
VQT6_API int vqt6_qpushbutton_is_flat(void* btn);
VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable);
VQT6_API int vqt6_qpushbutton_is_checkable(void* btn);
VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked);
VQT6_API int vqt6_qpushbutton_is_checked(void* btn);
VQT6_API void vqt6_qpushbutton_click(void* btn);
// ============================================================
// QLineEdit
// ============================================================
VQT6_API void* vqt6_qlineedit_create(void);
VQT6_API void* vqt6_qlineedit_create_with_text(void* text);
VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent);
VQT6_API void* vqt6_qlineedit_text(void* le);
VQT6_API void vqt6_qlineedit_set_text(void* le, void* text);
VQT6_API void* vqt6_qlineedit_placeholder_text(void* le);
VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text);
VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max);
VQT6_API int vqt6_qlineedit_max_length(void* le);
VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro);
VQT6_API int vqt6_qlineedit_is_read_only(void* le);
VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode);
VQT6_API int vqt6_qlineedit_echo_mode(void* le);
VQT6_API void vqt6_qlineedit_select_all(void* le);
VQT6_API void vqt6_qlineedit_clear(void* le);
// ============================================================
// QTextEdit / QPlainTextEdit
// ============================================================
VQT6_API void* vqt6_qtextedit_create(void);
VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent);
VQT6_API void* vqt6_qtextedit_to_plain_text(void* te);
VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text);
VQT6_API void vqt6_qtextedit_set_html(void* te, void* html);
VQT6_API void* vqt6_qtextedit_to_html(void* te);
VQT6_API void vqt6_qtextedit_append(void* te, void* text);
VQT6_API void vqt6_qtextedit_clear(void* te);
VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro);
VQT6_API int vqt6_qtextedit_is_read_only(void* te);
VQT6_API void* vqt6_qplaintextedit_create(void);
VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent);
VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte);
VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text);
VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text);
VQT6_API void vqt6_qplaintextedit_clear(void* pte);
VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro);
VQT6_API int vqt6_qplaintextedit_line_count(void* pte);
// ============================================================
// QCheckBox / QRadioButton
// ============================================================
VQT6_API void* vqt6_qcheckbox_create(void);
VQT6_API void* vqt6_qcheckbox_create_with_text(void* text);
VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked);
VQT6_API int vqt6_qcheckbox_is_checked(void* cb);
VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text);
VQT6_API void* vqt6_qcheckbox_text(void* cb);
VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate);
VQT6_API int vqt6_qcheckbox_is_tristate(void* cb);
VQT6_API void* vqt6_qradiobutton_create(void);
VQT6_API void* vqt6_qradiobutton_create_with_text(void* text);
VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked);
VQT6_API int vqt6_qradiobutton_is_checked(void* rb);
VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text);
VQT6_API void* vqt6_qradiobutton_text(void* rb);
// ============================================================
// QComboBox
// ============================================================
VQT6_API void* vqt6_qcombobox_create(void);
VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent);
VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text);
VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items);
VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text);
VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index);
VQT6_API void vqt6_qcombobox_clear(void* cb);
VQT6_API int vqt6_qcombobox_count(void* cb);
VQT6_API int vqt6_qcombobox_current_index(void* cb);
VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index);
VQT6_API void* vqt6_qcombobox_current_text(void* cb);
VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index);
VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable);
VQT6_API int vqt6_qcombobox_is_editable(void* cb);
// ============================================================
// QListWidget
// ============================================================
VQT6_API void* vqt6_qlistwidget_create(void);
VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent);
VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text);
VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items);
VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text);
VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row);
VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row);
VQT6_API void vqt6_qlistwidget_clear(void* lw);
VQT6_API int vqt6_qlistwidget_count(void* lw);
VQT6_API int vqt6_qlistwidget_current_row(void* lw);
VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row);
VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw);
VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row);
VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text);
// ============================================================
// QProgressBar
// ============================================================
VQT6_API void* vqt6_qprogressbar_create(void);
VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent);
VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value);
VQT6_API int vqt6_qprogressbar_value(void* pb);
VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min);
VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max);
VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max);
VQT6_API int vqt6_qprogressbar_minimum(void* pb);
VQT6_API int vqt6_qprogressbar_maximum(void* pb);
VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible);
VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format);
VQT6_API void vqt6_qprogressbar_reset(void* pb);
// ============================================================
// QSlider
// ============================================================
VQT6_API void* vqt6_qslider_create(void);
VQT6_API void* vqt6_qslider_create_with_orientation(int orientation);
VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent);
VQT6_API void vqt6_qslider_set_value(void* s, int value);
VQT6_API int vqt6_qslider_value(void* s);
VQT6_API void vqt6_qslider_set_minimum(void* s, int min);
VQT6_API void vqt6_qslider_set_maximum(void* s, int max);
VQT6_API void vqt6_qslider_set_range(void* s, int min, int max);
VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation);
VQT6_API int vqt6_qslider_orientation(void* s);
VQT6_API void vqt6_qslider_set_single_step(void* s, int step);
VQT6_API void vqt6_qslider_set_page_step(void* s, int step);
// ============================================================
// QSpinBox
// ============================================================
VQT6_API void* vqt6_qspinbox_create(void);
VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent);
VQT6_API int vqt6_qspinbox_value(void* sb);
VQT6_API void vqt6_qspinbox_set_value(void* sb, int value);
VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min);
VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max);
VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max);
VQT6_API int vqt6_qspinbox_minimum(void* sb);
VQT6_API int vqt6_qspinbox_maximum(void* sb);
VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step);
VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix);
VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix);
VQT6_API void* vqt6_qspinbox_prefix(void* sb);
VQT6_API void* vqt6_qspinbox_suffix(void* sb);
// ============================================================
// Layouts
// ============================================================
VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget);
VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget);
VQT6_API int vqt6_qlayout_count(void* layout);
VQT6_API void* vqt6_qlayout_item_at(void* layout, int index);
VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom);
VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing);
VQT6_API int vqt6_qlayout_spacing(void* layout);
VQT6_API void vqt6_qlayout_invalidate(void* layout);
VQT6_API void* vqt6_qhboxlayout_create(void);
VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child);
VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch);
VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size);
VQT6_API void* vqt6_qvboxlayout_create(void);
VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child);
VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch);
VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size);
VQT6_API void* vqt6_qgridlayout_create(void);
VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col);
VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span);
VQT6_API void* vqt6_qformlayout_create(void);
VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field);
VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field);
// ============================================================
// QStackedWidget / QTabWidget
// ============================================================
VQT6_API void* vqt6_qstackedwidget_create(void);
VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent);
VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w);
VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w);
VQT6_API int vqt6_qstackedwidget_count(void* sw);
VQT6_API int vqt6_qstackedwidget_current_index(void* sw);
VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index);
VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw);
VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index);
VQT6_API void* vqt6_qtabwidget_create(void);
VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent);
VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label);
VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label);
VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index);
VQT6_API int vqt6_qtabwidget_count(void* tw);
VQT6_API int vqt6_qtabwidget_current_index(void* tw);
VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index);
VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index);
VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text);
VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable);
VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw);
// ============================================================
// QMenuBar / QMenu / QAction
// ============================================================
VQT6_API void* vqt6_qmenubar_create(void);
VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent);
VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title);
VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu);
VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action);
VQT6_API void vqt6_qmenubar_clear(void* mb);
VQT6_API void* vqt6_qmenu_create(void);
VQT6_API void* vqt6_qmenu_create_with_title(void* title);
VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent);
VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title);
VQT6_API void vqt6_qmenu_add_action(void* menu, void* action);
VQT6_API void vqt6_qmenu_add_separator(void* menu);
VQT6_API void vqt6_qmenu_clear(void* menu);
VQT6_API void vqt6_qmenu_set_title(void* menu, void* title);
VQT6_API void* vqt6_qmenu_title(void* menu);
VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text);
VQT6_API void* vqt6_qaction_create(void);
VQT6_API void* vqt6_qaction_create_with_text(void* text);
VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qaction_set_text(void* action, void* text);
VQT6_API void* vqt6_qaction_text(void* action);
VQT6_API void vqt6_qaction_set_icon(void* action, void* icon);
VQT6_API void* vqt6_qaction_icon(void* action);
VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence);
VQT6_API void* vqt6_qaction_shortcut(void* action);
VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable);
VQT6_API int vqt6_qaction_is_checkable(void* action);
VQT6_API void vqt6_qaction_set_checked(void* action, int checked);
VQT6_API int vqt6_qaction_is_checked(void* action);
VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled);
VQT6_API int vqt6_qaction_is_enabled(void* action);
VQT6_API void vqt6_qaction_trigger(void* action);
// ============================================================
// QStatusBar / QToolBar
// ============================================================
VQT6_API void* vqt6_qstatusbar_create(void);
VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent);
VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms);
VQT6_API void vqt6_qstatusbar_clear_message(void* sb);
VQT6_API void* vqt6_qstatusbar_current_message(void* sb);
VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch);
VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch);
VQT6_API void* vqt6_qtoolbar_create(void);
VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent);
VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w);
VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action);
VQT6_API void vqt6_qtoolbar_add_separator(void* tb);
VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h);
VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation);
VQT6_API int vqt6_qtoolbar_orientation(void* tb);
// ============================================================
// QMessageBox
// ============================================================
VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons);
VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons);
VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons);
VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons);
VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text);
VQT6_API void vqt6_qmessagebox_about_qt(void* parent);
// ============================================================
// QFileDialog
// ============================================================
VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter);
VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter);
VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir);
VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter);
#ifdef __cplusplus
}
#endif
#endif // VQT6_BRIDGE_WIDGETS_H
+157
View File
@@ -0,0 +1,157 @@
import t, c
from stdint import *
from vqt6._types import *
# ============================================================
# vqt6/_qtcore.py — QtCore 的 t.State FFI 声明
#
# 所有函数都是 C 桥接层 (libvqt6_bridge.a) 的 extern "C" 函数
# 命名规范: vqt6_<class>_<action>
# ============================================================
# ============================================================
# QString — UTF-16 字符串
# ============================================================
# 创建 QString(从 UTF-8 C 字符串)
def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass
# 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0)
# buf 需足够大(建议 4 * qstring.length() + 1)
def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass
# 释放 QString
def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass
# 获取 QString 字符数
def vqt6_qstring_length(qstr: QtStringPtr) -> t.CInt | t.State: pass
# QString 是否为空
def vqt6_qstring_is_empty(qstr: QtStringPtr) -> t.CInt | t.State: pass
# QString 比较
def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.State: pass
# QString 拼接(返回新 QString)
def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass
# ============================================================
# QByteArray — 字节数组
# ============================================================
def vqt6_qbytearray_create(data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass
def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass
def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass
def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass
# ============================================================
# QObject — 所有 Qt 对象的基类
# ============================================================
# 注意: Qt 对象的内存由 C++ 管理,Viper 端不应直接 free
def vqt6_qobject_delete(obj: QtObjectPtr) -> t.State: pass
def vqt6_qobject_delete_later(obj: QtObjectPtr) -> t.State: pass
def vqt6_qobject_set_object_name(obj: QtObjectPtr, name: QtStringPtr) -> t.State: pass
def vqt6_qobject_object_name(obj: QtObjectPtr) -> QtStringPtr | t.State: pass
def vqt6_qobject_set_parent(child: QtObjectPtr, parent: QtObjectPtr) -> t.State: pass
def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass
# 信号/槽连接 (简化版: 函数指针形式)
# typedef void (*vqt6_callback_t)(void* user_data);
# vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理
# 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表
def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr,
receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass
def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr,
receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass
# 事件过滤器
def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass
def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass
# ============================================================
# QCoreApplication — 事件循环基类
# ============================================================
def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass
def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass
def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass
def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass
def vqt6_qcoreapp_exit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass
def vqt6_qcoreapp_process_events(app: QtCoreAppPtr, flags: t.CInt) -> t.State: pass
def vqt6_qcoreapp_post_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.State: pass
def vqt6_qcoreapp_send_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.CInt | t.State: pass
def vqt6_qcoreapp_organization_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass
def vqt6_qcoreapp_set_organization_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass
def vqt6_qcoreapp_application_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass
def vqt6_qcoreapp_set_application_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass
# ============================================================
# QTimer — 定时器
# ============================================================
def vqt6_qtimer_create() -> QtTimerPtr | t.State: pass
def vqt6_qtimer_create_with_parent(parent: QtObjectPtr) -> QtTimerPtr | t.State: pass
def vqt6_qtimer_start(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass
def vqt6_qtimer_stop(timer: QtTimerPtr) -> t.State: pass
def vqt6_qtimer_set_interval(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass
def vqt6_qtimer_interval(timer: QtTimerPtr) -> t.CInt | t.State: pass
def vqt6_qtimer_is_active(timer: QtTimerPtr) -> t.CInt | t.State: pass
def vqt6_qtimer_set_single_shot(timer: QtTimerPtr, single_shot: t.CInt) -> t.State: pass
def vqt6_qtimer_is_single_shot(timer: QtTimerPtr) -> t.CInt | t.State: pass
# ============================================================
# QVariant — 通用数据容器
# ============================================================
def vqt6_qvariant_create_int(value: t.CInt) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_create_double(value: t.CDouble) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_create_bool(value: t.CInt) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_create_string(s: QtStringPtr) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_to_int(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_to_double(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CDouble | t.State: pass
def vqt6_qvariant_to_bool(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_to_string(v: QtVariantPtr) -> QtStringPtr | t.State: pass
def vqt6_qvariant_type_id(v: QtVariantPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_is_valid(v: QtVariantPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_free(v: QtVariantPtr) -> t.State: pass
# ============================================================
# QEvent — 事件基类
# ============================================================
def vqt6_qevent_type(event: QtEventPtr) -> t.CInt | t.State: pass
def vqt6_qevent_accept(event: QtEventPtr) -> t.State: pass
def vqt6_qevent_ignore(event: QtEventPtr) -> t.State: pass
def vqt6_qevent_is_accepted(event: QtEventPtr) -> t.CInt | t.State: pass
# ============================================================
# 字符串列表 (QStringList / QList<QString>)
# ============================================================
def vqt6_qstringlist_create() -> QtStringListPtr | t.State: pass
def vqt6_qstringlist_append(list: QtStringListPtr, str: QtStringPtr) -> t.State: pass
def vqt6_qstringlist_size(list: QtStringListPtr) -> t.CInt | t.State: pass
def vqt6_qstringlist_at(list: QtStringListPtr, index: t.CInt) -> QtStringPtr | t.State: pass
def vqt6_qstringlist_free(list: QtStringListPtr) -> t.State: pass
# ============================================================
# 字节数组列表 (QList<QByteArray>)
# ============================================================
def vqt6_qbytearraylist_create() -> QtByteArrayListPtr | t.State: pass
def vqt6_qbytearraylist_append(list: QtByteArrayListPtr, qba: QtByteArrayPtr) -> t.State: pass
def vqt6_qbytearraylist_size(list: QtByteArrayListPtr) -> t.CInt | t.State: pass
def vqt6_qbytearraylist_at(list: QtByteArrayListPtr, index: t.CInt) -> QtByteArrayPtr | t.State: pass
def vqt6_qbytearraylist_free(list: QtByteArrayListPtr) -> t.State: pass
# ============================================================
# 全局回调注册表
# ============================================================
# 用于从 C++ 端回调 Viper 代码
# Viper 注册一个 slot 函数(用整数 ID 标识),C++ 在触发信号时通过 ID 查找
# typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data);
def vqt6_register_slot(slot_id: t.CInt, user_data: t.CVoid | t.CPtr) -> t.State: pass
def vqt6_unregister_slot(slot_id: t.CInt) -> t.State: pass
def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用
+237
View File
@@ -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
+184
View File
@@ -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
+478
View File
@@ -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
+186
View File
@@ -0,0 +1,186 @@
import t
from stdint import *
# ============================================================
# vqt6/_types.py — 公共类型定义
#
# Qt6 C++ 类在 Viper 端都是不透明指针 (void*)
# 不暴露 C++ 类的内部布局,只暴露指针
# ============================================================
# 不透明指针 typedef(Qt6 C++ 类的 Viper 端表示)
QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # void* 通用不透明指针
QtStringPtr: t.CTypedef = t.CVoid | t.CPtr # QString*
QtByteArrayPtr: t.CTypedef = t.CVoid | t.CPtr # QByteArray*
QtVariantPtr: t.CTypedef = t.CVoid | t.CPtr # QVariant*
QtObjectListPtr: t.CTypedef = t.CVoid | t.CPtr # QList<QObject*>*
QtStringListPtr: t.CTypedef = t.CVoid | t.CPtr # QStringList*
QtByteArrayListPtr: t.CTypedef = t.CVoid | t.CPtr # QList<QByteArray>*
QtEventPtr: t.CTypedef = t.CVoid | t.CPtr # QEvent*
# QtCore
QtCoreAppPtr: t.CTypedef = t.CVoid | t.CPtr # QCoreApplication*
QtTimerPtr: t.CTypedef = t.CVoid | t.CPtr # QTimer*
QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # QObject*
QtThreadPtr: t.CTypedef = t.CVoid | t.CPtr # QThread*
QtMutexPtr: t.CTypedef = t.CVoid | t.CPtr # QMutex*
QtWaitConditionPtr: t.CTypedef = t.CVoid | t.CPtr # QWaitCondition*
# QtGui
QtColorPtr: t.CTypedef = t.CVoid | t.CPtr # QColor*
QtFontPtr: t.CTypedef = t.CVoid | t.CPtr # QFont*
QtFontMetricsPtr: t.CTypedef = t.CVoid | t.CPtr # QFontMetrics*
QtPixmapPtr: t.CTypedef = t.CVoid | t.CPtr # QPixmap*
QtImagePtr: t.CTypedef = t.CVoid | t.CPtr # QImage*
QtPainterPtr: t.CTypedef = t.CVoid | t.CPtr # QPainter*
QtPenPtr: t.CTypedef = t.CVoid | t.CPtr # QPen*
QtBrushPtr: t.CTypedef = t.CVoid | t.CPtr # QBrush*
QtIconPtr: t.CTypedef = t.CVoid | t.CPtr # QIcon*
QtKeyEventPtr: t.CTypedef = t.CVoid | t.CPtr # QKeyEvent*
QtMouseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QMouseEvent*
QtResizeEventPtr: t.CTypedef = t.CVoid | t.CPtr # QResizeEvent*
QtPaintEventPtr: t.CTypedef = t.CVoid | t.CPtr # QPaintEvent*
QtCloseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QCloseEvent*
QtCursorPtr: t.CTypedef = t.CVoid | t.CPtr # QCursor*
# QtWidgets
QtAppPtr: t.CTypedef = t.CVoid | t.CPtr # QApplication*
QtWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QWidget*
QtDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QDialog*
QtMainWindowPtr: t.CTypedef = t.CVoid | t.CPtr # QMainWindow*
QtLabelPtr: t.CTypedef = t.CVoid | t.CPtr # QLabel*
QtPushButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QPushButton*
QtLineEditPtr: t.CTypedef = t.CVoid | t.CPtr # QLineEdit*
QtTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QTextEdit*
QtPlainTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QPlainTextEdit*
QtCheckBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QCheckBox*
QtRadioButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QRadioButton*
QtComboBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QComboBox*
QtListWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidget*
QtListWidgetItemPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidgetItem*
QtProgressBarPtr: t.CTypedef = t.CVoid | t.CPtr # QProgressBar*
QtSliderPtr: t.CTypedef = t.CVoid | t.CPtr # QSlider*
QtSpinBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QSpinBox*
QtLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QLayout*
QtBoxLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QHBoxLayout / QVBoxLayout*
QtGridLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QGridLayout*
QtFormLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QFormLayout*
QtStackedWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QStackedWidget*
QtTabWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QTabWidget*
QtMenuBarPtr: t.CTypedef = t.CVoid | t.CPtr # QMenuBar*
QtMenuPtr: t.CTypedef = t.CVoid | t.CPtr # QMenu*
QtActionPtr: t.CTypedef = t.CVoid | t.CPtr # QAction*
QtStatusBarPtr: t.CTypedef = t.CVoid | t.CPtr # QStatusBar*
QtToolBarPtr: t.CTypedef = t.CVoid | t.CPtr # QToolBar*
QtMessageBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QMessageBox*
QtFileDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFileDialog*
QtColorDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QColorDialog*
QtFontDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFontDialog*
QtInputDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QInputDialog*
# QtNetwork
QtTcpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QTcpSocket*
QtUdpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QUdpSocket*
QtHostAddressPtr: t.CTypedef = t.CVoid | t.CPtr # QHostAddress*
QtAbstractSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QAbstractSocket*
QtNetworkAccessManagerPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkAccessManager*
QtNetworkReplyPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkReply*
QtNetworkRequestPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkRequest*
# ============================================================
# Qt 通用常量(C++ 枚举值的 C 兼容定义)
# ============================================================
# Qt 键盘按键 (Qt::Key)
QT_KEY_ESCAPE: t.CDefine = 0x01000000
QT_KEY_TAB: t.CDefine = 0x01000001
QT_KEY_BACKTAB: t.CDefine = 0x01000002
QT_KEY_BACKSPACE: t.CDefine = 0x01000003
QT_KEY_RETURN: t.CDefine = 0x01000004
QT_KEY_ENTER: t.CDefine = 0x01000005
QT_KEY_INSERT: t.CDefine = 0x01000006
QT_KEY_DELETE: t.CDefine = 0x01000007
QT_KEY_PAUSE: t.CDefine = 0x01000008
QT_KEY_PRINT: t.CDefine = 0x01000009
QT_KEY_HOME: t.CDefine = 0x01000010
QT_KEY_END: t.CDefine = 0x01000011
QT_KEY_LEFT: t.CDefine = 0x01000012
QT_KEY_UP: t.CDefine = 0x01000013
QT_KEY_RIGHT: t.CDefine = 0x01000014
QT_KEY_DOWN: t.CDefine = 0x01000015
QT_KEY_PAGEUP: t.CDefine = 0x01000016
QT_KEY_PAGEDOWN: t.CDefine = 0x01000017
QT_KEY_SHIFT: t.CDefine = 0x01000020
QT_KEY_CONTROL: t.CDefine = 0x01000021
QT_KEY_META: t.CDefine = 0x01000022
QT_KEY_ALT: t.CDefine = 0x01000023
QT_KEY_F1: t.CDefine = 0x01000030
QT_KEY_F2: t.CDefine = 0x01000031
QT_KEY_F12: t.CDefine = 0x0100003b
QT_KEY_SPACE: t.CDefine = 0x20
QT_KEY_A: t.CDefine = 0x41
QT_KEY_Z: t.CDefine = 0x5a
QT_KEY_0: t.CDefine = 0x30
QT_KEY_9: t.CDefine = 0x39
# Qt 鼠标按键 (Qt::MouseButton)
QT_NO_BUTTON: t.CDefine = 0x00000000
QT_LEFT_BUTTON: t.CDefine = 0x00000001
QT_RIGHT_BUTTON: t.CDefine = 0x00000002
QT_MID_BUTTON: t.CDefine = 0x00000004
# Qt::AlignmentFlag
QT_ALIGN_LEFT: t.CDefine = 0x0001
QT_ALIGN_RIGHT: t.CDefine = 0x0002
QT_ALIGN_HCENTER: t.CDefine = 0x0004
QT_ALIGN_TOP: t.CDefine = 0x0020
QT_ALIGN_BOTTOM: t.CDefine = 0x0040
QT_ALIGN_VCENTER: t.CDefine = 0x0080
QT_ALIGN_CENTER: t.CDefine = QT_ALIGN_HCENTER | QT_ALIGN_VCENTER
# Qt::Orientation
QT_HORIZONTAL: t.CDefine = 0x1
QT_VERTICAL: t.CDefine = 0x2
# Qt 焦点
QT_NO_FOCUS: t.CDefine = 0x00
QT_TAB_FOCUS: t.CDefine = 0x01
QT_CLICK_FOCUS: t.CDefine = 0x02
QT_STRONG_FOCUS: t.CDefine = QT_TAB_FOCUS | QT_CLICK_FOCUS
QT_WHEEL_FOCUS: t.CDefine = 0x04
QT_ALL_FOCUS: t.CDefine = QT_STRONG_FOCUS | QT_WHEEL_FOCUS
# Qt::WindowFlag
QT_WINDOW: t.CDefine = 0x00000001
QT_DIALOG: t.CDefine = 0x00000002 | QT_WINDOW
QT_SHEET: t.CDefine = 0x00000004 | QT_WINDOW
QT_DRAWER: t.CDefine = QT_SHEET | 0x00000008
QT_POPUP: t.CDefine = 0x00000008 | QT_WINDOW
QT_TOOL: t.CDefine = 0x0000000a | QT_WINDOW
QT_TOOLTIP: t.CDefine = 0x0000000c | QT_WINDOW
QT_SPLASH_SCREEN: t.CDefine = 0x0000000e | QT_WINDOW
QT_WINDOW_TITLE: t.CDefine = 0x00000001
QT_WINDOW_SYSTEM_MENU: t.CDefine = 0x00000002
QT_WINDOW_MIN_MAX_BUTTONS: t.CDefine = 0x00000004
QT_WINDOW_CLOSE_BUTTON: t.CDefine = 0x08000000
QT_WINDOW_CONTEXT_HELP_BUTTON: t.CDefine = 0x00000008
# QMessageBox 标准按钮
QT_OK: t.CDefine = 0x00000400
QT_CANCEL: t.CDefine = 0x00400000
QT_YES: t.CDefine = 0x00004000
QT_NO: t.CDefine = 0x00010000
QT_CLOSE: t.CDefine = 0x00200000
# 事件类型
QT_EVENT_NONE: t.CDefine = 0
QT_EVENT_KEY: t.CDefine = 6
QT_EVENT_MOUSE_BUTTON_PRESS: t.CDefine = 2
QT_EVENT_MOUSE_BUTTON_RELEASE: t.CDefine = 3
QT_EVENT_MOUSE_MOVE: t.CDefine = 5
QT_EVENT_PAINT: t.CDefine = 12
QT_EVENT_RESIZE: t.CDefine = 14
QT_EVENT_CLOSE: t.CDefine = 19
QT_EVENT_SHOW: t.CDefine = 17
QT_EVENT_HIDE: t.CDefine = 18
+110
View File
@@ -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()
+90
View File
@@ -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 示例验证
+208
View File
@@ -0,0 +1,208 @@
# ============================================================
# vqt6 — Viper 的 Qt6 绑定包
#
# 公共 Pythonic API(基于 C 桥接层)
# 用户用法:
# import vqt6
# app = vqt6.QApplication([])
# win = vqt6.QWidget()
# win.setWindowTitle("Hello")
# win.show()
# app.exec()
# ============================================================
import t
from stdint import *
from vqt6._types import *
from vqt6._qtcore import *
from vqt6._qtwidgets import *
from vqt6._qtgui import *
from vqt6._qtnetwork import *
# ============================================================
# 高级 API 类(Pythonic 包装,不透明指针)
# ============================================================
@t.NoVTable
class QApplication:
"""QApplication 包装(不透明指针)"""
_ptr: QtAppPtr
def __init__(self, argv: list[str] | t.CPtr):
# 把 argv 转换为 argc/argv 数组
argc: t.CInt = 1
# Viper 端 argv 是 c_char_p 指针数组
# 这里仅传空 argv,避免 C ABI 复杂性
argv_ptr: t.CPtr = t.CPtr(0)
self._ptr = vqt6_qapplication_create(argc, argv_ptr)
if self._ptr is None:
raise RuntimeError("Failed to create QApplication")
def exec(self) -> int:
return vqt6_qapplication_exec(self._ptr)
def quit(self):
vqt6_qapplication_quit(self._ptr)
def exit(self, code: int):
vqt6_qapplication_exit(self._ptr, code)
def process_events(self):
vqt6_qapplication_process_events(self._ptr)
def desktop_width(self) -> int:
return vqt6_qapplication_desktop_width(self._ptr)
def desktop_height(self) -> int:
return vqt6_qapplication_desktop_height(self._ptr)
@t.NoVTable
class QWidget:
"""QWidget 包装"""
_ptr: QtWidgetPtr
def __init__(self, parent: "QWidget | None" = None):
if parent is not None and parent._ptr is not None:
self._ptr = vqt6_qwidget_create_with_parent(parent._ptr)
else:
self._ptr = vqt6_qwidget_create()
if self._ptr is None:
raise RuntimeError("Failed to create QWidget")
def show(self):
vqt6_qwidget_show(self._ptr)
def hide(self):
vqt6_qwidget_hide(self._ptr)
def close(self) -> int:
return vqt6_qwidget_close(self._ptr)
def setWindowTitle(self, title: str):
title_qs: QtStringPtr = vqt6_qstring_create(title)
vqt6_qwidget_set_window_title(self._ptr, title_qs)
vqt6_qstring_free(title_qs)
def windowTitle(self) -> str:
result: QtStringPtr = vqt6_qwidget_window_title(self._ptr)
buf: bytes = stdlib.malloc(1024)
vqt6_qstring_to_utf8(result, buf, 1024)
s: str = string.strndup(buf, 1024)
vqt6_qstring_free(result)
return s
def resize(self, w: int, h: int):
vqt6_qwidget_resize(self._ptr, w, h)
def move(self, x: int, y: int):
vqt6_qwidget_move(self._ptr, x, y)
def setGeometry(self, x: int, y: int, w: int, h: int):
vqt6_qwidget_set_geometry(self._ptr, x, y, w, h)
def setEnabled(self, enabled: int):
vqt6_qwidget_set_enabled(self._ptr, enabled)
def setVisible(self, visible: int):
vqt6_qwidget_set_visible(self._ptr, visible)
def isVisible(self) -> int:
return vqt6_qwidget_is_visible(self._ptr)
def setToolTip(self, tip: str):
tip_qs: QtStringPtr = vqt6_qstring_create(tip)
vqt6_qwidget_set_tool_tip(self._ptr, tip_qs)
vqt6_qstring_free(tip_qs)
@t.NoVTable
class QLabel:
"""QLabel 包装"""
_ptr: QtLabelPtr
def __init__(self, text: str = "", parent: "QWidget | None" = None):
text_qs: QtStringPtr = vqt6_qstring_create(text)
if parent is not None and parent._ptr is not None:
self._ptr = vqt6_qlabel_create_with_text_parent(text_qs, parent._ptr)
elif text_qs is not None:
self._ptr = vqt6_qlabel_create_with_text(text_qs)
else:
self._ptr = vqt6_qlabel_create()
vqt6_qstring_free(text_qs)
if self._ptr is None:
raise RuntimeError("Failed to create QLabel")
def setText(self, text: str):
text_qs: QtStringPtr = vqt6_qstring_create(text)
vqt6_qlabel_set_text(self._ptr, text_qs)
vqt6_qstring_free(text_qs)
def text(self) -> str:
result: QtStringPtr = vqt6_qlabel_text(self._ptr)
buf: bytes = stdlib.malloc(1024)
vqt6_qstring_to_utf8(result, buf, 1024)
s: str = string.strndup(buf, 1024)
vqt6_qstring_free(result)
return s
def setAlignment(self, alignment: int):
vqt6_qlabel_set_alignment(self._ptr, alignment)
@t.NoVTable
class QPushButton:
"""QPushButton 包装"""
_ptr: QtPushButtonPtr
def __init__(self, text: str = "", parent: "QWidget | None" = None):
text_qs: QtStringPtr = vqt6_qstring_create(text)
if parent is not None and parent._ptr is not None:
self._ptr = vqt6_qpushbutton_create_with_text_parent(text_qs, parent._ptr)
elif text_qs is not None:
self._ptr = vqt6_qpushbutton_create_with_text(text_qs)
else:
self._ptr = vqt6_qpushbutton_create()
vqt6_qstring_free(text_qs)
if self._ptr is None:
raise RuntimeError("Failed to create QPushButton")
def setText(self, text: str):
text_qs: QtStringPtr = vqt6_qstring_create(text)
vqt6_qpushbutton_set_text(self._ptr, text_qs)
vqt6_qstring_free(text_qs)
def text(self) -> str:
result: QtStringPtr = vqt6_qpushbutton_text(self._ptr)
buf: bytes = stdlib.malloc(1024)
vqt6_qstring_to_utf8(result, buf, 1024)
s: str = string.strndup(buf, 1024)
vqt6_qstring_free(result)
return s
def click(self):
vqt6_qpushbutton_click(self._ptr)
def setEnabled(self, enabled: int):
vqt6_qwidget_set_enabled(self._ptr, enabled)
# ============================================================
# 模块导出
# ============================================================
__all__ = [
# 高层类
"QApplication", "QWidget", "QLabel", "QPushButton",
# 类型
"QtObjectPtr", "QtStringPtr", "QtByteArrayPtr", "QtWidgetPtr", "QtAppPtr",
"QtLabelPtr", "QtPushButtonPtr",
"QtColorPtr", "QtFontPtr", "QtPixmapPtr", "QtImagePtr", "QtPainterPtr",
"QtTcpSocketPtr", "QtHostAddressPtr", "QtNetworkRequestPtr", "QtNetworkReplyPtr",
# 常量
"QT_KEY_ESCAPE", "QT_KEY_RETURN", "QT_KEY_A", "QT_KEY_Z",
"QT_LEFT_BUTTON", "QT_RIGHT_BUTTON", "QT_MID_BUTTON",
"QT_HORIZONTAL", "QT_VERTICAL",
"QT_ALIGN_LEFT", "QT_ALIGN_CENTER", "QT_ALIGN_RIGHT",
"QT_PORT_HTTP", "QT_PORT_HTTPS", "QT_PORT_FTP",
"QT_OK", "QT_CANCEL", "QT_YES", "QT_NO", "QT_CLOSE",
]
+151
View File
@@ -0,0 +1,151 @@
// ============================================================
// vqt6/_bridge.h — C 桥接层头文件
//
// 作用: 把 Qt6 C++ API 包装成 extern "C" 函数,供 Viper FFI 调用
// 编译: 作为静态库 libvqt6_bridge.a 或动态库 vqt6_bridge.dll
// ============================================================
#ifndef VQT6_BRIDGE_H
#define VQT6_BRIDGE_H
#include <stddef.h>
#include <stdint.h>
#if defined(_WIN32)
# if defined(VQT6_BRIDGE_STATIC)
# define VQT6_API
# elif defined(VQT6_BRIDGE_BUILD)
# define VQT6_API __declspec(dllexport)
# else
# define VQT6_API __declspec(dllimport)
# endif
#else
# if defined(__GNUC__) && (__GNUC__ >= 4)
# define VQT6_API __attribute__((visibility("default")))
# else
# define VQT6_API
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
// ============================================================
// QString
// ============================================================
VQT6_API void* vqt6_qstring_create(const char* utf8);
VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size);
VQT6_API void vqt6_qstring_free(void* qstr);
VQT6_API int vqt6_qstring_length(void* qstr);
VQT6_API int vqt6_qstring_is_empty(void* qstr);
VQT6_API int vqt6_qstring_equals(void* qstr, void* other);
VQT6_API void* vqt6_qstring_append(void* qstr, void* other);
// ============================================================
// QByteArray
// ============================================================
VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size);
VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size);
VQT6_API size_t vqt6_qbytearray_size(void* qba);
VQT6_API void vqt6_qbytearray_free(void* qba);
// ============================================================
// QObject
// ============================================================
VQT6_API void vqt6_qobject_delete(void* obj);
VQT6_API void vqt6_qobject_delete_later(void* obj);
VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name);
VQT6_API void* vqt6_qobject_object_name(void* obj);
VQT6_API void vqt6_qobject_set_parent(void* child, void* parent);
VQT6_API void* vqt6_qobject_parent(void* obj);
VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name,
void* receiver, const char* slot_name);
VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name,
void* receiver, const char* slot_name);
VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter);
VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter);
// ============================================================
// QCoreApplication
// ============================================================
VQT6_API void* vqt6_qcoreapp_create(const char* app_name);
VQT6_API void* vqt6_qcoreapp_instance(void);
VQT6_API int vqt6_qcoreapp_exec(void* app);
VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code);
VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code);
VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags);
VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event);
VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event);
VQT6_API void* vqt6_qcoreapp_organization_name(void* app);
VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name);
VQT6_API void* vqt6_qcoreapp_application_name(void* app);
VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name);
// ============================================================
// QTimer
// ============================================================
VQT6_API void* vqt6_qtimer_create(void);
VQT6_API void* vqt6_qtimer_create_with_parent(void* parent);
VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms);
VQT6_API void vqt6_qtimer_stop(void* timer);
VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms);
VQT6_API int vqt6_qtimer_interval(void* timer);
VQT6_API int vqt6_qtimer_is_active(void* timer);
VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot);
VQT6_API int vqt6_qtimer_is_single_shot(void* timer);
// ============================================================
// QVariant
// ============================================================
VQT6_API void* vqt6_qvariant_create_int(int value);
VQT6_API void* vqt6_qvariant_create_double(double value);
VQT6_API void* vqt6_qvariant_create_bool(int value);
VQT6_API void* vqt6_qvariant_create_string(void* s);
VQT6_API int vqt6_qvariant_to_int(void* v, int* ok);
VQT6_API double vqt6_qvariant_to_double(void* v, int* ok);
VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok);
VQT6_API void* vqt6_qvariant_to_string(void* v);
VQT6_API int vqt6_qvariant_type_id(void* v);
VQT6_API int vqt6_qvariant_is_valid(void* v);
VQT6_API void vqt6_qvariant_free(void* v);
// ============================================================
// QEvent
// ============================================================
VQT6_API int vqt6_qevent_type(void* event);
VQT6_API void vqt6_qevent_accept(void* event);
VQT6_API void vqt6_qevent_ignore(void* event);
VQT6_API int vqt6_qevent_is_accepted(void* event);
// ============================================================
// QStringList
// ============================================================
VQT6_API void* vqt6_qstringlist_create(void);
VQT6_API void vqt6_qstringlist_append(void* list, void* str);
VQT6_API int vqt6_qstringlist_size(void* list);
VQT6_API void* vqt6_qstringlist_at(void* list, int index);
VQT6_API void vqt6_qstringlist_free(void* list);
// ============================================================
// QByteArrayList
// ============================================================
VQT6_API void* vqt6_qbytearraylist_create(void);
VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba);
VQT6_API int vqt6_qbytearraylist_size(void* list);
VQT6_API void* vqt6_qbytearraylist_at(void* list, int index);
VQT6_API void vqt6_qbytearraylist_free(void* list);
// ============================================================
// 全局回调注册表
// ============================================================
typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data);
VQT6_API void vqt6_register_slot(int slot_id, void* user_data);
VQT6_API void vqt6_unregister_slot(int slot_id);
VQT6_API void vqt6_trigger_slot(int slot_id);
#ifdef __cplusplus
}
#endif
#endif // VQT6_BRIDGE_H
+433
View File
@@ -0,0 +1,433 @@
// ============================================================
// vqt6/_bridge_core.cpp — QtCore C 桥接层实现
// ============================================================
#include "_bridge.h"
#include <QString>
#include <QByteArray>
#include <QObject>
#include <QCoreApplication>
#include <QTimer>
#include <QVariant>
#include <QEvent>
#include <QStringList>
#include <QList>
#include <QHash>
#include <QMutex>
#include <cstring>
// 全局回调表(线程安全)
namespace {
QMutex g_slot_mutex;
QHash<int, QPair<vqt6_slot_callback_t, void*>> g_slots;
}
// ============================================================
// QString
// ============================================================
extern "C" VQT6_API void* vqt6_qstring_create(const char* utf8) {
if (utf8 == nullptr) return nullptr;
return new QString(QString::fromUtf8(utf8));
}
extern "C" VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size) {
if (qstr == nullptr || buf == nullptr || buf_size == 0) return 0;
QString* s = static_cast<QString*>(qstr);
QByteArray ba = s->toUtf8();
size_t len = static_cast<size_t>(ba.size());
if (len >= buf_size) len = buf_size - 1;
std::memcpy(buf, ba.constData(), len);
buf[len] = '\0';
return len;
}
extern "C" VQT6_API void vqt6_qstring_free(void* qstr) {
delete static_cast<QString*>(qstr);
}
extern "C" VQT6_API int vqt6_qstring_length(void* qstr) {
if (qstr == nullptr) return 0;
return static_cast<QString*>(qstr)->length();
}
extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) {
if (qstr == nullptr) return 1;
return static_cast<QString*>(qstr)->isEmpty() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qstring_equals(void* qstr, void* other) {
if (qstr == nullptr || other == nullptr) return 0;
return *static_cast<QString*>(qstr) == *static_cast<QString*>(other) ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qstring_append(void* qstr, void* other) {
if (qstr == nullptr || other == nullptr) return nullptr;
return new QString(*static_cast<QString*>(qstr) + *static_cast<QString*>(other));
}
// ============================================================
// QByteArray
// ============================================================
extern "C" VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size) {
if (data == nullptr) return new QByteArray();
return new QByteArray(static_cast<const char*>(data), static_cast<int>(size));
}
extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) {
if (qba == nullptr) return nullptr;
QByteArray* ba = static_cast<QByteArray*>(qba);
if (out_size != nullptr) *out_size = static_cast<size_t>(ba->size());
return ba->data();
}
extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) {
if (qba == nullptr) return 0;
return static_cast<size_t>(static_cast<QByteArray*>(qba)->size());
}
extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) {
delete static_cast<QByteArray*>(qba);
}
// ============================================================
// QObject
// ============================================================
extern "C" VQT6_API void vqt6_qobject_delete(void* obj) {
if (obj == nullptr) return;
delete static_cast<QObject*>(obj);
}
extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) {
if (obj == nullptr) return;
static_cast<QObject*>(obj)->deleteLater();
}
extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) {
if (obj == nullptr || name == nullptr) return;
static_cast<QObject*>(obj)->setObjectName(*static_cast<QString*>(name));
}
extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) {
if (obj == nullptr) return nullptr;
return new QString(static_cast<QObject*>(obj)->objectName());
}
extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) {
if (child == nullptr) return;
static_cast<QObject*>(child)->setParent(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) {
if (obj == nullptr) return nullptr;
return static_cast<QObject*>(obj)->parent();
}
extern "C" VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name,
void* receiver, const char* slot_name) {
if (sender == nullptr || receiver == nullptr || signal_name == nullptr || slot_name == nullptr)
return 0;
return QObject::connect(
static_cast<QObject*>(sender), signal_name,
static_cast<QObject*>(receiver), slot_name
) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name,
void* receiver, const char* slot_name) {
if (sender == nullptr || receiver == nullptr) return 0;
return QObject::disconnect(
static_cast<QObject*>(sender), signal_name,
static_cast<QObject*>(receiver), slot_name
) ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter) {
if (watched == nullptr || filter == nullptr) return;
static_cast<QObject*>(watched)->installEventFilter(static_cast<QObject*>(filter));
}
extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) {
if (watched == nullptr || filter == nullptr) return;
static_cast<QObject*>(watched)->removeEventFilter(static_cast<QObject*>(filter));
}
// ============================================================
// QCoreApplication
// ============================================================
extern "C" VQT6_API void* vqt6_qcoreapp_create(const char* app_name) {
if (app_name == nullptr) return nullptr;
int argc = 1;
static char app_name_copy[1024];
std::strncpy(app_name_copy, app_name, sizeof(app_name_copy) - 1);
app_name_copy[sizeof(app_name_copy) - 1] = '\0';
char* argv[] = { app_name_copy, nullptr };
return new QCoreApplication(argc, argv);
}
extern "C" VQT6_API void* vqt6_qcoreapp_instance(void) {
return QCoreApplication::instance();
}
extern "C" VQT6_API int vqt6_qcoreapp_exec(void* app) {
if (app == nullptr) return -1;
return static_cast<QCoreApplication*>(app)->exec();
}
extern "C" VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code) {
if (app == nullptr) return;
// 优先使用 exit_code 重载
QCoreApplication* a = static_cast<QCoreApplication*>(app);
if (a == QCoreApplication::instance()) {
a->exit(exit_code);
}
}
extern "C" VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code) {
if (app == nullptr) return;
static_cast<QCoreApplication*>(app)->exit(exit_code);
}
extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) {
if (app == nullptr) return;
static_cast<QCoreApplication*>(app)->processEvents(static_cast<QEventLoop::ProcessEventsFlag>(flags));
}
extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) {
if (receiver == nullptr || event == nullptr) return;
QCoreApplication::postEvent(static_cast<QObject*>(receiver), static_cast<QEvent*>(event));
}
extern "C" VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event) {
if (receiver == nullptr || event == nullptr) return 0;
return QCoreApplication::sendEvent(static_cast<QObject*>(receiver), static_cast<QEvent*>(event)) ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qcoreapp_organization_name(void* app) {
if (app == nullptr) return nullptr;
return new QString(QCoreApplication::organizationName());
}
extern "C" VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name) {
if (app == nullptr || name == nullptr) return;
QCoreApplication::setOrganizationName(*static_cast<QString*>(name));
}
extern "C" VQT6_API void* vqt6_qcoreapp_application_name(void* app) {
if (app == nullptr) return nullptr;
return new QString(QCoreApplication::applicationName());
}
extern "C" VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name) {
if (app == nullptr || name == nullptr) return;
QCoreApplication::setApplicationName(*static_cast<QString*>(name));
}
// ============================================================
// QTimer
// ============================================================
extern "C" VQT6_API void* vqt6_qtimer_create(void) {
return new QTimer();
}
extern "C" VQT6_API void* vqt6_qtimer_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QTimer(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->start(interval_ms);
}
extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->stop();
}
extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->setInterval(interval_ms);
}
extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) {
if (timer == nullptr) return 0;
return static_cast<QTimer*>(timer)->interval();
}
extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) {
if (timer == nullptr) return 0;
return static_cast<QTimer*>(timer)->isActive() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot) {
if (timer == nullptr) return;
static_cast<QTimer*>(timer)->setSingleShot(single_shot != 0);
}
extern "C" VQT6_API int vqt6_qtimer_is_single_shot(void* timer) {
if (timer == nullptr) return 0;
return static_cast<QTimer*>(timer)->isSingleShot() ? 1 : 0;
}
// ============================================================
// QVariant
// ============================================================
extern "C" VQT6_API void* vqt6_qvariant_create_int(int value) {
return new QVariant(value);
}
extern "C" VQT6_API void* vqt6_qvariant_create_double(double value) {
return new QVariant(value);
}
extern "C" VQT6_API void* vqt6_qvariant_create_bool(int value) {
return new QVariant(value != 0);
}
extern "C" VQT6_API void* vqt6_qvariant_create_string(void* s) {
if (s == nullptr) return new QVariant();
return new QVariant(*static_cast<QString*>(s));
}
extern "C" VQT6_API int vqt6_qvariant_to_int(void* v, int* ok) {
if (v == nullptr) return 0;
bool bok = false;
int val = static_cast<QVariant*>(v)->toInt(&bok);
if (ok != nullptr) *ok = bok ? 1 : 0;
return val;
}
extern "C" VQT6_API double vqt6_qvariant_to_double(void* v, int* ok) {
if (v == nullptr) return 0.0;
bool bok = false;
double val = static_cast<QVariant*>(v)->toDouble(&bok);
if (ok != nullptr) *ok = bok ? 1 : 0;
return val;
}
extern "C" VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok) {
if (v == nullptr) return 0;
bool bok = false;
bool val = static_cast<QVariant*>(v)->toBool();
if (ok != nullptr) *ok = 1;
return val ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qvariant_to_string(void* v) {
if (v == nullptr) return nullptr;
return new QString(static_cast<QVariant*>(v)->toString());
}
extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) {
if (v == nullptr) return 0;
return static_cast<int>(static_cast<QVariant*>(v)->typeId());
}
extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) {
if (v == nullptr) return 0;
return static_cast<QVariant*>(v)->isValid() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qvariant_free(void* v) {
delete static_cast<QVariant*>(v);
}
// ============================================================
// QEvent
// ============================================================
extern "C" VQT6_API int vqt6_qevent_type(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QEvent*>(event)->type());
}
extern "C" VQT6_API void vqt6_qevent_accept(void* event) {
if (event == nullptr) return;
static_cast<QEvent*>(event)->accept();
}
extern "C" VQT6_API void vqt6_qevent_ignore(void* event) {
if (event == nullptr) return;
static_cast<QEvent*>(event)->ignore();
}
extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) {
if (event == nullptr) return 0;
return static_cast<QEvent*>(event)->isAccepted() ? 1 : 0;
}
// ============================================================
// QStringList
// ============================================================
extern "C" VQT6_API void* vqt6_qstringlist_create(void) {
return new QStringList();
}
extern "C" VQT6_API void vqt6_qstringlist_append(void* list, void* str) {
if (list == nullptr || str == nullptr) return;
static_cast<QStringList*>(list)->append(*static_cast<QString*>(str));
}
extern "C" VQT6_API int vqt6_qstringlist_size(void* list) {
if (list == nullptr) return 0;
return static_cast<QStringList*>(list)->size();
}
extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) {
if (list == nullptr) return nullptr;
QStringList* sl = static_cast<QStringList*>(list);
if (index < 0 || index >= sl->size()) return nullptr;
return new QString(sl->at(index));
}
extern "C" VQT6_API void vqt6_qstringlist_free(void* list) {
delete static_cast<QStringList*>(list);
}
// ============================================================
// QByteArrayList
// ============================================================
extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) {
return new QList<QByteArray>();
}
extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) {
if (list == nullptr || qba == nullptr) return;
static_cast<QList<QByteArray>*>(list)->append(*static_cast<QByteArray*>(qba));
}
extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) {
if (list == nullptr) return 0;
return static_cast<QList<QByteArray>*>(list)->size();
}
extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) {
if (list == nullptr) return nullptr;
QList<QByteArray>* qbl = static_cast<QList<QByteArray>*>(list);
if (index < 0 || index >= qbl->size()) return nullptr;
return new QByteArray(qbl->at(index));
}
extern "C" VQT6_API void vqt6_qbytearraylist_free(void* list) {
delete static_cast<QList<QByteArray>*>(list);
}
// ============================================================
// 全局回调注册表
// ============================================================
extern "C" VQT6_API void vqt6_register_slot(int slot_id, void* user_data) {
QMutexLocker locker(&g_slot_mutex);
g_slots.insert(slot_id, QPair<vqt6_slot_callback_t, void*>(nullptr, user_data));
}
extern "C" VQT6_API void vqt6_unregister_slot(int slot_id) {
QMutexLocker locker(&g_slot_mutex);
g_slots.remove(slot_id);
}
extern "C" VQT6_API void vqt6_trigger_slot(int slot_id) {
QMutexLocker locker(&g_slot_mutex);
auto it = g_slots.find(slot_id);
if (it != g_slots.end() && it.value().first != nullptr) {
it.value().first(slot_id, it.value().second);
}
}
+868
View File
@@ -0,0 +1,868 @@
// ============================================================
// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现
// ============================================================
#include "_bridge.h"
#include "_bridge_gui.h"
#include <QColor>
#include <QFont>
#include <QFontMetrics>
#include <QPixmap>
#include <QImage>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QIcon>
#include <QCursor>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QPaintEvent>
#include <QCloseEvent>
#include <QPainterPath>
#include <QPolygon>
#include <QPoint>
#include <QPointF>
#include <QRect>
#include <QRectF>
#include <QGuiApplication>
#include <QScreen>
#include <QImageReader>
#include <QBuffer>
#include <QStyle>
#include <QStringList>
// ============================================================
// QColor
// ============================================================
extern "C" VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b) {
return new QColor(r, g, b);
}
extern "C" VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a) {
return new QColor(r, g, b, a);
}
extern "C" VQT6_API void* vqt6_qcolor_create_name(void* name) {
if (name == nullptr) return new QColor();
return new QColor(*static_cast<QString*>(name));
}
extern "C" VQT6_API void* vqt6_qcolor_create_hex(void* hex_str) {
if (hex_str == nullptr) return new QColor();
return new QColor(*static_cast<QString*>(hex_str));
}
extern "C" VQT6_API int vqt6_qcolor_red(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->red();
}
extern "C" VQT6_API int vqt6_qcolor_green(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->green();
}
extern "C" VQT6_API int vqt6_qcolor_blue(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->blue();
}
extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) {
if (c == nullptr) return 255;
return static_cast<QColor*>(c)->alpha();
}
extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setRed(r);
}
extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setGreen(g);
}
extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setBlue(b);
}
extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setAlpha(a);
}
extern "C" VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setRgb(r, g, b);
}
extern "C" VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a) {
if (c == nullptr) return;
static_cast<QColor*>(c)->setRgba(r, g, b, a);
}
extern "C" VQT6_API void* vqt6_qcolor_name(void* c) {
if (c == nullptr) return nullptr;
return new QString(static_cast<QColor*>(c)->name());
}
extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) {
if (c == nullptr) return 0;
return static_cast<QColor*>(c)->isValid() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qcolor_free(void* c) {
delete static_cast<QColor*>(c);
}
// ============================================================
// QFont
// ============================================================
extern "C" VQT6_API void* vqt6_qfont_create(void) {
return new QFont();
}
extern "C" VQT6_API void* vqt6_qfont_create_with_family(void* family) {
if (family == nullptr) return new QFont();
return new QFont(*static_cast<QString*>(family));
}
extern "C" VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size) {
if (family == nullptr) return new QFont();
return new QFont(*static_cast<QString*>(family), point_size);
}
extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) {
if (font == nullptr || family == nullptr) return;
static_cast<QFont*>(font)->setFamily(*static_cast<QString*>(family));
}
extern "C" VQT6_API void* vqt6_qfont_family(void* font) {
if (font == nullptr) return nullptr;
return new QString(static_cast<QFont*>(font)->family());
}
extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setPointSize(point_size);
}
extern "C" VQT6_API int vqt6_qfont_point_size(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->pointSize();
}
extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setPixelSize(pixel_size);
}
extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->pixelSize();
}
extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setBold(bold != 0);
}
extern "C" VQT6_API int vqt6_qfont_bold(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->bold() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setItalic(italic != 0);
}
extern "C" VQT6_API int vqt6_qfont_italic(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->italic() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setUnderline(underline != 0);
}
extern "C" VQT6_API int vqt6_qfont_underline(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->underline() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setStrikeOut(strike_out != 0);
}
extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) {
if (font == nullptr) return 0;
return static_cast<QFont*>(font)->strikeOut() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) {
if (font == nullptr) return;
static_cast<QFont*>(font)->setWeight(static_cast<QFont::Weight>(weight));
}
extern "C" VQT6_API int vqt6_qfont_weight(void* font) {
if (font == nullptr) return 0;
return static_cast<int>(static_cast<QFont*>(font)->weight());
}
extern "C" VQT6_API void vqt6_qfont_free(void* font) {
delete static_cast<QFont*>(font);
}
// ============================================================
// QFontMetrics
// ============================================================
extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) {
if (font == nullptr) return nullptr;
return new QFontMetrics(*static_cast<QFont*>(font));
}
extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) {
if (fm == nullptr || text == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->horizontalAdvance(*static_cast<QString*>(text));
}
extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) {
if (fm == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->height();
}
extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) {
if (fm == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->ascent();
}
extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) {
if (fm == nullptr) return 0;
return static_cast<QFontMetrics*>(fm)->descent();
}
extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) {
delete static_cast<QFontMetrics*>(fm);
}
// ============================================================
// QPixmap
// ============================================================
extern "C" VQT6_API void* vqt6_qpixmap_create(void) {
return new QPixmap();
}
extern "C" VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h) {
return new QPixmap(w, h);
}
extern "C" VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name) {
if (pm == nullptr || file_name == nullptr) return 0;
return static_cast<QPixmap*>(pm)->load(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size) {
if (pm == nullptr || data == nullptr) return 0;
return static_cast<QPixmap*>(pm)->loadFromData(static_cast<const uchar*>(data), static_cast<uint>(size)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name) {
if (pm == nullptr || file_name == nullptr) return 0;
return static_cast<QPixmap*>(pm)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) {
if (pm == nullptr) return 0;
return static_cast<QPixmap*>(pm)->width();
}
extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) {
if (pm == nullptr) return 0;
return static_cast<QPixmap*>(pm)->height();
}
extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) {
if (pm == nullptr) return 0;
return static_cast<QPixmap*>(pm)->isNull() ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h) {
if (pm == nullptr) return nullptr;
return new QPixmap(static_cast<QPixmap*>(pm)->scaled(w, h));
}
extern "C" VQT6_API void vqt6_qpixmap_fill(void* pm, void* color) {
if (pm == nullptr) return;
if (color != nullptr) {
static_cast<QPixmap*>(pm)->fill(*static_cast<QColor*>(color));
} else {
static_cast<QPixmap*>(pm)->fill();
}
}
extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) {
delete static_cast<QPixmap*>(pm);
}
// ============================================================
// QImage
// ============================================================
extern "C" VQT6_API void* vqt6_qimage_create(void) {
return new QImage();
}
extern "C" VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format) {
return new QImage(w, h, static_cast<QImage::Format>(format));
}
extern "C" VQT6_API int vqt6_qimage_load(void* img, void* file_name) {
if (img == nullptr || file_name == nullptr) return 0;
return static_cast<QImage*>(img)->load(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qimage_save(void* img, void* file_name) {
if (img == nullptr || file_name == nullptr) return 0;
return static_cast<QImage*>(img)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qimage_width(void* img) {
if (img == nullptr) return 0;
return static_cast<QImage*>(img)->width();
}
extern "C" VQT6_API int vqt6_qimage_height(void* img) {
if (img == nullptr) return 0;
return static_cast<QImage*>(img)->height();
}
extern "C" VQT6_API int vqt6_qimage_format(void* img) {
if (img == nullptr) return 0;
return static_cast<int>(static_cast<QImage*>(img)->format());
}
extern "C" VQT6_API int vqt6_qimage_is_null(void* img) {
if (img == nullptr) return 0;
return static_cast<QImage*>(img)->isNull() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qimage_fill(void* img, void* color) {
if (img == nullptr) return;
if (color != nullptr) {
static_cast<QImage*>(img)->fill(*static_cast<QColor*>(color));
}
}
extern "C" VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h) {
if (img == nullptr) return nullptr;
return new QImage(static_cast<QImage*>(img)->scaled(w, h));
}
extern "C" VQT6_API void vqt6_qimage_free(void* img) {
delete static_cast<QImage*>(img);
}
// ============================================================
// QPainter
// ============================================================
extern "C" VQT6_API void* vqt6_qpainter_create(void) {
return new QPainter();
}
extern "C" VQT6_API int vqt6_qpainter_begin(void* p, void* device) {
if (p == nullptr || device == nullptr) return 0;
return static_cast<QPainter*>(p)->begin(static_cast<QPixmap*>(device)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpainter_end(void* p) {
if (p == nullptr) return 0;
return static_cast<QPainter*>(p)->end() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) {
if (p == nullptr) return 0;
return static_cast<QPainter*>(p)->isActive() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen) {
if (p == nullptr || pen == nullptr) return;
static_cast<QPainter*>(p)->setPen(*static_cast<QPen*>(pen));
}
extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) {
if (p == nullptr || brush == nullptr) return;
static_cast<QPainter*>(p)->setBrush(*static_cast<QBrush*>(brush));
}
extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) {
if (p == nullptr || font == nullptr) return;
static_cast<QPainter*>(p)->setFont(*static_cast<QFont*>(font));
}
extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) {
if (p == nullptr) return nullptr;
return new QPen(static_cast<QPainter*>(p)->pen());
}
extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) {
if (p == nullptr) return nullptr;
return new QBrush(static_cast<QPainter*>(p)->brush());
}
extern "C" VQT6_API void* vqt6_qpainter_font(void* p) {
if (p == nullptr) return nullptr;
return new QFont(static_cast<QPainter*>(p)->font());
}
extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->setOpacity(opacity);
}
extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) {
if (p == nullptr) return 1.0;
return static_cast<QPainter*>(p)->opacity();
}
extern "C" VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawLine(x1, y1, x2, y2);
}
extern "C" VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawRect(x, y, w, h);
}
extern "C" VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color) {
if (p == nullptr || color == nullptr) return;
static_cast<QPainter*>(p)->fillRect(x, y, w, h, *static_cast<QColor*>(color));
}
extern "C" VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawEllipse(x, y, w, h);
}
extern "C" VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawArc(x, y, w, h, start_angle, span_angle);
}
extern "C" VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawChord(x, y, w, h, start_angle, span_angle);
}
extern "C" VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawPie(x, y, w, h, start_angle, span_angle);
}
extern "C" VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count) {
if (p == nullptr || points == nullptr || point_count < 1) return;
QPolygon polygon;
for (int i = 0; i < point_count; ++i) {
polygon << QPoint(points[i*2], points[i*2+1]);
}
static_cast<QPainter*>(p)->drawPolygon(polygon);
}
extern "C" VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count) {
if (p == nullptr || points == nullptr || point_count < 1) return;
QPolygon polyline;
for (int i = 0; i < point_count; ++i) {
polyline << QPoint(points[i*2], points[i*2+1]);
}
static_cast<QPainter*>(p)->drawPolyline(polyline);
}
extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->drawPoint(x, y);
}
extern "C" VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count) {
if (p == nullptr || points == nullptr || point_count < 1) return;
QPolygon pts;
for (int i = 0; i < point_count; ++i) {
pts << QPoint(points[i*2], points[i*2+1]);
}
static_cast<QPainter*>(p)->drawPoints(pts);
}
extern "C" VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text) {
if (p == nullptr || text == nullptr) return;
static_cast<QPainter*>(p)->drawText(x, y, *static_cast<QString*>(text));
}
extern "C" VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text) {
if (p == nullptr || text == nullptr) return;
static_cast<QPainter*>(p)->drawText(x, y, w, h, flags, *static_cast<QString*>(text));
}
extern "C" VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap) {
if (p == nullptr || pixmap == nullptr) return;
static_cast<QPainter*>(p)->drawPixmap(x, y, *static_cast<QPixmap*>(pixmap));
}
extern "C" VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image) {
if (p == nullptr || image == nullptr) return;
static_cast<QPainter*>(p)->drawImage(x, y, *static_cast<QImage*>(image));
}
extern "C" VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap) {
if (p == nullptr || pixmap == nullptr) return;
static_cast<QPainter*>(p)->drawTiledPixmap(x, y, w, h, *static_cast<QPixmap*>(pixmap));
}
extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->translate(dx, dy);
}
extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->rotate(angle);
}
extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->scale(sx, sy);
}
extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->resetTransform();
}
extern "C" VQT6_API void vqt6_qpainter_save(void* p) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->save();
}
extern "C" VQT6_API void vqt6_qpainter_restore(void* p) {
if (p == nullptr) return;
static_cast<QPainter*>(p)->restore();
}
extern "C" VQT6_API void vqt6_qpainter_free(void* p) {
delete static_cast<QPainter*>(p);
}
// ============================================================
// QPen
// ============================================================
extern "C" VQT6_API void* vqt6_qpen_create(void) {
return new QPen();
}
extern "C" VQT6_API void* vqt6_qpen_create_with_color(void* color) {
if (color == nullptr) return new QPen();
return new QPen(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width) {
if (color == nullptr) return new QPen();
return new QPen(*static_cast<QColor*>(color), width);
}
extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) {
if (pen == nullptr || color == nullptr) return;
static_cast<QPen*>(pen)->setColor(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qpen_color(void* pen) {
if (pen == nullptr) return nullptr;
return new QColor(static_cast<QPen*>(pen)->color());
}
extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) {
if (pen == nullptr) return;
static_cast<QPen*>(pen)->setWidth(width);
}
extern "C" VQT6_API int vqt6_qpen_width(void* pen) {
if (pen == nullptr) return 0;
return static_cast<QPen*>(pen)->width();
}
extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) {
if (pen == nullptr) return;
static_cast<QPen*>(pen)->setStyle(static_cast<Qt::PenStyle>(style));
}
extern "C" VQT6_API int vqt6_qpen_style(void* pen) {
if (pen == nullptr) return 0;
return static_cast<int>(static_cast<QPen*>(pen)->style());
}
extern "C" VQT6_API void vqt6_qpen_free(void* pen) {
delete static_cast<QPen*>(pen);
}
// ============================================================
// QBrush
// ============================================================
extern "C" VQT6_API void* vqt6_qbrush_create(void) {
return new QBrush();
}
extern "C" VQT6_API void* vqt6_qbrush_create_with_color(void* color) {
if (color == nullptr) return new QBrush();
return new QBrush(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) {
return new QBrush(static_cast<Qt::BrushStyle>(style));
}
extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) {
if (brush == nullptr || color == nullptr) return;
static_cast<QBrush*>(brush)->setColor(*static_cast<QColor*>(color));
}
extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) {
if (brush == nullptr) return nullptr;
return new QColor(static_cast<QBrush*>(brush)->color());
}
extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) {
if (brush == nullptr) return;
static_cast<QBrush*>(brush)->setStyle(static_cast<Qt::BrushStyle>(style));
}
extern "C" VQT6_API int vqt6_qbrush_style(void* brush) {
if (brush == nullptr) return 0;
return static_cast<int>(static_cast<QBrush*>(brush)->style());
}
extern "C" VQT6_API void vqt6_qbrush_free(void* brush) {
delete static_cast<QBrush*>(brush);
}
// ============================================================
// QIcon
// ============================================================
extern "C" VQT6_API void* vqt6_qicon_create(void) {
return new QIcon();
}
extern "C" VQT6_API void* vqt6_qicon_create_with_file(void* file_name) {
if (file_name == nullptr) return new QIcon();
return new QIcon(*static_cast<QString*>(file_name));
}
extern "C" VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name) {
if (icon == nullptr || file_name == nullptr) return;
static_cast<QIcon*>(icon)->addFile(*static_cast<QString*>(file_name));
}
extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) {
if (icon == nullptr || pixmap == nullptr) return;
static_cast<QIcon*>(icon)->addPixmap(*static_cast<QPixmap*>(pixmap));
}
extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) {
if (icon == nullptr) return 0;
return static_cast<QIcon*>(icon)->isNull() ? 1 : 0;
}
extern "C" VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h) {
if (icon == nullptr) return nullptr;
return new QPixmap(static_cast<QIcon*>(icon)->pixmap(w, h));
}
extern "C" VQT6_API void vqt6_qicon_free(void* icon) {
delete static_cast<QIcon*>(icon);
}
// ============================================================
// QCursor
// ============================================================
extern "C" VQT6_API void* vqt6_qcursor_create(void) {
return new QCursor();
}
extern "C" VQT6_API void* vqt6_qcursor_create_with_shape(int shape) {
return new QCursor(static_cast<Qt::CursorShape>(shape));
}
extern "C" VQT6_API void vqt6_qcursor_pos(int* x, int* y) {
QPoint p = QCursor::pos();
if (x != nullptr) *x = p.x();
if (y != nullptr) *y = p.y();
}
extern "C" VQT6_API void vqt6_qcursor_set_pos(int x, int y) {
QCursor::setPos(x, y);
}
extern "C" VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape) {
if (cursor == nullptr) return;
static_cast<QCursor*>(cursor)->setShape(static_cast<Qt::CursorShape>(shape));
}
extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) {
if (cursor == nullptr) return 0;
return static_cast<int>(static_cast<QCursor*>(cursor)->shape());
}
extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) {
delete static_cast<QCursor*>(cursor);
}
// ============================================================
// QKeyEvent
// ============================================================
extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) {
QString* t = static_cast<QString*>(text);
return new QKeyEvent(static_cast<QEvent::Type>(type), key, static_cast<Qt::KeyboardModifiers>(modifiers),
t != nullptr ? *t : QString());
}
extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) {
if (event == nullptr) return 0;
return static_cast<QKeyEvent*>(event)->key();
}
extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) {
if (event == nullptr) return nullptr;
return new QString(static_cast<QKeyEvent*>(event)->text());
}
extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QKeyEvent*>(event)->modifiers());
}
extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) {
if (event == nullptr) return 0;
return static_cast<QKeyEvent*>(event)->isAutoRepeat() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) {
delete static_cast<QKeyEvent*>(event);
}
// ============================================================
// QMouseEvent
// ============================================================
extern "C" VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers) {
QPointF* lp = static_cast<QPointF*>(local_pos);
return new QMouseEvent(
static_cast<QEvent::Type>(type),
lp != nullptr ? *lp : QPointF(0, 0),
Qt::NoButton,
static_cast<Qt::MouseButton>(button),
static_cast<Qt::KeyboardModifiers>(modifiers)
);
}
extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->button());
}
extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->buttons());
}
extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().x());
}
extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().y());
}
extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().x());
}
extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().y());
}
extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) {
if (event == nullptr) return 0;
return static_cast<int>(static_cast<QMouseEvent*>(event)->modifiers());
}
extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) {
delete static_cast<QMouseEvent*>(event);
}
// ============================================================
// QResizeEvent / QPaintEvent / QCloseEvent
// ============================================================
extern "C" VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height) {
return new QResizeEvent(QSize(width, height), QSize(old_width, old_height));
}
extern "C" VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h) {
if (event == nullptr) return;
QSize s = static_cast<QResizeEvent*>(event)->size();
if (w != nullptr) *w = s.width();
if (h != nullptr) *h = s.height();
}
extern "C" VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h) {
if (event == nullptr) return;
QSize s = static_cast<QResizeEvent*>(event)->oldSize();
if (w != nullptr) *w = s.width();
if (h != nullptr) *h = s.height();
}
extern "C" VQT6_API void vqt6_qresizeevent_free(void* event) {
delete static_cast<QResizeEvent*>(event);
}
extern "C" VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h) {
return new QPaintEvent(QRect(rect_x, rect_y, rect_w, rect_h));
}
extern "C" VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h) {
if (event == nullptr) return;
QRect r = static_cast<QPaintEvent*>(event)->rect();
if (x != nullptr) *x = r.x();
if (y != nullptr) *y = r.y();
if (w != nullptr) *w = r.width();
if (h != nullptr) *h = r.height();
}
extern "C" VQT6_API void vqt6_qpaintevent_free(void* event) {
delete static_cast<QPaintEvent*>(event);
}
extern "C" VQT6_API void* vqt6_qcloseevent_create(void) {
return new QCloseEvent();
}
extern "C" VQT6_API int vqt6_qcloseevent_is_accepted(void* event) {
if (event == nullptr) return 0;
return static_cast<QCloseEvent*>(event)->isAccepted() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) {
if (event == nullptr) return;
static_cast<QCloseEvent*>(event)->accept();
}
extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) {
if (event == nullptr) return;
static_cast<QCloseEvent*>(event)->ignore();
}
extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) {
delete static_cast<QCloseEvent*>(event);
}
+231
View File
@@ -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
+519
View File
@@ -0,0 +1,519 @@
// ============================================================
// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现
// ============================================================
#include "_bridge.h"
#include "_bridge_network.h"
#include <QHostAddress>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QHttpHeaders>
#include <QHttp2Configuration>
#include <QNetworkCookieJar>
// ============================================================
// QHostAddress
// ============================================================
extern "C" VQT6_API void* vqt6_qhostaddress_create(void) {
return new QHostAddress();
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4) {
return new QHostAddress(static_cast<quint32>(ipv4));
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) {
if (address == nullptr) return new QHostAddress();
return new QHostAddress(*static_cast<QString*>(address));
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_host(void) {
return new QHostAddress(QHostAddress::LocalHost);
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void) {
return new QHostAddress(QHostAddress::LocalHostIPv4);
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void) {
return new QHostAddress(QHostAddress::Broadcast);
}
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void) {
return new QHostAddress(QHostAddress::AnyIPv4);
}
extern "C" VQT6_API void* vqt6_qhostaddress_to_string(void* addr) {
if (addr == nullptr) return nullptr;
return new QString(static_cast<QHostAddress*>(addr)->toString());
}
extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) {
if (addr == nullptr) return 0;
return static_cast<uint32_t>(static_cast<QHostAddress*>(addr)->toIPv4Address());
}
extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) {
if (addr == nullptr) return 0;
return static_cast<QHostAddress*>(addr)->isNull() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) {
if (addr == nullptr) return 0;
return static_cast<QHostAddress*>(addr)->isLoopback() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) {
if (addr == nullptr) return 0;
return static_cast<QHostAddress*>(addr)->isBroadcast() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) {
if (addr == nullptr) return 0;
return static_cast<int>(static_cast<QHostAddress*>(addr)->protocol());
}
extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) {
delete static_cast<QHostAddress*>(addr);
}
// ============================================================
// QAbstractSocket
// ============================================================
extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) {
if (socket == nullptr) return 0;
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->state());
}
extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) {
if (socket == nullptr) return 0;
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->error());
}
extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) {
if (socket == nullptr) return nullptr;
return new QString(static_cast<QAbstractSocket*>(socket)->errorString());
}
extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port) {
if (socket == nullptr || host_name == nullptr) return;
static_cast<QAbstractSocket*>(socket)->connectToHost(*static_cast<QString*>(host_name), port);
}
extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port) {
if (socket == nullptr || address == nullptr) return;
static_cast<QAbstractSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port);
}
extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) {
if (socket == nullptr) return;
static_cast<QAbstractSocket*>(socket)->disconnectFromHost();
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForConnected(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForReadyRead(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForBytesWritten(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->waitForDisconnected(timeout_ms) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_is_valid(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->isValid() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->isOpen() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QAbstractSocket*>(socket)->flush() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) {
if (socket == nullptr) return;
static_cast<QAbstractSocket*>(socket)->close();
}
extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) {
if (socket == nullptr) return;
static_cast<QAbstractSocket*>(socket)->abort();
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size) {
if (socket == nullptr || buf == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->read(static_cast<char*>(buf), static_cast<qint64>(max_size)));
}
extern "C" VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size) {
if (socket == nullptr) return nullptr;
QByteArray ba = static_cast<QAbstractSocket*>(socket)->readAll();
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size) {
if (socket == nullptr || data == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->write(static_cast<const char*>(data), static_cast<qint64>(size)));
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) {
if (socket == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesAvailable());
}
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) {
if (socket == nullptr) return 0;
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesToWrite());
}
extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) {
if (socket == nullptr) return nullptr;
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->peerAddress());
}
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) {
if (socket == nullptr) return 0;
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(socket)->peerPort());
}
extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) {
if (socket == nullptr) return nullptr;
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->localAddress());
}
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) {
if (socket == nullptr) return 0;
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(socket)->localPort());
}
// ============================================================
// QTcpSocket
// ============================================================
extern "C" VQT6_API void* vqt6_qtcpsocket_create(void) {
return new QTcpSocket();
}
extern "C" VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QTcpSocket(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode) {
if (socket == nullptr || host_name == nullptr) return;
static_cast<QTcpSocket*>(socket)->connectToHost(*static_cast<QString*>(host_name), port,
static_cast<QIODevice::OpenMode>(mode));
}
extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode) {
if (socket == nullptr || address == nullptr) return;
static_cast<QTcpSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port,
static_cast<QIODevice::OpenMode>(mode));
}
extern "C" VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor) {
if (socket == nullptr) return 0;
return static_cast<QTcpSocket*>(socket)->setSocketDescriptor(static_cast<qintptr>(socket_descriptor)) ? 1 : 0;
}
extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) {
if (socket == nullptr) return -1;
return static_cast<intptr_t>(static_cast<QTcpSocket*>(socket)->socketDescriptor());
}
extern "C" VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type) {
Q_UNUSED(socket);
Q_UNUSED(proxy_type);
// QNetworkProxy 配置在更高层
}
extern "C" VQT6_API void vqt6_qtcpsocket_abort(void* socket) {
if (socket == nullptr) return;
static_cast<QTcpSocket*>(socket)->abort();
}
// ============================================================
// QUdpSocket
// ============================================================
extern "C" VQT6_API void* vqt6_qudpsocket_create(void) {
return new QUdpSocket();
}
extern "C" VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QUdpSocket(static_cast<QObject*>(parent));
}
extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) {
if (socket == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->bind(port) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port) {
if (socket == nullptr || address == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->bind(*static_cast<QHostAddress*>(address), port) ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) {
if (socket == nullptr) return;
static_cast<QUdpSocket*>(socket)->close();
}
extern "C" VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port) {
if (socket == nullptr || data == nullptr || host == nullptr) return 0;
return static_cast<size_t>(static_cast<QUdpSocket*>(socket)->writeDatagram(
static_cast<const char*>(data), static_cast<qint64>(size),
*static_cast<QHostAddress*>(host), port));
}
extern "C" VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port) {
if (socket == nullptr || data == nullptr) return 0;
QHostAddress sender;
quint16 sender_port = 0;
qint64 n = static_cast<QUdpSocket*>(socket)->readDatagram(
static_cast<char*>(data), static_cast<qint64>(max_size), &sender, &sender_port);
if (host != nullptr) {
QHostAddress* dst = static_cast<QHostAddress*>(host);
*dst = sender;
}
if (port != nullptr) {
*port = sender_port;
}
return static_cast<size_t>(n);
}
extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) {
if (socket == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->hasPendingDatagrams() ? 1 : 0;
}
extern "C" VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket) {
if (socket == nullptr) return 0;
return static_cast<size_t>(static_cast<QUdpSocket*>(socket)->pendingDatagramSize());
}
extern "C" VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address) {
if (socket == nullptr || group_address == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->joinMulticastGroup(*static_cast<QHostAddress*>(group_address)) ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address) {
if (socket == nullptr || group_address == nullptr) return 0;
return static_cast<QUdpSocket*>(socket)->leaveMulticastGroup(*static_cast<QHostAddress*>(group_address)) ? 1 : 0;
}
// ============================================================
// QNetworkRequest
// ============================================================
extern "C" VQT6_API void* vqt6_qnetworkrequest_create(void) {
return new QNetworkRequest();
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url) {
if (url == nullptr) return new QNetworkRequest();
return new QNetworkRequest(QUrl(*static_cast<QString*>(url)));
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) {
if (req == nullptr || url == nullptr) return;
static_cast<QNetworkRequest*>(req)->setUrl(QUrl(*static_cast<QString*>(url)));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) {
if (req == nullptr) return nullptr;
return new QString(static_cast<QNetworkRequest*>(req)->url().toString());
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value) {
if (req == nullptr || value == nullptr) return;
static_cast<QNetworkRequest*>(req)->setHeader(static_cast<QNetworkRequest::KnownHeaders>(header_type),
*static_cast<QVariant*>(value));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) {
if (req == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkRequest*>(req)->header(static_cast<QNetworkRequest::KnownHeaders>(header_type)));
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size) {
if (req == nullptr || header_name == nullptr) return;
static_cast<QNetworkRequest*>(req)->setRawHeader(QByteArray(header_name),
QByteArray(static_cast<const char*>(value), static_cast<int>(value_size)));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size) {
if (req == nullptr || header_name == nullptr) return nullptr;
QByteArray ba = static_cast<QNetworkRequest*>(req)->rawHeader(QByteArray(header_name));
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value) {
if (req == nullptr || value == nullptr) return;
static_cast<QNetworkRequest*>(req)->setAttribute(static_cast<QNetworkRequest::Attribute>(attr_type),
*static_cast<QVariant*>(value));
}
extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) {
if (req == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkRequest*>(req)->attribute(static_cast<QNetworkRequest::Attribute>(attr_type)));
}
extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) {
delete static_cast<QNetworkRequest*>(req);
}
// ============================================================
// QNetworkAccessManager
// ============================================================
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create(void) {
return new QNetworkAccessManager();
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent) {
if (parent == nullptr) return nullptr;
return new QNetworkAccessManager(static_cast<QObject*>(parent));
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) {
if (nam == nullptr || req == nullptr) return nullptr;
return static_cast<QNetworkAccessManager*>(nam)->get(*static_cast<QNetworkRequest*>(req));
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size) {
if (nam == nullptr || req == nullptr) return nullptr;
QByteArray payload;
if (data != nullptr && size > 0) {
payload = QByteArray(static_cast<const char*>(data), static_cast<int>(size));
}
return static_cast<QNetworkAccessManager*>(nam)->post(*static_cast<QNetworkRequest*>(req), payload);
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size) {
if (nam == nullptr || req == nullptr) return nullptr;
QByteArray payload;
if (data != nullptr && size > 0) {
payload = QByteArray(static_cast<const char*>(data), static_cast<int>(size));
}
return static_cast<QNetworkAccessManager*>(nam)->put(*static_cast<QNetworkRequest*>(req), payload);
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req) {
if (nam == nullptr || req == nullptr) return nullptr;
return static_cast<QNetworkAccessManager*>(nam)->deleteResource(*static_cast<QNetworkRequest*>(req));
}
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) {
if (nam == nullptr || req == nullptr) return nullptr;
return static_cast<QNetworkAccessManager*>(nam)->head(*static_cast<QNetworkRequest*>(req));
}
extern "C" VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store) {
if (nam == nullptr || store == nullptr) return;
QNetworkCookieJar* jar = qobject_cast<QNetworkCookieJar*>(static_cast<QObject*>(store));
if (jar != nullptr) {
static_cast<QNetworkAccessManager*>(nam)->setCookieJar(jar);
}
}
// ============================================================
// QNetworkReply
// ============================================================
extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) {
if (reply == nullptr) return nullptr;
return new QString(static_cast<QNetworkReply*>(reply)->url().toString());
}
extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) {
if (reply == nullptr) return nullptr;
return new QNetworkRequest(static_cast<QNetworkReply*>(reply)->request());
}
extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) {
if (reply == nullptr) return 0;
return static_cast<int>(static_cast<QNetworkReply*>(reply)->error());
}
extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) {
if (reply == nullptr) return nullptr;
return new QString(static_cast<QNetworkReply*>(reply)->errorString());
}
extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) {
if (reply == nullptr) return 0;
return static_cast<QNetworkReply*>(reply)->isFinished() ? 1 : 0;
}
extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) {
if (reply == nullptr) return 0;
return static_cast<QNetworkReply*>(reply)->isRunning() ? 1 : 0;
}
extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) {
if (reply == nullptr) return;
static_cast<QNetworkReply*>(reply)->abort();
}
extern "C" VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size) {
if (reply == nullptr || buf == nullptr) return 0;
return static_cast<size_t>(static_cast<QNetworkReply*>(reply)->read(static_cast<char*>(buf), static_cast<qint64>(max_size)));
}
extern "C" VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size) {
if (reply == nullptr) return nullptr;
QByteArray ba = static_cast<QNetworkReply*>(reply)->readAll();
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply) {
if (reply == nullptr) return 0;
return static_cast<size_t>(static_cast<QNetworkReply*>(reply)->bytesAvailable());
}
extern "C" VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type) {
if (reply == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkReply*>(reply)->header(static_cast<QNetworkRequest::KnownHeaders>(header_type)));
}
extern "C" VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size) {
if (reply == nullptr || header_name == nullptr) return nullptr;
QByteArray ba = static_cast<QNetworkReply*>(reply)->rawHeader(QByteArray(header_name));
if (out_size != nullptr) *out_size = static_cast<size_t>(ba.size());
return ba.data();
}
extern "C" VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code) {
if (reply == nullptr) return nullptr;
return new QVariant(static_cast<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(attribute_code)));
}
extern "C" VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value) {
if (reply == nullptr) return default_value;
return static_cast<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(attribute_code)).toInt(default_value);
}
extern "C" VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size) {
if (reply == nullptr || header_name == nullptr) return;
static_cast<QNetworkReply*>(reply)->setRawHeader(QByteArray(header_name),
QByteArray(static_cast<const char*>(value), static_cast<int>(value_size)));
}
+137
View File
@@ -0,0 +1,137 @@
// ============================================================
// vqt6/_bridge_network.h — QtNetwork C 桥接函数声明
// ============================================================
#ifndef VQT6_BRIDGE_NETWORK_H
#define VQT6_BRIDGE_NETWORK_H
#include "_bridge.h"
#ifdef __cplusplus
extern "C" {
#endif
// ============================================================
// QHostAddress
// ============================================================
VQT6_API void* vqt6_qhostaddress_create(void);
VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4);
VQT6_API void* vqt6_qhostaddress_create_with_string(void* address);
VQT6_API void* vqt6_qhostaddress_create_with_local_host(void);
VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void);
VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void);
VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void);
VQT6_API void* vqt6_qhostaddress_to_string(void* addr);
VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr);
VQT6_API int vqt6_qhostaddress_is_null(void* addr);
VQT6_API int vqt6_qhostaddress_is_loopback(void* addr);
VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr);
VQT6_API int vqt6_qhostaddress_protocol(void* addr);
VQT6_API void vqt6_qhostaddress_free(void* addr);
// ============================================================
// QAbstractSocket
// ============================================================
VQT6_API int vqt6_qabstractsocket_state(void* socket);
VQT6_API int vqt6_qabstractsocket_error(void* socket);
VQT6_API void* vqt6_qabstractsocket_error_string(void* socket);
VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port);
VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port);
VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket);
VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms);
VQT6_API int vqt6_qabstractsocket_is_valid(void* socket);
VQT6_API int vqt6_qabstractsocket_is_open(void* socket);
VQT6_API int vqt6_qabstractsocket_flush(void* socket);
VQT6_API void vqt6_qabstractsocket_close(void* socket);
VQT6_API void vqt6_qabstractsocket_abort(void* socket);
VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size);
VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size);
VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size);
VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket);
VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket);
VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket);
VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket);
VQT6_API void* vqt6_qabstractsocket_local_address(void* socket);
VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket);
// ============================================================
// QTcpSocket
// ============================================================
VQT6_API void* vqt6_qtcpsocket_create(void);
VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent);
VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode);
VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode);
VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor);
VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket);
VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type);
VQT6_API void vqt6_qtcpsocket_abort(void* socket);
// ============================================================
// QUdpSocket
// ============================================================
VQT6_API void* vqt6_qudpsocket_create(void);
VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent);
VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port);
VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port);
VQT6_API void vqt6_qudpsocket_close(void* socket);
VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port);
VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port);
VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket);
VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket);
VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address);
VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address);
// ============================================================
// QNetworkRequest
// ============================================================
VQT6_API void* vqt6_qnetworkrequest_create(void);
VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url);
VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url);
VQT6_API void* vqt6_qnetworkrequest_url(void* req);
VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value);
VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type);
VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size);
VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size);
VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value);
VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type);
VQT6_API void vqt6_qnetworkrequest_free(void* req);
// ============================================================
// QNetworkAccessManager
// ============================================================
VQT6_API void* vqt6_qnetworkaccessmanager_create(void);
VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent);
VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req);
VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size);
VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size);
VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req);
VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req);
VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store);
// ============================================================
// QNetworkReply
// ============================================================
VQT6_API void* vqt6_qnetworkreply_url(void* reply);
VQT6_API void* vqt6_qnetworkreply_request(void* reply);
VQT6_API int vqt6_qnetworkreply_error(void* reply);
VQT6_API void* vqt6_qnetworkreply_error_string(void* reply);
VQT6_API int vqt6_qnetworkreply_is_finished(void* reply);
VQT6_API int vqt6_qnetworkreply_is_running(void* reply);
VQT6_API void vqt6_qnetworkreply_abort(void* reply);
VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size);
VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size);
VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply);
VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type);
VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size);
VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code);
VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value);
VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size);
#ifdef __cplusplus
}
#endif
#endif // VQT6_BRIDGE_NETWORK_H
File diff suppressed because it is too large. Load diff
+432
View File
@@ -0,0 +1,432 @@
// ============================================================
// vqt6/_bridge_widgets.h — QtWidgets C 桥接函数声明
// ============================================================
#ifndef VQT6_BRIDGE_WIDGETS_H
#define VQT6_BRIDGE_WIDGETS_H
#include "_bridge.h"
#ifdef __cplusplus
extern "C" {
#endif
// ============================================================
// QApplication
// ============================================================
VQT6_API void* vqt6_qapplication_create(int argc, char** argv);
VQT6_API void* vqt6_qapplication_instance(void);
VQT6_API int vqt6_qapplication_exec(void* app);
VQT6_API void vqt6_qapplication_quit(void* app);
VQT6_API void vqt6_qapplication_exit(void* app, int exit_code);
VQT6_API void vqt6_qapplication_process_events(void* app);
VQT6_API int vqt6_qapplication_desktop_width(void* app);
VQT6_API int vqt6_qapplication_desktop_height(void* app);
VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit);
VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app);
// ============================================================
// QWidget
// ============================================================
VQT6_API void* vqt6_qwidget_create(void);
VQT6_API void* vqt6_qwidget_create_with_parent(void* parent);
VQT6_API void vqt6_qwidget_show(void* widget);
VQT6_API void vqt6_qwidget_hide(void* widget);
VQT6_API int vqt6_qwidget_close(void* widget);
VQT6_API int vqt6_qwidget_is_visible(void* widget);
VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible);
VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h);
VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h);
VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h);
VQT6_API void vqt6_qwidget_move(void* widget, int x, int y);
VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y);
VQT6_API int vqt6_qwidget_width(void* widget);
VQT6_API int vqt6_qwidget_height(void* widget);
VQT6_API int vqt6_qwidget_x(void* widget);
VQT6_API int vqt6_qwidget_y(void* widget);
VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title);
VQT6_API void* vqt6_qwidget_window_title(void* widget);
VQT6_API void vqt6_qwidget_set_text(void* widget, void* text);
VQT6_API void* vqt6_qwidget_text(void* widget);
VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled);
VQT6_API int vqt6_qwidget_is_enabled(void* widget);
VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent);
VQT6_API void* vqt6_qwidget_parent_widget(void* widget);
VQT6_API void vqt6_qwidget_set_focus(void* widget);
VQT6_API void vqt6_qwidget_clear_focus(void* widget);
VQT6_API int vqt6_qwidget_has_focus(void* widget);
VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy);
VQT6_API void vqt6_qwidget_update(void* widget);
VQT6_API void vqt6_qwidget_repaint(void* widget);
VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled);
VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags);
VQT6_API int vqt6_qwidget_window_flags(void* widget);
VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor);
VQT6_API void* vqt6_qwidget_cursor(void* widget);
VQT6_API void vqt6_qwidget_unset_cursor(void* widget);
VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip);
VQT6_API void* vqt6_qwidget_tool_tip(void* widget);
VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip);
VQT6_API void* vqt6_qwidget_status_tip(void* widget);
VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h);
VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h);
VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h);
// ============================================================
// QDialog
// ============================================================
VQT6_API void* vqt6_qdialog_create(void);
VQT6_API void* vqt6_qdialog_create_with_parent(void* parent);
VQT6_API int vqt6_qdialog_exec(void* dialog);
VQT6_API void vqt6_qdialog_done(void* dialog, int result);
VQT6_API void vqt6_qdialog_accept(void* dialog);
VQT6_API void vqt6_qdialog_reject(void* dialog);
VQT6_API void vqt6_qdialog_set_result(void* dialog, int result);
VQT6_API int vqt6_qdialog_result(void* dialog);
VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal);
VQT6_API int vqt6_qdialog_is_modal(void* dialog);
// ============================================================
// QMainWindow
// ============================================================
VQT6_API void* vqt6_qmainwindow_create(void);
VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent);
VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget);
VQT6_API void* vqt6_qmainwindow_central_widget(void* mw);
VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw);
VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar);
VQT6_API void* vqt6_qmainwindow_status_bar(void* mw);
VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar);
VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar);
VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw);
// ============================================================
// QLabel
// ============================================================
VQT6_API void* vqt6_qlabel_create(void);
VQT6_API void* vqt6_qlabel_create_with_text(void* text);
VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qlabel_set_text(void* label, void* text);
VQT6_API void* vqt6_qlabel_text(void* label);
VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment);
VQT6_API int vqt6_qlabel_alignment(void* label);
VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap);
VQT6_API void* vqt6_qlabel_pixmap(void* label);
VQT6_API void vqt6_qlabel_set_indent(void* label, int indent);
VQT6_API void vqt6_qlabel_set_margin(void* label, int margin);
VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap);
VQT6_API int vqt6_qlabel_word_wrap(void* label);
// ============================================================
// QPushButton
// ============================================================
VQT6_API void* vqt6_qpushbutton_create(void);
VQT6_API void* vqt6_qpushbutton_create_with_text(void* text);
VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text);
VQT6_API void* vqt6_qpushbutton_text(void* btn);
VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon);
VQT6_API void* vqt6_qpushbutton_icon(void* btn);
VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default);
VQT6_API int vqt6_qpushbutton_is_default(void* btn);
VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat);
VQT6_API int vqt6_qpushbutton_is_flat(void* btn);
VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable);
VQT6_API int vqt6_qpushbutton_is_checkable(void* btn);
VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked);
VQT6_API int vqt6_qpushbutton_is_checked(void* btn);
VQT6_API void vqt6_qpushbutton_click(void* btn);
// ============================================================
// QLineEdit
// ============================================================
VQT6_API void* vqt6_qlineedit_create(void);
VQT6_API void* vqt6_qlineedit_create_with_text(void* text);
VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent);
VQT6_API void* vqt6_qlineedit_text(void* le);
VQT6_API void vqt6_qlineedit_set_text(void* le, void* text);
VQT6_API void* vqt6_qlineedit_placeholder_text(void* le);
VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text);
VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max);
VQT6_API int vqt6_qlineedit_max_length(void* le);
VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro);
VQT6_API int vqt6_qlineedit_is_read_only(void* le);
VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode);
VQT6_API int vqt6_qlineedit_echo_mode(void* le);
VQT6_API void vqt6_qlineedit_select_all(void* le);
VQT6_API void vqt6_qlineedit_clear(void* le);
// ============================================================
// QTextEdit / QPlainTextEdit
// ============================================================
VQT6_API void* vqt6_qtextedit_create(void);
VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent);
VQT6_API void* vqt6_qtextedit_to_plain_text(void* te);
VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text);
VQT6_API void vqt6_qtextedit_set_html(void* te, void* html);
VQT6_API void* vqt6_qtextedit_to_html(void* te);
VQT6_API void vqt6_qtextedit_append(void* te, void* text);
VQT6_API void vqt6_qtextedit_clear(void* te);
VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro);
VQT6_API int vqt6_qtextedit_is_read_only(void* te);
VQT6_API void* vqt6_qplaintextedit_create(void);
VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent);
VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte);
VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text);
VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text);
VQT6_API void vqt6_qplaintextedit_clear(void* pte);
VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro);
VQT6_API int vqt6_qplaintextedit_line_count(void* pte);
// ============================================================
// QCheckBox / QRadioButton
// ============================================================
VQT6_API void* vqt6_qcheckbox_create(void);
VQT6_API void* vqt6_qcheckbox_create_with_text(void* text);
VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked);
VQT6_API int vqt6_qcheckbox_is_checked(void* cb);
VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text);
VQT6_API void* vqt6_qcheckbox_text(void* cb);
VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate);
VQT6_API int vqt6_qcheckbox_is_tristate(void* cb);
VQT6_API void* vqt6_qradiobutton_create(void);
VQT6_API void* vqt6_qradiobutton_create_with_text(void* text);
VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked);
VQT6_API int vqt6_qradiobutton_is_checked(void* rb);
VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text);
VQT6_API void* vqt6_qradiobutton_text(void* rb);
// ============================================================
// QComboBox
// ============================================================
VQT6_API void* vqt6_qcombobox_create(void);
VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent);
VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text);
VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items);
VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text);
VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index);
VQT6_API void vqt6_qcombobox_clear(void* cb);
VQT6_API int vqt6_qcombobox_count(void* cb);
VQT6_API int vqt6_qcombobox_current_index(void* cb);
VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index);
VQT6_API void* vqt6_qcombobox_current_text(void* cb);
VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index);
VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable);
VQT6_API int vqt6_qcombobox_is_editable(void* cb);
// ============================================================
// QListWidget
// ============================================================
VQT6_API void* vqt6_qlistwidget_create(void);
VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent);
VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text);
VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items);
VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text);
VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row);
VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row);
VQT6_API void vqt6_qlistwidget_clear(void* lw);
VQT6_API int vqt6_qlistwidget_count(void* lw);
VQT6_API int vqt6_qlistwidget_current_row(void* lw);
VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row);
VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw);
VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row);
VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text);
// ============================================================
// QProgressBar
// ============================================================
VQT6_API void* vqt6_qprogressbar_create(void);
VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent);
VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value);
VQT6_API int vqt6_qprogressbar_value(void* pb);
VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min);
VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max);
VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max);
VQT6_API int vqt6_qprogressbar_minimum(void* pb);
VQT6_API int vqt6_qprogressbar_maximum(void* pb);
VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible);
VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format);
VQT6_API void vqt6_qprogressbar_reset(void* pb);
// ============================================================
// QSlider
// ============================================================
VQT6_API void* vqt6_qslider_create(void);
VQT6_API void* vqt6_qslider_create_with_orientation(int orientation);
VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent);
VQT6_API void vqt6_qslider_set_value(void* s, int value);
VQT6_API int vqt6_qslider_value(void* s);
VQT6_API void vqt6_qslider_set_minimum(void* s, int min);
VQT6_API void vqt6_qslider_set_maximum(void* s, int max);
VQT6_API void vqt6_qslider_set_range(void* s, int min, int max);
VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation);
VQT6_API int vqt6_qslider_orientation(void* s);
VQT6_API void vqt6_qslider_set_single_step(void* s, int step);
VQT6_API void vqt6_qslider_set_page_step(void* s, int step);
// ============================================================
// QSpinBox
// ============================================================
VQT6_API void* vqt6_qspinbox_create(void);
VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent);
VQT6_API int vqt6_qspinbox_value(void* sb);
VQT6_API void vqt6_qspinbox_set_value(void* sb, int value);
VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min);
VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max);
VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max);
VQT6_API int vqt6_qspinbox_minimum(void* sb);
VQT6_API int vqt6_qspinbox_maximum(void* sb);
VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step);
VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix);
VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix);
VQT6_API void* vqt6_qspinbox_prefix(void* sb);
VQT6_API void* vqt6_qspinbox_suffix(void* sb);
// ============================================================
// Layouts
// ============================================================
VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget);
VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget);
VQT6_API int vqt6_qlayout_count(void* layout);
VQT6_API void* vqt6_qlayout_item_at(void* layout, int index);
VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom);
VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing);
VQT6_API int vqt6_qlayout_spacing(void* layout);
VQT6_API void vqt6_qlayout_invalidate(void* layout);
VQT6_API void* vqt6_qhboxlayout_create(void);
VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child);
VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch);
VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size);
VQT6_API void* vqt6_qvboxlayout_create(void);
VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child);
VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch);
VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size);
VQT6_API void* vqt6_qgridlayout_create(void);
VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col);
VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span);
VQT6_API void* vqt6_qformlayout_create(void);
VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent);
VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field);
VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field);
// ============================================================
// QStackedWidget / QTabWidget
// ============================================================
VQT6_API void* vqt6_qstackedwidget_create(void);
VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent);
VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w);
VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w);
VQT6_API int vqt6_qstackedwidget_count(void* sw);
VQT6_API int vqt6_qstackedwidget_current_index(void* sw);
VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index);
VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw);
VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index);
VQT6_API void* vqt6_qtabwidget_create(void);
VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent);
VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label);
VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label);
VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index);
VQT6_API int vqt6_qtabwidget_count(void* tw);
VQT6_API int vqt6_qtabwidget_current_index(void* tw);
VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index);
VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index);
VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text);
VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable);
VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw);
// ============================================================
// QMenuBar / QMenu / QAction
// ============================================================
VQT6_API void* vqt6_qmenubar_create(void);
VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent);
VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title);
VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu);
VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action);
VQT6_API void vqt6_qmenubar_clear(void* mb);
VQT6_API void* vqt6_qmenu_create(void);
VQT6_API void* vqt6_qmenu_create_with_title(void* title);
VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent);
VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title);
VQT6_API void vqt6_qmenu_add_action(void* menu, void* action);
VQT6_API void vqt6_qmenu_add_separator(void* menu);
VQT6_API void vqt6_qmenu_clear(void* menu);
VQT6_API void vqt6_qmenu_set_title(void* menu, void* title);
VQT6_API void* vqt6_qmenu_title(void* menu);
VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text);
VQT6_API void* vqt6_qaction_create(void);
VQT6_API void* vqt6_qaction_create_with_text(void* text);
VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent);
VQT6_API void vqt6_qaction_set_text(void* action, void* text);
VQT6_API void* vqt6_qaction_text(void* action);
VQT6_API void vqt6_qaction_set_icon(void* action, void* icon);
VQT6_API void* vqt6_qaction_icon(void* action);
VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence);
VQT6_API void* vqt6_qaction_shortcut(void* action);
VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable);
VQT6_API int vqt6_qaction_is_checkable(void* action);
VQT6_API void vqt6_qaction_set_checked(void* action, int checked);
VQT6_API int vqt6_qaction_is_checked(void* action);
VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled);
VQT6_API int vqt6_qaction_is_enabled(void* action);
VQT6_API void vqt6_qaction_trigger(void* action);
// ============================================================
// QStatusBar / QToolBar
// ============================================================
VQT6_API void* vqt6_qstatusbar_create(void);
VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent);
VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms);
VQT6_API void vqt6_qstatusbar_clear_message(void* sb);
VQT6_API void* vqt6_qstatusbar_current_message(void* sb);
VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch);
VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch);
VQT6_API void* vqt6_qtoolbar_create(void);
VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent);
VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w);
VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action);
VQT6_API void vqt6_qtoolbar_add_separator(void* tb);
VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h);
VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation);
VQT6_API int vqt6_qtoolbar_orientation(void* tb);
// ============================================================
// QMessageBox
// ============================================================
VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons);
VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons);
VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons);
VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons);
VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text);
VQT6_API void vqt6_qmessagebox_about_qt(void* parent);
// ============================================================
// QFileDialog
// ============================================================
VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter);
VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter);
VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir);
VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter);
#ifdef __cplusplus
}
#endif
#endif // VQT6_BRIDGE_WIDGETS_H
+157
View File
@@ -0,0 +1,157 @@
import t, c
from stdint import *
from vqt6._types import *
# ============================================================
# vqt6/_qtcore.py — QtCore 的 t.State FFI 声明
#
# 所有函数都是 C 桥接层 (libvqt6_bridge.a) 的 extern "C" 函数
# 命名规范: vqt6_<class>_<action>
# ============================================================
# ============================================================
# QString — UTF-16 字符串
# ============================================================
# 创建 QString(从 UTF-8 C 字符串)
def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass
# 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0)
# buf 需足够大(建议 4 * qstring.length() + 1)
def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass
# 释放 QString
def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass
# 获取 QString 字符数
def vqt6_qstring_length(qstr: QtStringPtr) -> t.CInt | t.State: pass
# QString 是否为空
def vqt6_qstring_is_empty(qstr: QtStringPtr) -> t.CInt | t.State: pass
# QString 比较
def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.State: pass
# QString 拼接(返回新 QString)
def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass
# ============================================================
# QByteArray — 字节数组
# ============================================================
def vqt6_qbytearray_create(data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass
def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass
def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass
def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass
# ============================================================
# QObject — 所有 Qt 对象的基类
# ============================================================
# 注意: Qt 对象的内存由 C++ 管理,Viper 端不应直接 free
def vqt6_qobject_delete(obj: QtObjectPtr) -> t.State: pass
def vqt6_qobject_delete_later(obj: QtObjectPtr) -> t.State: pass
def vqt6_qobject_set_object_name(obj: QtObjectPtr, name: QtStringPtr) -> t.State: pass
def vqt6_qobject_object_name(obj: QtObjectPtr) -> QtStringPtr | t.State: pass
def vqt6_qobject_set_parent(child: QtObjectPtr, parent: QtObjectPtr) -> t.State: pass
def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass
# 信号/槽连接 (简化版: 函数指针形式)
# typedef void (*vqt6_callback_t)(void* user_data);
# vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理
# 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表
def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr,
receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass
def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr,
receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass
# 事件过滤器
def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass
def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass
# ============================================================
# QCoreApplication — 事件循环基类
# ============================================================
def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass
def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass
def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass
def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass
def vqt6_qcoreapp_exit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass
def vqt6_qcoreapp_process_events(app: QtCoreAppPtr, flags: t.CInt) -> t.State: pass
def vqt6_qcoreapp_post_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.State: pass
def vqt6_qcoreapp_send_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.CInt | t.State: pass
def vqt6_qcoreapp_organization_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass
def vqt6_qcoreapp_set_organization_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass
def vqt6_qcoreapp_application_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass
def vqt6_qcoreapp_set_application_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass
# ============================================================
# QTimer — 定时器
# ============================================================
def vqt6_qtimer_create() -> QtTimerPtr | t.State: pass
def vqt6_qtimer_create_with_parent(parent: QtObjectPtr) -> QtTimerPtr | t.State: pass
def vqt6_qtimer_start(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass
def vqt6_qtimer_stop(timer: QtTimerPtr) -> t.State: pass
def vqt6_qtimer_set_interval(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass
def vqt6_qtimer_interval(timer: QtTimerPtr) -> t.CInt | t.State: pass
def vqt6_qtimer_is_active(timer: QtTimerPtr) -> t.CInt | t.State: pass
def vqt6_qtimer_set_single_shot(timer: QtTimerPtr, single_shot: t.CInt) -> t.State: pass
def vqt6_qtimer_is_single_shot(timer: QtTimerPtr) -> t.CInt | t.State: pass
# ============================================================
# QVariant — 通用数据容器
# ============================================================
def vqt6_qvariant_create_int(value: t.CInt) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_create_double(value: t.CDouble) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_create_bool(value: t.CInt) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_create_string(s: QtStringPtr) -> QtVariantPtr | t.State: pass
def vqt6_qvariant_to_int(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_to_double(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CDouble | t.State: pass
def vqt6_qvariant_to_bool(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_to_string(v: QtVariantPtr) -> QtStringPtr | t.State: pass
def vqt6_qvariant_type_id(v: QtVariantPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_is_valid(v: QtVariantPtr) -> t.CInt | t.State: pass
def vqt6_qvariant_free(v: QtVariantPtr) -> t.State: pass
# ============================================================
# QEvent — 事件基类
# ============================================================
def vqt6_qevent_type(event: QtEventPtr) -> t.CInt | t.State: pass
def vqt6_qevent_accept(event: QtEventPtr) -> t.State: pass
def vqt6_qevent_ignore(event: QtEventPtr) -> t.State: pass
def vqt6_qevent_is_accepted(event: QtEventPtr) -> t.CInt | t.State: pass
# ============================================================
# 字符串列表 (QStringList / QList<QString>)
# ============================================================
def vqt6_qstringlist_create() -> QtStringListPtr | t.State: pass
def vqt6_qstringlist_append(list: QtStringListPtr, str: QtStringPtr) -> t.State: pass
def vqt6_qstringlist_size(list: QtStringListPtr) -> t.CInt | t.State: pass
def vqt6_qstringlist_at(list: QtStringListPtr, index: t.CInt) -> QtStringPtr | t.State: pass
def vqt6_qstringlist_free(list: QtStringListPtr) -> t.State: pass
# ============================================================
# 字节数组列表 (QList<QByteArray>)
# ============================================================
def vqt6_qbytearraylist_create() -> QtByteArrayListPtr | t.State: pass
def vqt6_qbytearraylist_append(list: QtByteArrayListPtr, qba: QtByteArrayPtr) -> t.State: pass
def vqt6_qbytearraylist_size(list: QtByteArrayListPtr) -> t.CInt | t.State: pass
def vqt6_qbytearraylist_at(list: QtByteArrayListPtr, index: t.CInt) -> QtByteArrayPtr | t.State: pass
def vqt6_qbytearraylist_free(list: QtByteArrayListPtr) -> t.State: pass
# ============================================================
# 全局回调注册表
# ============================================================
# 用于从 C++ 端回调 Viper 代码
# Viper 注册一个 slot 函数(用整数 ID 标识),C++ 在触发信号时通过 ID 查找
# typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data);
def vqt6_register_slot(slot_id: t.CInt, user_data: t.CVoid | t.CPtr) -> t.State: pass
def vqt6_unregister_slot(slot_id: t.CInt) -> t.State: pass
def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff. Show more