snapshot before regression test
This commit is contained in:
commit
796222a300
2295 files changed
+206453
No files matched your search
@@ -0,0 +1,425 @@
|
||||
# GCC/Clang 内建函数声明
|
||||
# 所有函数均为仅声明(t.State 等价于 CExtern | CExport),由编译器/运行时提供实现
|
||||
import t
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 随机数生成 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 时间戳计数器 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内存屏障 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 位操作 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 字节序交换 (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)
|
||||
# ============================================================
|
||||
|
||||
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 Store)
|
||||
# ============================================================
|
||||
|
||||
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 I/O)
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模型特定寄存器 (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)
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 描述符表 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 控制寄存器 (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 状态操作
|
||||
# ============================================================
|
||||
|
||||
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 Builtins)
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 可变参数 (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 / Frame)
|
||||
# ============================================================
|
||||
|
||||
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)
|
||||
# ============================================================
|
||||
|
||||
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)
|
||||
# ============================================================
|
||||
|
||||
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)
|
||||
# ============================================================
|
||||
|
||||
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)
|
||||
# ============================================================
|
||||
|
||||
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 check)
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 浮点分类 (FP 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 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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 类型转换与溢出检查 (Overflow)
|
||||
# ============================================================
|
||||
|
||||
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 状态
|
||||
# ============================================================
|
||||
|
||||
def __builtin_ia32_emms() -> t.State: pass
|
||||
def __builtin_ia32_femms() -> t.State: pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 排队指令 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 用户级等待 (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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 访问控制 (CLAC / STAC)
|
||||
# ============================================================
|
||||
|
||||
def __builtin_ia32_clac() -> t.State: pass
|
||||
def __builtin_ia32_stac() -> t.State: pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TLB 无效化 (INVLPG 变体)
|
||||
# ============================================================
|
||||
|
||||
def __builtin_ia32_invlpgb(aux: t.CUInt64T, pcid: t.CUInt64T) -> t.State: pass
|
||||
def __builtin_ia32_tlbsync() -> t.State: pass
|
||||
@@ -0,0 +1,271 @@
|
||||
import t, c
|
||||
import memhub
|
||||
import string
|
||||
import json
|
||||
from stdint import *
|
||||
|
||||
# Variant 类型标签 (与 _variant.py 保持一致)
|
||||
VARIANT_NONE: t.CDefine = 0 # 无类型/空值
|
||||
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 # 自定义指针类型
|
||||
|
||||
# Variant 结构体大小: vtype(i32, 4 bytes) + padding(4 bytes) + ptr(i8*, 8 bytes) = 16 bytes
|
||||
_VARIANT_SIZE: t.CDefine = 16
|
||||
|
||||
|
||||
class dict:
|
||||
"""堆上动态字典容器,基于 mbuddy 分配器。
|
||||
键类型固定为 str (i8*),值使用 Variant 存储 (类型标签 + 无类型指针)。
|
||||
支持嵌套 dict/list 和 JSON 序列化。
|
||||
|
||||
用法:
|
||||
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)
|
||||
|
||||
# 嵌套 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:
|
||||
# 堆分配 dict 对象
|
||||
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:
|
||||
"""查找 key 的索引,找不到返回 __count__"""
|
||||
for i in range(self.__count__):
|
||||
key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + i * 8)
|
||||
if key_ptr[0] == key: return i
|
||||
return self.__count__
|
||||
|
||||
def __getitem__(self, key: str) -> t.CPtr:
|
||||
"""返回值的无类型指针。用户用 c.Deref 解引用获取实际值。
|
||||
例: p: t.CPtr = d["x"]; v: int = c.Deref(p)"""
|
||||
idx: t.CSizeT = self._find(key)
|
||||
if idx >= self.__count__: return None
|
||||
# Variant.ptr 在 Variant 结构体偏移 8 处
|
||||
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):
|
||||
"""存储值为 VARIANT_PTR。val 自动取地址 (t.CNeedPtr)。
|
||||
注意: val 指向的值生命周期由调用者管理。
|
||||
如需持久存储,请使用 set_int / set_str 等类型化方法。"""
|
||||
self._set_variant_raw(key, VARIANT_PTR, val)
|
||||
|
||||
def _set_variant_raw(self, key: str, vtype: t.CInt, ptr: t.CPtr):
|
||||
"""内部方法: 存储 Variant (vtype + ptr)。不自动取地址。"""
|
||||
idx: t.CSizeT = self._find(key)
|
||||
if idx < self.__count__:
|
||||
# 更新已有键
|
||||
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
|
||||
|
||||
# ============================================================
|
||||
# 类型化 setter — 在 __mbuddy__ 中分配持久存储
|
||||
# ============================================================
|
||||
|
||||
def set_int(self, key: str, val: int):
|
||||
"""存储 int 值 (VARIANT_INT)。值复制到 __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):
|
||||
"""存储 str 值 (VARIANT_STR)。直接存储字符串指针。"""
|
||||
self._set_variant_raw(key, VARIANT_STR, val)
|
||||
|
||||
def set_float(self, key: str, val: float):
|
||||
"""存储 float 值 (VARIANT_FLOAT)。值复制到 __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):
|
||||
"""存储 double 值 (VARIANT_DOUBLE)。值复制到 __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):
|
||||
"""存储嵌套 dict 指针 (VARIANT_DICT)。"""
|
||||
self._set_variant_raw(key, VARIANT_DICT, val)
|
||||
|
||||
def set_list(self, key: str, val: t.CPtr):
|
||||
"""存储嵌套 list 指针 (VARIANT_LIST)。"""
|
||||
self._set_variant_raw(key, VARIANT_LIST, val)
|
||||
|
||||
def set_bool(self, key: str, val: t.CInt):
|
||||
"""存储 bool 值 (VARIANT_BOOL)。值复制到 __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)
|
||||
|
||||
# ============================================================
|
||||
# 查询方法
|
||||
# ============================================================
|
||||
|
||||
def get_vtype(self, key: str) -> t.CInt:
|
||||
"""返回 key 对应值的 Variant 类型标签。"""
|
||||
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:
|
||||
"""返回值指针,不存在则返回 default。"""
|
||||
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:
|
||||
"""检查 key 是否存在。"""
|
||||
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 处理:利用 includes/json 库实现序列化/反序列化
|
||||
# ============================================================
|
||||
|
||||
def to_json(self, pool: memhub.MemManager | t.CPtr) -> json.JsonValue | t.CPtr:
|
||||
"""将 dict 转换为 JsonValue 对象 (JSON_OBJECT)。
|
||||
根据 Variant 类型标签自动选择合适的 JSON 值类型。"""
|
||||
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:
|
||||
# 默认: 将 PTR 作为整数处理
|
||||
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):
|
||||
"""从 JsonValue 对象填充 dict。
|
||||
根据 JSON 值类型自动提取并存储为对应 Variant 类型。"""
|
||||
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:
|
||||
"""将 dict 序列化为 JSON 字符串。"""
|
||||
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):
|
||||
"""从 JSON 字符串解析并填充 dict。"""
|
||||
root: json.JsonValue | t.CPtr = json.parse(pool, json_str)
|
||||
self.from_json(pool, root)
|
||||
@@ -0,0 +1,319 @@
|
||||
import t
|
||||
import memhub
|
||||
import string
|
||||
|
||||
|
||||
class _Type:
|
||||
def type_id(self) -> int:
|
||||
return 99
|
||||
|
||||
|
||||
class _str:
|
||||
# 编译期元数据:声明此类希望从 with 上下文获取 __mbuddy__ 字段(非必要,找不到不报错)
|
||||
__requires__: list[str] = ['__mbuddy__']
|
||||
__data__: str
|
||||
__mbuddy__: memhub.MemBuddy | t.CPtr
|
||||
|
||||
def upper(self) -> str:
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
buf: bytes = self.__mbuddy__.alloc(length + 1)
|
||||
if buf == None: return self.__data__
|
||||
for i, ch in enumerate(src):
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
buf[i] = ch - 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
def lower(self) -> str:
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
buf: bytes = self.__mbuddy__.alloc(length + 1)
|
||||
if buf == None: return self.__data__
|
||||
for i, ch in enumerate(src):
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
buf[i] = ch + 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
def capitalize(self) -> str:
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
buf: bytes = self.__mbuddy__.alloc(length + 1)
|
||||
if buf == None: return self.__data__
|
||||
first: bool = True
|
||||
for i, ch in enumerate(src):
|
||||
if first:
|
||||
first = False
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
buf[i] = ch - 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
buf[i] = ch + 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
def swapcase(self) -> str:
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
buf: bytes = self.__mbuddy__.alloc(length + 1)
|
||||
if buf == None: return self.__data__
|
||||
for i, ch in enumerate(src):
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
buf[i] = ch - 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
buf[i] = ch + 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
def title(self) -> str:
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
buf: bytes = self.__mbuddy__.alloc(length + 1)
|
||||
if buf == None: return self.__data__
|
||||
prev_alpha: bool = False
|
||||
for i, ch in enumerate(src):
|
||||
cur_alpha: bool = False
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
cur_alpha = True
|
||||
else:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
cur_alpha = True
|
||||
if cur_alpha:
|
||||
if prev_alpha:
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
buf[i] = ch + 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
buf[i] = ch - 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
prev_alpha = cur_alpha
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
def casefold(self) -> str:
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
buf: bytes = self.__mbuddy__.alloc(length + 1)
|
||||
if buf == None: return self.__data__
|
||||
for i, ch in enumerate(src):
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
buf[i] = ch + 32
|
||||
else:
|
||||
buf[i] = ch
|
||||
else:
|
||||
buf[i] = ch
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
def isupper(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_alpha: bool = False
|
||||
for ch in src:
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
has_alpha = True
|
||||
else:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
return False
|
||||
return has_alpha
|
||||
|
||||
def islower(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_alpha: bool = False
|
||||
for ch in src:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
has_alpha = True
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
return False
|
||||
return has_alpha
|
||||
|
||||
def isalpha(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_char: bool = False
|
||||
for ch in src:
|
||||
has_char = True
|
||||
cur_alpha: bool = False
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
cur_alpha = True
|
||||
else:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
cur_alpha = True
|
||||
if not cur_alpha:
|
||||
return False
|
||||
return has_char
|
||||
|
||||
def isdigit(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_char: bool = False
|
||||
for ch in src:
|
||||
has_char = True
|
||||
if ch >= 48:
|
||||
if ch > 57:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
return has_char
|
||||
|
||||
def isalnum(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_char: bool = False
|
||||
for ch in src:
|
||||
has_char = True
|
||||
ok: bool = False
|
||||
if ch >= 48:
|
||||
if ch <= 57:
|
||||
ok = True
|
||||
if not ok:
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
ok = True
|
||||
else:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
ok = True
|
||||
if not ok:
|
||||
return False
|
||||
return has_char
|
||||
|
||||
def isspace(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_char: bool = False
|
||||
for ch in src:
|
||||
has_char = True
|
||||
is_space: bool = False
|
||||
if ch == 32 or ch == 9 or ch == 10 or ch == 13 or ch == 11 or ch == 12:
|
||||
is_space = True
|
||||
if not is_space:
|
||||
return False
|
||||
return has_char
|
||||
|
||||
def isascii(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_char: bool = False
|
||||
for ch in src:
|
||||
has_char = True
|
||||
if ch > 127: return False
|
||||
return has_char
|
||||
|
||||
def istitle(self) -> bool:
|
||||
src: str = self.__data__
|
||||
has_char: bool = False
|
||||
prev_alpha: bool = False
|
||||
for ch in src:
|
||||
has_char = True
|
||||
cur_alpha: bool = False
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
cur_alpha = True
|
||||
else:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
cur_alpha = True
|
||||
if cur_alpha:
|
||||
if not prev_alpha:
|
||||
if ch >= 97:
|
||||
if ch <= 122:
|
||||
return False
|
||||
else:
|
||||
if ch >= 65:
|
||||
if ch <= 90:
|
||||
return False
|
||||
prev_alpha = cur_alpha
|
||||
return has_char
|
||||
|
||||
def split(self, delimiter: str) -> list[str]:
|
||||
result = list[str](self.__mbuddy__)
|
||||
src: str = self.__data__
|
||||
length: t.CSizeT = len(src)
|
||||
delim_len: t.CSizeT = string.strlen(delimiter)
|
||||
start: t.CSizeT = 0
|
||||
i: t.CSizeT = 0
|
||||
cur: str = src
|
||||
sub_len: t.CSizeT = 0
|
||||
sub: bytes = None
|
||||
src_off: bytes = None
|
||||
term: bytes = None
|
||||
if delim_len == 0:
|
||||
sub_len = length
|
||||
sub = self.__mbuddy__.alloc(sub_len + 1)
|
||||
if sub != None:
|
||||
src_off = bytes(t.CUInt64T(src) + start)
|
||||
string.memcpy(sub, src_off, sub_len)
|
||||
term = sub
|
||||
term[sub_len] = 0
|
||||
result.append(str(sub))
|
||||
return result
|
||||
while i + delim_len <= length:
|
||||
if string.strncmp(cur, delimiter, delim_len) == 0:
|
||||
sub_len = i - start
|
||||
sub = self.__mbuddy__.alloc(sub_len + 1)
|
||||
if sub != None:
|
||||
src_off = bytes(t.CUInt64T(src) + start)
|
||||
string.memcpy(sub, src_off, sub_len)
|
||||
term = sub
|
||||
term[sub_len] = 0
|
||||
result.append(str(sub))
|
||||
start = i + delim_len
|
||||
cur += delim_len
|
||||
i += delim_len
|
||||
else:
|
||||
cur += 1
|
||||
i += 1
|
||||
sub_len = length - start
|
||||
sub = self.__mbuddy__.alloc(sub_len + 1)
|
||||
if sub != None:
|
||||
src_off = bytes(t.CUInt64T(src) + start)
|
||||
string.memcpy(sub, src_off, sub_len)
|
||||
term = sub
|
||||
term[sub_len] = 0
|
||||
result.append(str(sub))
|
||||
return result
|
||||
@@ -0,0 +1,90 @@
|
||||
import t, c
|
||||
import memhub
|
||||
import string
|
||||
from stdint import *
|
||||
|
||||
|
||||
class list[T]:
|
||||
"""堆上动态列表容器,基于 memhub.MemManager 多态分配器。
|
||||
|
||||
用法:
|
||||
pool: memhub.MemManager = memhub.MemBuddy(arena, arena_size)
|
||||
nums: list[int] = list[int](pool)
|
||||
nums.append(42)
|
||||
x: int = nums.get(0)
|
||||
|
||||
对于指针类型(如 AST | t.CPtr),传 elem_size=8 避免对象切片:
|
||||
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):
|
||||
# 堆分配 list[T] 对象 (6 字段 × 8 = 48 字节,无 vtable)
|
||||
return pool.alloc(48)
|
||||
|
||||
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]
|
||||
@@ -0,0 +1,64 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
# Variant 类型标签 (固定枚举 + 自定义 PTR)
|
||||
VARIANT_NONE: t.CDefine = 0 # 无类型/空值
|
||||
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 # 自定义指针类型
|
||||
|
||||
|
||||
class Variant:
|
||||
"""通用变体类型,存储类型标签 + 无类型指针。
|
||||
用于 dict/list 的万能对象存储,支持嵌套和 JSON 序列化。
|
||||
|
||||
用法:
|
||||
v: Variant = Variant(VARIANT_INT, t.CNeedPtr(42))
|
||||
v2: Variant = Variant(VARIANT_STR, t.CNeedPtr("hello"))
|
||||
|
||||
# 获取值
|
||||
ptr: t.CPtr = v.ptr
|
||||
i: int = c.Deref(ptr)
|
||||
"""
|
||||
vtype: t.CInt
|
||||
ptr: t.CPtr
|
||||
|
||||
def __init__(self, vtype: t.CInt, val: t.CNeedPtr):
|
||||
"""构造 Variant。
|
||||
val 使用 t.CNeedPtr 自动取地址(非指针值自动 alloca+store)。
|
||||
注意: val 的生命周期由调用者管理,Variant 仅存储指针。
|
||||
"""
|
||||
self.vtype = vtype
|
||||
self.ptr = val
|
||||
|
||||
def is_none(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_NONE
|
||||
|
||||
def is_int(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_INT
|
||||
|
||||
def is_float(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_FLOAT
|
||||
|
||||
def is_double(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_DOUBLE
|
||||
|
||||
def is_str(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_STR
|
||||
|
||||
def is_dict(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_DICT
|
||||
|
||||
def is_list(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_LIST
|
||||
|
||||
def is_bool(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_BOOL
|
||||
|
||||
def is_ptr(self) -> t.CInt:
|
||||
return self.vtype == VARIANT_PTR
|
||||
@@ -0,0 +1,67 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32process import TlsAlloc, TlsGetValue, TlsSetValue
|
||||
import stdlib
|
||||
import stdio
|
||||
import string
|
||||
|
||||
|
||||
# 最大提供者栈深度(编译器会检查是否够用,不够再往上提)
|
||||
_MAX_PROVIDER_DEPTH: t.CDefine = 32
|
||||
|
||||
|
||||
@t.Object
|
||||
class _ProviderStack:
|
||||
"""提供者栈,存储字段名和指针对。"""
|
||||
names: t.CArray[VOIDPTR, 32]
|
||||
ptrs: t.CArray[VOIDPTR, 32]
|
||||
top: UINT64
|
||||
|
||||
|
||||
# TLS 索引(全局,所有线程共享同一个索引)
|
||||
_tls_index: ULONG = 0
|
||||
|
||||
|
||||
@t.TLS
|
||||
def _init_tls():
|
||||
"""初始化 TLS 索引(一次性执行,后续调用跳过)。"""
|
||||
global _tls_index
|
||||
_tls_index = TlsAlloc()
|
||||
|
||||
|
||||
def _get_stack() -> _ProviderStack | t.CPtr:
|
||||
"""获取当前线程的提供者栈,不存在则分配。"""
|
||||
_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):
|
||||
"""压入提供者 (field_name, ptr) 到栈中。"""
|
||||
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():
|
||||
"""弹出栈顶提供者。"""
|
||||
stack: _ProviderStack | t.CPtr = _get_stack()
|
||||
if stack.top > 0:
|
||||
stack.top = stack.top - 1
|
||||
|
||||
|
||||
def _find_provider(field_name: str) -> t.CPtr:
|
||||
"""从栈顶向下查找匹配 field_name 的提供者,返回对应的指针。找不到返回 NULL。"""
|
||||
stack: _ProviderStack | t.CPtr = _get_stack()
|
||||
for i in range(stack.top - 1, -1, -1):
|
||||
if stack.names[i] == field_name:
|
||||
return stack.ptrs[i]
|
||||
return None
|
||||
@@ -0,0 +1,458 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import memhub
|
||||
import stdio
|
||||
import hashtable
|
||||
|
||||
|
||||
# ============================================================
|
||||
# argparse.py — 命令行参数解析库(Python argparse 风格)
|
||||
#
|
||||
# 用法:
|
||||
# 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)
|
||||
# ============================================================
|
||||
|
||||
# 类型常量
|
||||
STRING: t.CDefine = 0
|
||||
INT: t.CDefine = 1
|
||||
BOOL: t.CDefine = 2
|
||||
|
||||
# 动作常量
|
||||
STORE: t.CDefine = 0
|
||||
STORE_TRUE: t.CDefine = 1
|
||||
STORE_FALSE: t.CDefine = 2
|
||||
COUNT: t.CDefine = 3
|
||||
|
||||
# 限制
|
||||
MAX_ARGS: t.CDefine = 32
|
||||
|
||||
# 模块级 mbuddy 指针(由用户在 main 中赋值)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Argument — 参数定义结构体
|
||||
# ============================================================
|
||||
|
||||
class Argument:
|
||||
name: str # "--input" 或 "output"(位置参数)
|
||||
short_name: str # "-i" 或 None
|
||||
help_text: str # 帮助文本
|
||||
arg_type: INT # STRING, INT, BOOL
|
||||
action: INT # STORE, STORE_TRUE, STORE_FALSE, COUNT
|
||||
default_int: INT # INT 类型默认值
|
||||
default_str: str # STRING 类型默认值
|
||||
required: bool # 是否必须
|
||||
is_positional: bool # 是否位置参数
|
||||
dest: str # 查找键名("--input" → "input")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ParsedArgs — 解析结果
|
||||
# ============================================================
|
||||
|
||||
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:
|
||||
"""获取字符串值。键不存在返回 None。"""
|
||||
if self._ht.__contains__(name) == 0: return None
|
||||
return self._ht[name]
|
||||
|
||||
def get_int(self, name: str) -> INT:
|
||||
"""获取整数值。键不存在返回 0。"""
|
||||
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) -> INT:
|
||||
"""获取布尔值(返回 1 或 0)。键不存在返回 0。"""
|
||||
if self._ht.__contains__(name) == 0: return 0
|
||||
ptr: t.CPtr = self._ht[name]
|
||||
return 1 if c.Deref(t.CInt(t.CUInt64T(ptr), t.CPtr)) != 0 else 0
|
||||
|
||||
def has(self, name: str) -> bool:
|
||||
"""检查键是否存在。"""
|
||||
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 — 命令行参数解析器
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
return mb.alloc(40)
|
||||
|
||||
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):
|
||||
"""注册一个命令行参数。
|
||||
|
||||
Args:
|
||||
name: 参数名("--input" 或 "output")
|
||||
short: 短选项("-i"),可选
|
||||
arg_type: 类型(STRING/INT/BOOL)
|
||||
default: INT 默认值
|
||||
default_str: STRING 默认值
|
||||
required: 是否必须
|
||||
action: 动作(STORE/STORE_TRUE/STORE_FALSE/COUNT)
|
||||
help: 帮助文本
|
||||
"""
|
||||
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
|
||||
# 判断是否位置参数
|
||||
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:
|
||||
"""精确匹配长选项名"""
|
||||
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:
|
||||
"""匹配 --name=value 中的 name 前缀"""
|
||||
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)
|
||||
if v != 0:
|
||||
args._set_bool(arg.dest, True)
|
||||
else:
|
||||
args._set_bool(arg.dest, False)
|
||||
|
||||
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:
|
||||
"""解析命令行参数。
|
||||
|
||||
Args:
|
||||
argc: 参数个数
|
||||
argv: 参数数组(char**,argv[0] 为程序名)
|
||||
Returns:
|
||||
ParsedArgs 指针,失败返回 None
|
||||
"""
|
||||
if self.__mbuddy__ is None: return None
|
||||
|
||||
args: ParsedArgs | t.CPtr = ParsedArgs(self.__mbuddy__)
|
||||
if args is None: return None
|
||||
|
||||
# 初始化默认值
|
||||
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
|
||||
|
||||
# 解析 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
|
||||
name_len: INT = 0
|
||||
|
||||
while idx < argc:
|
||||
entry = t.CPtr(t.CUInt64T(argv) + idx * 8)
|
||||
token = entry[0]
|
||||
if token is None: break
|
||||
|
||||
# "--" 结束符:后续全部为位置参数
|
||||
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
|
||||
|
||||
# 长选项 --name 或 --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
|
||||
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(值在下一个 argv 或标志)
|
||||
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
|
||||
|
||||
# 短选项 -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
|
||||
|
||||
# 位置参数
|
||||
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
|
||||
|
||||
# 检查必须参数
|
||||
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):
|
||||
"""打印帮助信息"""
|
||||
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):
|
||||
"""打印用法简述"""
|
||||
stdio.printf("usage: %s [options]\n", self._prog)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# release — 释放 ParsedArgs 及其内部资源
|
||||
# ============================================================
|
||||
|
||||
def release(args: ParsedArgs | t.CPtr):
|
||||
"""释放 ParsedArgs 对象及其内部 HashTable。"""
|
||||
if args is None: return
|
||||
if args.__mbuddy__ is None: return
|
||||
if args._ht is not None:
|
||||
if args._ht.__slots__ is not None:
|
||||
args.__mbuddy__.free(args._ht.__slots__)
|
||||
args.__mbuddy__.free(t.CVoid(t.CUInt64T(args._ht), t.CPtr))
|
||||
args.__mbuddy__.free(t.CVoid(t.CUInt64T(args), t.CPtr))
|
||||
+153
@@ -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]
|
||||
)
|
||||
@@ -0,0 +1,105 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
# 导入子模块
|
||||
from .tokens import (
|
||||
Token, TokenType, Keyword, TokOp, _init_tables,
|
||||
)
|
||||
# 公共部分:基类、枚举、常量、辅助函数、dump
|
||||
from .base import (
|
||||
AST, ASTKind, ASTCtx, OpKind, ASTFlag,
|
||||
# 常量
|
||||
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE,
|
||||
FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR,
|
||||
# 辅助函数
|
||||
_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,
|
||||
)
|
||||
# 语句节点
|
||||
from .stmts import (
|
||||
# 模块层
|
||||
Module, Expression, Interactive, FunctionType,
|
||||
# 语句
|
||||
FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign,
|
||||
For, While, If, With, Raise, Try, Assert, Global, Nonlocal,
|
||||
Pass, Break, Continue, Expr, Import, ImportFrom, Match,
|
||||
)
|
||||
# 表达式节点
|
||||
from .exprs import (
|
||||
# 表达式
|
||||
BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set,
|
||||
ListComp, SetComp, DictComp, GeneratorExp,
|
||||
Await, Yield, YieldFrom, FormattedValue, JoinedStr,
|
||||
Constant, NamedExpr, Attribute, Subscript, Starred, Name,
|
||||
List, Tuple, Slice,
|
||||
Call, Compare, OpNode,
|
||||
)
|
||||
# 辅助节点
|
||||
from .astaux import (
|
||||
ExceptHandler, Arguments, Arg, Keyword, Alias, WithItem,
|
||||
Comprehension,
|
||||
)
|
||||
# 模式匹配
|
||||
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
|
||||
|
||||
# ============================================================
|
||||
# 全局内存池指针(遵循项目规则:声明 _mbuddy)
|
||||
# 用户在 main 中初始化:ast._mbuddy = memhub.MemBuddy(arena, size)
|
||||
# ============================================================
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 公共 API: parse
|
||||
# ============================================================
|
||||
|
||||
def parse(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr:
|
||||
"""解析 Python 源代码,返回 AST Module 节点。
|
||||
|
||||
参数:
|
||||
src: NUL 结尾的源代码字符串
|
||||
pool: memhub.MemManager 实例,用于分配 AST 节点
|
||||
|
||||
返回:
|
||||
AST Module 节点,失败返回 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:
|
||||
"""解析单个表达式,返回 Expression 节点"""
|
||||
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)
|
||||
@@ -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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
@@ -0,0 +1,474 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
from .tokens import TokOp
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ASTKind - 节点类型枚举(kind() 虚函数返回值)
|
||||
# ============================================================
|
||||
|
||||
class ASTKind(t.CEnum):
|
||||
# 核心 15 节点
|
||||
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
|
||||
# 模块层
|
||||
Expression: t.State
|
||||
Interactive: t.State
|
||||
FunctionType: t.State
|
||||
# 语句
|
||||
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
|
||||
# 表达式
|
||||
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
|
||||
# 辅助节点
|
||||
ExceptHandler: t.State
|
||||
Arguments: t.State
|
||||
Arg: t.State
|
||||
Keyword: t.State
|
||||
Alias: t.State
|
||||
WithItem: t.State
|
||||
Comprehension: t.State
|
||||
OpNode: t.State
|
||||
# 模式匹配
|
||||
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 - 名称上下文(Load/Store/Del)
|
||||
# ============================================================
|
||||
|
||||
class ASTCtx(t.CEnum):
|
||||
Load: t.State
|
||||
Store: t.State
|
||||
Del: t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
# OpKind - 运算符枚举(BinOp/UnaryOp/Compare 共用)
|
||||
# ============================================================
|
||||
|
||||
class OpKind(t.CEnum):
|
||||
# 二元算术/位运算
|
||||
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
|
||||
# 布尔运算
|
||||
And: t.State
|
||||
Or: t.State
|
||||
# 比较运算
|
||||
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
|
||||
# 一元运算
|
||||
Not: t.State
|
||||
UAdd: t.State
|
||||
USub: t.State
|
||||
Invert: t.State
|
||||
# 空
|
||||
NoneOp: t.State
|
||||
|
||||
|
||||
# Constant 子类型标识
|
||||
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
|
||||
|
||||
# 标志位
|
||||
FLAG_IS_ASYNC: t.CDefine = 1
|
||||
FLAG_SIMPLE: t.CDefine = 2
|
||||
FLAG_HAS_STAR: t.CDefine = 4
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ASTFlag - 节点标志位枚举
|
||||
# ============================================================
|
||||
|
||||
class ASTFlag(t.CEnum):
|
||||
IsAsync: t.State
|
||||
Simple: t.State
|
||||
HasStar: t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 辅助函数
|
||||
# ============================================================
|
||||
|
||||
def _copy_str(pool: memhub.MemManager | t.CPtr, src: str) -> str:
|
||||
"""从 pool 分配并复制 C 字符串"""
|
||||
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):
|
||||
"""初始化 AST 基类字段"""
|
||||
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):
|
||||
"""为 list 中的每个子节点设置 parent 指针"""
|
||||
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):
|
||||
"""向 list 追加子节点(模块级函数,避免与 AST.append 方法名冲突)。
|
||||
|
||||
在 AST.append 方法中调用此函数,绕过编译器把 list.append 误解析为
|
||||
AST.append 虚函数调用的类型推断问题。"""
|
||||
if lst is None or node is None:
|
||||
return
|
||||
lst.append(node)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 运算符映射: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 辅助函数
|
||||
# ============================================================
|
||||
|
||||
def _emit(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT,
|
||||
text: str) -> t.CSizeT:
|
||||
"""追加字面量到 buf+pos,返回新 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:
|
||||
"""追加字符串值到 buf+pos(用 %s 格式)"""
|
||||
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:
|
||||
"""追加整数值到 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, "%lld", val)
|
||||
if n < 0:
|
||||
return pos
|
||||
return pos + t.CSizeT(n)
|
||||
|
||||
|
||||
def _op_name(op: t.CInt) -> str:
|
||||
"""返回 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:
|
||||
"""遍历 list[AST | CPtr] 容器,多态 dump 每个元素"""
|
||||
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:
|
||||
"""遍历 list[CInt] (OpKind 值),输出 op 名称列表"""
|
||||
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 - 多态基类
|
||||
#
|
||||
# @t.CVTable 启用 vtable,支持 kind()/type_name()/dump()/accept() 虚函数
|
||||
# 子节点用 list[AST | CPtr] 容器存储(O(1) 随机访问,比链表高效)
|
||||
# parent 字段维护父指针(用于向上遍历)
|
||||
# ============================================================
|
||||
|
||||
@t.CVTable
|
||||
class AST:
|
||||
"""AST 节点基类。所有具体节点类继承此类。
|
||||
|
||||
字段:
|
||||
parent: 父节点指针(向上遍历)
|
||||
pool: 分配器(用于子节点/字符串分配)
|
||||
lineno/col_offset: 起始位置
|
||||
end_lineno/end_col_offset: 结束位置
|
||||
children: 子节点列表(body 语句块,通过 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:
|
||||
"""返回节点类型(ASTKind 值),子类覆盖"""
|
||||
return 0
|
||||
|
||||
def type_name(self) -> str:
|
||||
"""返回节点类型名,子类覆盖"""
|
||||
return "AST"
|
||||
|
||||
def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
pos: t.CSizeT) -> t.CSizeT:
|
||||
"""多态 dump:子类覆盖以自定义格式。返回写入后的 pos"""
|
||||
return pos
|
||||
|
||||
def accept(self, visitor: t.CPtr):
|
||||
"""访问者模式入口(待实现):ASTVisitor 在 __visitor.py 定义后,
|
||||
子类覆盖此方法分派到 visitor.visit_X(self)。当前为空实现。"""
|
||||
pass
|
||||
|
||||
def append(self, node: AST | t.CPtr):
|
||||
"""将 node 追加为子节点(添加到 children 列表),设置 parent 指针。
|
||||
|
||||
用于 parser 构建语句块:module.append(stmt), if_node.append(stmt) 等。
|
||||
首次调用时懒初始化 children 列表。
|
||||
|
||||
注意:list[AST|CPtr] 当前按值复制存储(编译器限制),所以必须先设置
|
||||
node.parent 再 append,这样副本中的 parent 才是正确的。"""
|
||||
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)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块级 dump 函数(供 ast.dump(node, buf, size) 调用)
|
||||
# ============================================================
|
||||
|
||||
def dump(node: AST | t.CPtr, buf: t.CChar | t.CPtr, size: t.CSizeT):
|
||||
"""将 AST 节点序列化到 buf(容量 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 终止,防止 printf 越界
|
||||
if final_pos < size:
|
||||
buf[final_pos] = '\0'
|
||||
else:
|
||||
buf[size - 1] = '\0'
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,743 @@
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
# 缩进栈最大深度
|
||||
LEXER_MAX_INDENT: t.CDefine = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Lexer 状态结构体
|
||||
# ============================================================
|
||||
class Lexer:
|
||||
src: str # 源代码(NUL 结尾)
|
||||
pos: t.CSizeT # 当前位置
|
||||
len: t.CSizeT # 源代码长度
|
||||
lineno: t.CInt # 当前行号(从 1 开始)
|
||||
col: t.CInt # 当前列号(从 0 开始)
|
||||
pool: memhub.MemManager | t.CPtr # 内存池
|
||||
indent_stack: t.CInt | t.CPtr # 缩进栈(int 数组,从 pool 分配)
|
||||
indent_top: t.CInt # 栈顶索引(-1 表示空栈)
|
||||
paren_depth: t.CInt # 括号深度(>0 时不产生 TokenType.NewLine)
|
||||
tokens_head: Token | t.CPtr # token 链表头
|
||||
tokens_tail: Token | t.CPtr # token 链表尾
|
||||
at_line_start: t.CInt # 1=行首(需处理缩进)
|
||||
error_count: t.CInt # 错误计数
|
||||
|
||||
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:
|
||||
"""从 pool 分配并返回 Lexer(跨模块安全包装)"""
|
||||
return Lexer(pool)
|
||||
|
||||
|
||||
def _lexer_init(lx: Lexer | t.CPtr, src: str,
|
||||
pool: memhub.MemManager | t.CPtr):
|
||||
"""初始化 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
|
||||
# 分配缩进栈
|
||||
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
|
||||
# 栈底压入 0(基础缩进)
|
||||
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)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 辅助函数
|
||||
# ============================================================
|
||||
|
||||
def _peek(lx: Lexer | t.CPtr, offset: t.CSizeT) -> t.CChar:
|
||||
"""查看 pos+offset 处字符,越界返回 '\0'"""
|
||||
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:
|
||||
"""前进一个字符,返回该字符"""
|
||||
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):
|
||||
"""将 token 追加到链表"""
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 缩进处理
|
||||
# ============================================================
|
||||
|
||||
def _handle_indent(lx: Lexer | t.CPtr):
|
||||
"""处理行首缩进,生成 TokenType.Indent/TokenType.Dedent。
|
||||
跳过空行和注释行(不产生缩进变化)。"""
|
||||
# 先跳过空行和注释行
|
||||
while lx.pos < lx.len:
|
||||
# 记住行首位置,用于非空行回退
|
||||
line_start_pos: t.CSizeT = lx.pos
|
||||
line_start_col: t.CInt = lx.col
|
||||
# 跳过空白(不跨行)
|
||||
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 行尾符的 \r,跳过(让 \n 触发空行处理)
|
||||
lx.pos += 1
|
||||
else:
|
||||
break
|
||||
if lx.pos >= lx.len:
|
||||
break
|
||||
ch = lx.src[lx.pos]
|
||||
if ch == '\n':
|
||||
# 空行,跳过
|
||||
lx.pos += 1
|
||||
lx.lineno += 1
|
||||
lx.col = 0
|
||||
continue
|
||||
if ch == '\r':
|
||||
# CRLF 空行(\r 后跟 \n),跳过 \r
|
||||
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 == '#':
|
||||
# 注释行,跳过到行尾
|
||||
while lx.pos < lx.len and lx.src[lx.pos] != '\n':
|
||||
lx.pos += 1
|
||||
continue
|
||||
# 非空行:回退到行首,让后续缩进计算能读到前导空格
|
||||
lx.pos = line_start_pos
|
||||
lx.col = line_start_col
|
||||
break
|
||||
|
||||
if lx.pos >= lx.len:
|
||||
# 文件末尾,不再处理缩进
|
||||
lx.at_line_start = 0
|
||||
return
|
||||
|
||||
# 计算当前行缩进
|
||||
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 lx.pos < lx.len:
|
||||
ch = lx.src[lx.pos]
|
||||
if ch == '\n' or ch == '\r' or ch == '#':
|
||||
# 空行或注释行,回退位置让主循环处理
|
||||
lx.pos = save_pos
|
||||
lx.col = save_col
|
||||
lx.at_line_start = 0
|
||||
return
|
||||
|
||||
# 与缩进栈比较
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 标识符/关键字
|
||||
# ============================================================
|
||||
|
||||
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)
|
||||
# 查找关键字
|
||||
kw_id: t.CInt = _kw_lookup(tok.str_val)
|
||||
if kw_id:
|
||||
tok.kw_subtype = kw_id
|
||||
_emit(lx, tok)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 数字
|
||||
# ============================================================
|
||||
|
||||
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]
|
||||
# 处理 0x/0o/0b 前缀
|
||||
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
|
||||
|
||||
# 十进制整数/浮点
|
||||
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
|
||||
|
||||
# 小数部分
|
||||
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
|
||||
|
||||
# 指数部分
|
||||
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
|
||||
|
||||
# 虚数后缀
|
||||
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)
|
||||
# 解析数值
|
||||
if is_float:
|
||||
tok.float_val = string.atof(tok.str_val)
|
||||
else:
|
||||
tok.int_val = string.atoll(tok.str_val)
|
||||
_emit(lx, tok)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 字符串
|
||||
# ============================================================
|
||||
|
||||
def _read_string(lx: Lexer | t.CPtr):
|
||||
"""读取字符串字面量。
|
||||
支持前缀: r, b, u, f, rb, br, rf, fr(大小写不敏感)
|
||||
支持引号: ', ", ''', """
|
||||
start_lineno: t.CInt = lx.lineno
|
||||
start_col: t.CInt = lx.col
|
||||
prefix_start: t.CSizeT = lx.pos
|
||||
|
||||
# 读取前缀(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
|
||||
|
||||
# 确定引号
|
||||
quote: t.CChar = lx.src[lx.pos]
|
||||
if quote != '\'' and quote != '"':
|
||||
lx.error_count += 1
|
||||
return
|
||||
|
||||
# 检查三引号
|
||||
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
|
||||
|
||||
# 读取字符串内容
|
||||
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':
|
||||
# 单引号字符串不能跨行(除非续行)
|
||||
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
|
||||
# 跳过结束引号
|
||||
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
|
||||
|
||||
# 创建 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
|
||||
|
||||
# 处理转义序列(非 raw 字符串)
|
||||
if is_raw == 0 and content_len > 0:
|
||||
# 分配转换缓冲区(最大情况:每个字符都是普通字符,无需扩展)
|
||||
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 == '\\':
|
||||
conv_buf[wpos] = '\\'
|
||||
elif next_ch == '\'':
|
||||
conv_buf[wpos] = '\''
|
||||
elif next_ch == '"':
|
||||
conv_buf[wpos] = '"'
|
||||
elif next_ch == '0':
|
||||
conv_buf[wpos] = '\0'
|
||||
else:
|
||||
# 未知转义,保留原样(包括 \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)
|
||||
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 字段复用:bit0=raw, bit1=bytes, bit2=fstring, bit3=triple
|
||||
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
|
||||
_emit(lx, tok)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 运算符
|
||||
# ============================================================
|
||||
|
||||
def _read_operator(lx: Lexer | t.CPtr):
|
||||
"""贪婪匹配运算符"""
|
||||
start_lineno: t.CInt = lx.lineno
|
||||
start_col: t.CInt = lx.col
|
||||
remaining: t.CSizeT = lx.len - lx.pos
|
||||
|
||||
# 遍历运算符表,找最长匹配
|
||||
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):
|
||||
# 比较 cur.name 与 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:
|
||||
# 未知字符,报错并跳过
|
||||
lx.error_count += 1
|
||||
lx.pos += 1
|
||||
lx.col += 1
|
||||
return
|
||||
|
||||
# 更新括号深度
|
||||
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)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主词法分析入口
|
||||
# ============================================================
|
||||
|
||||
def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr:
|
||||
"""执行词法分析,返回 token 链表头"""
|
||||
if lx == None: return None
|
||||
while lx.pos < lx.len:
|
||||
# 行首缩进处理
|
||||
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
|
||||
|
||||
# 换行
|
||||
if ch == '\n':
|
||||
if lx.paren_depth > 0:
|
||||
# 括号内,产生 TokenType.Nl
|
||||
tok: Token | t.CPtr = new_token(lx.pool, TokenType.Nl, lx.lineno, lx.col)
|
||||
_emit(lx, tok)
|
||||
else:
|
||||
# 逻辑换行
|
||||
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
|
||||
|
||||
# 反斜线续行
|
||||
if ch == '\\' and lx.pos + 1 < lx.len and lx.src[lx.pos + 1] == '\n':
|
||||
lx.pos += 2
|
||||
lx.lineno += 1
|
||||
lx.col = 0
|
||||
continue
|
||||
|
||||
# 空白
|
||||
if _is_space(ch):
|
||||
lx.pos += 1
|
||||
lx.col += 1
|
||||
continue
|
||||
|
||||
# 注释
|
||||
if ch == '#':
|
||||
while lx.pos < lx.len and lx.src[lx.pos] != '\n':
|
||||
lx.pos += 1
|
||||
continue
|
||||
|
||||
# 字符串前缀(如 r"...")或字符串
|
||||
if ch == '\'' or ch == '"':
|
||||
_read_string(lx)
|
||||
continue
|
||||
# 字符串前缀字母后跟引号(必须在 _is_alpha 之前检测,否则 f/r/b/u 会被当作 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
|
||||
# 双前缀如 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
|
||||
|
||||
# 标识符/关键字
|
||||
if _is_alpha(ch):
|
||||
_read_name(lx)
|
||||
continue
|
||||
|
||||
# 数字
|
||||
if _is_digit(ch):
|
||||
_read_number(lx)
|
||||
continue
|
||||
|
||||
# 运算符
|
||||
_read_operator(lx)
|
||||
|
||||
# 文件结尾:产生 TokenType.NewLine(如果有内容)
|
||||
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)
|
||||
|
||||
# 产生剩余 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
|
||||
@@ -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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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 节点
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,391 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Token 类型枚举(参考 CPython Lib/token.py)
|
||||
# 用 t.CEnum 组织为类型安全枚举;旧名 XXX 保留为兼容别名
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 关键字枚举(参考 CPython Lib/keyword.py)
|
||||
# 用 t.CEnum 组织为类型安全枚举;旧名 KW_XXX 保留为兼容别名
|
||||
# NotKeyword(0) 表示非关键字(哨兵,避免 False_=0 与 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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 运算符/分隔符枚举
|
||||
# 用 t.CEnum 组织为类型安全枚举;旧名 OP_XXX 保留为兼容别名
|
||||
# 存储在 token.op_subtype 字段
|
||||
# ============================================================
|
||||
|
||||
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 # ! (非标准,用于解析容错)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Token 结构体
|
||||
# ============================================================
|
||||
class Token:
|
||||
type: t.CInt # Token 类型(TokenType.EndMarker/TokenType.NewLine/TokenType.Name/...)
|
||||
op_subtype: t.CInt # 运算符子类型(OP_*),仅 type==TokenType.Op 时有效
|
||||
kw_subtype: t.CInt # 关键字子类型(KW_*),仅 type==TokenType.Name 且是关键字时有效
|
||||
str_val: str # token 文本(NUL 结尾,从 pool 分配)
|
||||
int_val: t.CInt64T # 整数值(TokenType.Number 用)
|
||||
float_val: t.CDouble # 浮点值(TokenType.Number 用)
|
||||
is_float: t.CInt # 1=浮点数, 0=整数
|
||||
is_complex: t.CInt # 1=复数, 0=实数
|
||||
lineno: t.CInt # 起始行号
|
||||
col_offset: t.CInt # 起始列偏移
|
||||
end_lineno: t.CInt # 结束行号
|
||||
end_col_offset: t.CInt # 结束列偏移
|
||||
next: Token | t.CPtr # 链表下一个 token
|
||||
|
||||
def __new__(self, pool: memhub.MemManager | t.CPtr):
|
||||
"""从 mpool 分配 Token 结构体内存并零初始化"""
|
||||
ptr: Token | t.CPtr = pool.alloc(Token.__sizeof__())
|
||||
if ptr:
|
||||
string.memset(ptr, 0, Token.__sizeof__())
|
||||
return ptr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 关键字查找表
|
||||
# 由于 TransPyC 无 dict 字面量,用链表实现
|
||||
# ============================================================
|
||||
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
|
||||
|
||||
|
||||
# 全局关键字链表头(懒初始化)
|
||||
_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):
|
||||
"""将关键字名注册到链表"""
|
||||
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:
|
||||
"""查找关键字,返回 kw_id(0 表示非关键字)"""
|
||||
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):
|
||||
"""初始化关键字表(仅一次)"""
|
||||
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)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 运算符查找表
|
||||
# 由于 TransPyC 无 dict,用数组+线性查找
|
||||
# 运算符按长度降序排列,以便贪婪匹配
|
||||
# ============================================================
|
||||
class OpEntry:
|
||||
name: str # 运算符文本(如 "==", "+=")
|
||||
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):
|
||||
"""初始化运算符表(按长度降序注册,便于贪婪匹配)"""
|
||||
global _op_head
|
||||
if _op_head != None: return
|
||||
# 3 字符运算符
|
||||
_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 字符运算符
|
||||
_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 字符运算符
|
||||
_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):
|
||||
"""初始化所有查找表(幂等)"""
|
||||
_init_keywords(pool)
|
||||
_init_operators(pool)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Token 创建辅助函数
|
||||
# ============================================================
|
||||
|
||||
def new_token(pool: memhub.MemManager | t.CPtr, ttype: t.CInt, lineno: t.CInt,
|
||||
col_offset: t.CInt) -> Token | t.CPtr:
|
||||
"""创建一个空 Token,调用方填充字段"""
|
||||
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):
|
||||
"""从 src[start:start+length] 复制文本到 token.str_val
|
||||
|
||||
注意:length == 0 时也分配 1 字节存 NUL,让空字符串与 NULL 指针区分开。
|
||||
"""
|
||||
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):
|
||||
"""直接复制一个 C 字符串到 token.str_val"""
|
||||
if tok == None or text == None: return
|
||||
slen: t.CSizeT = string.strlen(text)
|
||||
buf: str = pool.alloc(slen + 1)
|
||||
if buf == None: return
|
||||
string.memcpy(buf, text, slen + 1)
|
||||
tok.str_val = buf
|
||||
@@ -0,0 +1,42 @@
|
||||
import t, c
|
||||
|
||||
|
||||
ATOMIC_RELAXED: t.CDefine = 0
|
||||
ATOMIC_CONSUME: t.CDefine = 1
|
||||
ATOMIC_ACQUIRE: t.CDefine = 2
|
||||
ATOMIC_RELEASE: t.CDefine = 3
|
||||
ATOMIC_ACQ_REL: t.CDefine = 4
|
||||
ATOMIC_SEQ_CST: t.CDefine = 5
|
||||
|
||||
|
||||
def __atomic_test_and_set(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CBool:
|
||||
result: t.CUInt8T = 1
|
||||
c.Asm(f"""mov al, 1
|
||||
xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al
|
||||
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out = [c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)],
|
||||
inp = [c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)],
|
||||
op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
return t.CBool(result)
|
||||
|
||||
|
||||
def __atomic_clear(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CVoid:
|
||||
c.Asm(f"""mov byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], 0""",
|
||||
inp = [c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)],
|
||||
op = [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
|
||||
def __atomic_thread_fence(order: t.CInt) -> t.CVoid:
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
|
||||
def __atomic_signal_fence(order: t.CInt) -> t.CVoid:
|
||||
pass
|
||||
|
||||
|
||||
def __atomic_always_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool:
|
||||
return t.CBool(1)
|
||||
|
||||
|
||||
def __atomic_is_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool:
|
||||
return t.CBool(1)
|
||||
@@ -0,0 +1,78 @@
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
# Base64 编解码 纯裸实现
|
||||
# ==============================================
|
||||
# Base64 编码对照表
|
||||
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 编码
|
||||
# * @param in: 输入二进制数据
|
||||
# * @param in_len: 输入长度
|
||||
# * @param out: 输出Base64字符串缓冲区
|
||||
# * @retval 编码后字符串长度
|
||||
def b64encode(s: str, out: str) -> t.CSizeT:
|
||||
_s = t.CUInt8T(s, t.CPtr)
|
||||
length: t.CSizeT = len(s)
|
||||
i: t.CSizeT = 0
|
||||
j: t.CSizeT = 0
|
||||
val: t.CUInt32T = 0
|
||||
# 每3字节一组转4字节Base64
|
||||
for i in range(0, length, 3):
|
||||
# 拼接24bit分组
|
||||
val = ((t.CUInt32T(_s[i + 0]) << 16 ) |
|
||||
(t.CUInt32T(_s[i + 1]) << 8 if (i + 1 < length) else 0) |
|
||||
(t.CUInt32T(_s[i + 2]) << 0 if (i + 2 < length) else 0))
|
||||
# 拆分4个6bit 查表
|
||||
out[j + 0] = b64_tab[(val >> 18) & 0x3F]
|
||||
out[j + 1] = b64_tab[(val >> 12) & 0x3F]
|
||||
out[j + 2] = b64_tab[(val >> 6) & 0x3F] if (i + 1 < length) else '='
|
||||
out[j + 3] = b64_tab[(val >> 0) & 0x3F] if (i + 2 < length) else '='
|
||||
j += 4
|
||||
out[j] = '\0' # 字符串结尾
|
||||
return j
|
||||
|
||||
|
||||
# * @brief Base64 解码
|
||||
# * @param in: Base64字符串
|
||||
# * @param out: 输出二进制缓冲区
|
||||
# * @retval 解码后二进制长度
|
||||
def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT:
|
||||
length: t.CSizeT = len(s)
|
||||
i: t.CSizeT = 0
|
||||
j: t.CSizeT = 0
|
||||
val: t.CUInt32T = 0
|
||||
c: t.CInt
|
||||
# 每4个Base64字符还原3字节
|
||||
for i in range(0, length, 4):
|
||||
if s[i] == '=': break
|
||||
val = 0
|
||||
# 逐个解析6bit
|
||||
c = s[i] - 43
|
||||
val |= (b64_dec_tab[c] & 0x3F) << 18
|
||||
c = s[i+1] - 43
|
||||
val |= (b64_dec_tab[c] & 0x3F) << 12
|
||||
c = s[i+2] - 43
|
||||
if s[i+2] != '=': val |= (b64_dec_tab[c] & 0x3F) << 6
|
||||
c = s[i+3] - 43
|
||||
if s[i+3] != '=': val |= (b64_dec_tab[c] & 0x3F)
|
||||
# 还原3字节
|
||||
out[j] = (val >> 16) & 0xFF
|
||||
j += 1
|
||||
if s[i+2] != '=':
|
||||
out[j] = (val >> 8) & 0xFF
|
||||
j += 1
|
||||
if s[i+3] != '=':
|
||||
out[j] = val & 0xFF
|
||||
j += 1
|
||||
return j
|
||||
@@ -0,0 +1,348 @@
|
||||
import t, c
|
||||
|
||||
|
||||
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(malloc(length * 2 + 1))
|
||||
if not out: return None
|
||||
oi: t.CInt = 0
|
||||
for i in range(length):
|
||||
s: t.CUnsignedChar = t.CUnsignedChar(data[i])
|
||||
out[oi] = HEX_CHARS[(s >> 4) & 0x0F]
|
||||
oi += 1
|
||||
out[oi] = HEX_CHARS[(s >> 0) & 0x0F]
|
||||
oi += 1
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def b2a_hex(data: str, length: t.CInt) -> str:
|
||||
return hexlify(data, length)
|
||||
|
||||
def a2b_hex(hexstr: str, length: t.CInt) -> str:
|
||||
if not hexstr or length < 0 or length % 2 != 0: return None
|
||||
out_len: t.CInt = length // 2
|
||||
out: str = str(malloc(out_len + 1))
|
||||
if not out: return None
|
||||
oi: t.CInt = 0
|
||||
for i in range(0, length, 2):
|
||||
hi: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i])]
|
||||
lo: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i + 1])]
|
||||
if hi < 0 or lo < 0:
|
||||
free(out)
|
||||
return None
|
||||
out[oi] = t.CChar((hi << 4) | lo)
|
||||
oi += 1
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def unhexlify(data: str, length: t.CInt):
|
||||
return a2b_hex(data, length)
|
||||
|
||||
def b2a_base64(data: str, length: t.CInt) -> str:
|
||||
if not data or length < 0: return None
|
||||
olen: t.CInt = (length // 3) * 4
|
||||
if length % 3 != 0:
|
||||
olen += 4
|
||||
olen += 1
|
||||
out: str = str(malloc(olen + 1))
|
||||
if not out: return None
|
||||
oi: t.CInt = 0
|
||||
for i in range(0, length, 3):
|
||||
b0: t.CUnsignedChar = t.CUnsignedChar(data[i])
|
||||
b1: t.CUnsignedChar = 0
|
||||
b2: t.CUnsignedChar = 0
|
||||
if i + 1 < length:
|
||||
b1 = t.CUnsignedChar(data[i + 1])
|
||||
if i + 2 < length:
|
||||
b2 = t.CUnsignedChar(data[i + 2])
|
||||
out[oi] = B64_CHARS[(b0 >> 2) & 0x3F]
|
||||
oi += 1
|
||||
out[oi] = B64_CHARS[((b0 & 0x03) << 4) | ((b1 >> 4) & 0x0F)]
|
||||
oi += 1
|
||||
if i + 1 < length:
|
||||
out[oi] = B64_CHARS[((b1 & 0x0F) << 2) | ((b2 >> 6) & 0x03)]
|
||||
else:
|
||||
out[oi] = '='
|
||||
oi += 1
|
||||
if i + 2 < length:
|
||||
out[oi] = B64_CHARS[b2 & 0x3F]
|
||||
else:
|
||||
out[oi] = '='
|
||||
oi += 1
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def a2b_base64(data: str, length: t.CInt) -> str:
|
||||
if not data or length < 4: return None
|
||||
olen: t.CInt = (length // 4) * 3
|
||||
if length >= 4 and data[length - 1] == '=':
|
||||
olen -= 1
|
||||
if length >= 4 and data[length - 2] == '=':
|
||||
olen -= 1
|
||||
out: str = str(malloc(olen + 1))
|
||||
if not out: return None
|
||||
oi: t.CInt = 0
|
||||
for i in range(0, length, 4):
|
||||
v0: t.CInt = 0
|
||||
v1: t.CInt = 0
|
||||
v2: t.CInt = 0
|
||||
v3: t.CInt = 0
|
||||
j: t.CInt
|
||||
for j in range(4):
|
||||
c: t.CChar = data[i + j]
|
||||
if c == '=':
|
||||
pass
|
||||
else:
|
||||
k: t.CInt
|
||||
for k in range(64):
|
||||
if B64_CHARS[k] == c:
|
||||
if j == 0: v0 = k
|
||||
elif j == 1: v1 = k
|
||||
elif j == 2: v2 = k
|
||||
elif j == 3: v3 = k
|
||||
break
|
||||
out[oi] = t.CChar((v0 << 2) | (v1 >> 4))
|
||||
oi += 1
|
||||
if data[i + 2] != '=':
|
||||
out[oi] = t.CChar(((v1 & 0x0F) << 4) | (v2 >> 2))
|
||||
oi += 1
|
||||
if data[i + 3] != '=':
|
||||
out[oi] = t.CChar(((v2 & 0x03) << 6) | v3)
|
||||
oi += 1
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def b2a_uu(data: str, length: t.CInt) -> str:
|
||||
if not data or length < 1 or length > 45: return None
|
||||
out: str = str(malloc(length * 2 + 2))
|
||||
if not out: return None
|
||||
oi: t.CInt = 0
|
||||
out[oi] = UU_CHARS[length]
|
||||
oi += 1
|
||||
for i in range(0, length, 3):
|
||||
b0: t.CUnsignedChar = t.CUnsignedChar(data[i])
|
||||
b1: t.CUnsignedChar = 0
|
||||
b2: t.CUnsignedChar = 0
|
||||
if i + 1 < length:
|
||||
b1 = t.CUnsignedChar(data[i + 1])
|
||||
if i + 2 < length:
|
||||
b2 = t.CUnsignedChar(data[i + 2])
|
||||
m: t.CUnsignedInt = (t.CUnsignedInt(b0) << 16) | (t.CUnsignedInt(b1) << 8) | t.CUnsignedInt(b2)
|
||||
out[oi] = UU_CHARS[(m >> 18) & 0x3F]
|
||||
oi += 1
|
||||
out[oi] = UU_CHARS[(m >> 12) & 0x3F]
|
||||
oi += 1
|
||||
out[oi] = UU_CHARS[(m >> 6) & 0x3F]
|
||||
oi += 1
|
||||
out[oi] = UU_CHARS[m & 0x3F]
|
||||
oi += 1
|
||||
out[oi] = '\n'
|
||||
oi += 1
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def a2b_uu(data: str) -> str:
|
||||
if not data or data[0] == ' ' or data[0] == '`': return None
|
||||
length: t.CInt = t.CInt(data[0]) - 32
|
||||
if length < 0 or length > 45: return None
|
||||
out: str = str(malloc(length + 1))
|
||||
if not out: return None
|
||||
oi: t.CInt = 0
|
||||
i: t.CInt = 1
|
||||
while oi < length:
|
||||
v0: t.CInt = data[i] - 32
|
||||
v1: t.CInt = data[i + 1] - 32
|
||||
v2: t.CInt = data[i + 2] - 32
|
||||
v3: t.CInt = data[i + 3] - 32
|
||||
if v0 < 0 or v0 > 63: v0 = 0
|
||||
if v1 < 0 or v1 > 63: v1 = 0
|
||||
if v2 < 0 or v2 > 63: v2 = 0
|
||||
if v3 < 0 or v3 > 63: v3 = 0
|
||||
m: t.CUnsignedInt = (t.CUnsignedInt(v0) << 18) | (t.CUnsignedInt(v1) << 12) | (t.CUnsignedInt(v2) << 6) | t.CUnsignedInt(v3)
|
||||
if oi < length:
|
||||
out[oi] = t.CChar((m >> 16) & 0xFF)
|
||||
oi += 1
|
||||
if oi < length:
|
||||
out[oi] = t.CChar((m >> 8) & 0xFF)
|
||||
oi += 1
|
||||
if oi < length:
|
||||
out[oi] = t.CChar(m & 0xFF)
|
||||
oi += 1
|
||||
i += 4
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def b2a_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]:
|
||||
if not data or length != 3:
|
||||
return None, crc
|
||||
out: str = str(malloc(5))
|
||||
if not out:
|
||||
return None, crc
|
||||
# 3字节 → 4字节 HQX
|
||||
m: t.CUnsignedInt = (t.CUnsignedChar(data[0]) << 16) | (t.CUnsignedChar(data[1]) << 8) | t.CUnsignedChar(data[2])
|
||||
out[0] = HQX_CHARS[(m >> 18) & 0x3F]
|
||||
out[1] = HQX_CHARS[(m >> 12) & 0x3F]
|
||||
out[2] = HQX_CHARS[(m >> 6) & 0x3F]
|
||||
out[3] = HQX_CHARS[m & 0x3F]
|
||||
out[4] = '\0'
|
||||
# CRC 初始化 + 正确计算
|
||||
s: t.CUnsignedShort = crc
|
||||
for i in range(3):
|
||||
byte: t.CUnsignedChar = t.CUnsignedChar(data[i])
|
||||
s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF]
|
||||
return out, s
|
||||
|
||||
|
||||
def a2b_hqx(data: str, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]:
|
||||
if not data:
|
||||
return None, crc
|
||||
# 检查字符是否有效
|
||||
for i in range(4):
|
||||
cchar: t.CUnsignedChar = t.CUnsignedChar(data[i])
|
||||
if HQX_VALS[cchar] < 0:
|
||||
return None, crc
|
||||
# 解码
|
||||
m: t.CUnsignedInt = 0
|
||||
for i in range(4):
|
||||
m = (m << 6) | t.CUnsignedInt(HQX_VALS[t.CUnsignedChar(data[i])])
|
||||
out: str = str(malloc(4))
|
||||
if not out:
|
||||
return None, crc
|
||||
out[0] = t.CChar((m >> 16) & 0xFF)
|
||||
out[1] = t.CChar((m >> 8) & 0xFF)
|
||||
out[2] = t.CChar(m & 0xFF)
|
||||
out[3] = '\0'
|
||||
# CRC 初始化 + 正确计算
|
||||
s: t.CUnsignedShort = crc
|
||||
for i in range(3):
|
||||
byte: t.CUnsignedChar = t.CUnsignedChar(out[i])
|
||||
s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF]
|
||||
return out, s
|
||||
|
||||
def adler32(data: str, length: t.CInt, adler: t.CUnsignedInt) -> t.CUnsignedInt:
|
||||
a: t.CUnsignedInt = adler & 0xFFFF
|
||||
b: t.CUnsignedInt = (adler >> 16) & 0xFFFF
|
||||
i: t.CInt
|
||||
for i in range(length):
|
||||
a = (a + t.CUnsignedChar(data[i])) % 65521
|
||||
b = (b + a) % 65521
|
||||
return (b << 16) | a
|
||||
@@ -0,0 +1,11 @@
|
||||
import t
|
||||
|
||||
|
||||
def print(*args, sep: str = " ", end: str = "\n") -> t.State:
|
||||
...
|
||||
def input(prompt: str = "") -> str | t.State:
|
||||
...
|
||||
|
||||
class type:
|
||||
def __init__(self): ...
|
||||
def __str__(self): ...
|
||||
@@ -0,0 +1,53 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import (
|
||||
CRITICAL_SECTION,
|
||||
InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection,
|
||||
InitializeConditionVariable, SleepConditionVariableCS,
|
||||
WakeConditionVariable, WakeAllConditionVariable
|
||||
)
|
||||
|
||||
|
||||
@t.Object
|
||||
class Condition:
|
||||
"""基于 Windows 条件变量的条件变量,内部包含 CRITICAL_SECTION。
|
||||
|
||||
用法:
|
||||
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))
|
||||
@@ -0,0 +1,20 @@
|
||||
"""ctraits — 编译时类型特征库
|
||||
|
||||
提供编译时类型判断函数,不纳入运行时编译。
|
||||
所有函数仅在编译时求值,可与 c.CIf 等编译时条件配合使用。
|
||||
"""
|
||||
import t
|
||||
|
||||
|
||||
def isptr(x: t.CType) -> bool:
|
||||
"""编译时判断 x 的类型是否为指针类型。
|
||||
|
||||
返回 True 如果 x 是指针(ptr_count > 0),否则返回 False。
|
||||
可与 c.CIf 配合使用实现条件编译。
|
||||
|
||||
示例:
|
||||
if c.CIf(ctraits.isptr(my_var)):
|
||||
# 仅当 my_var 是指针类型时编译此分支
|
||||
...
|
||||
"""
|
||||
pass
|
||||
@@ -0,0 +1,36 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import CreateEventA, SetEvent, ResetEvent, WaitForSingleObject
|
||||
|
||||
|
||||
@t.Object
|
||||
class Event:
|
||||
"""基于 Windows Event 的事件对象,支持手动/自动重置。
|
||||
|
||||
用法:
|
||||
evt: Event = Event(FALSE, FALSE)
|
||||
evt.set()
|
||||
evt.wait()
|
||||
"""
|
||||
handle: HANDLE
|
||||
manual_reset: BOOL
|
||||
|
||||
def __init__(self, manual_reset: BOOL = FALSE, initial_state: BOOL = FALSE):
|
||||
self.manual_reset = manual_reset
|
||||
self.handle = CreateEventA(NULL, manual_reset, initial_state, NULL)
|
||||
|
||||
def set(self):
|
||||
SetEvent(self.handle)
|
||||
|
||||
def clear(self):
|
||||
ResetEvent(self.handle)
|
||||
|
||||
def is_set(self) -> BOOL:
|
||||
return WaitForSingleObject(self.handle, 0) == WAIT_OBJECT_0
|
||||
|
||||
def wait(self, timeout_ms: ULONG = INFINITE) -> BOOL:
|
||||
return WaitForSingleObject(self.handle, timeout_ms) == WAIT_OBJECT_0
|
||||
|
||||
def close(self):
|
||||
CloseHandle(self.handle)
|
||||
@@ -0,0 +1,4 @@
|
||||
from .__md5 import md5, MD5_DIGEST_LEN
|
||||
from .__sha1 import sha1, SHA1_DIGEST_LEN
|
||||
from .__sha256 import sha256, SHA256_DIGEST_LEN
|
||||
from .__sha512 import sha512, SHA512_DIGEST_LEN
|
||||
@@ -0,0 +1,131 @@
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
# MD5 哈希算法
|
||||
# ==============================================
|
||||
MD5_BLOCK_LEN: t.CDefine = 64 # 分组块大小
|
||||
MD5_DIGEST_LEN: t.CDefine = 16 # 摘要输出长度
|
||||
|
||||
# MD5 四轮非线性函数
|
||||
def md5_F(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) | (~x & z)
|
||||
def md5_G(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & z) | (y & ~z)
|
||||
def md5_H(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return x ^ y ^ z
|
||||
def md5_I(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return y ^ (x | ~z)
|
||||
# 循环左移
|
||||
def md5_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n))
|
||||
|
||||
# MD5 常量表、移位表
|
||||
md5_T: 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 上下文结构体
|
||||
@t.Object
|
||||
class md5:
|
||||
state: t.CArray[t.CUInt32T, 4] # 4个32位状态寄存器
|
||||
count: t.CUInt64T # 已处理比特数
|
||||
buf: t.CArray[t.CUInt8T, MD5_BLOCK_LEN] # 分组缓冲区
|
||||
# 初始化MD5上下文
|
||||
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 单分组压缩变换
|
||||
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]
|
||||
# 字节序转32位字
|
||||
for i in range(16):
|
||||
w[i] = ((t.CUInt32T(block[i * 4 + 0]) << 0) |
|
||||
(t.CUInt32T(block[i * 4 + 1]) << 8) |
|
||||
(t.CUInt32T(block[i * 4 + 2]) << 16) |
|
||||
(t.CUInt32T(block[i * 4 + 3]) << 24))
|
||||
# 4轮64步迭代
|
||||
for i in range(16):
|
||||
tmp: t.CUInt32T = md5_F(b, c, d) + a + md5_T[i] + w[i]
|
||||
a = d; d = c; c = b
|
||||
b += md5_rotl(tmp, md5_S[i])
|
||||
# 在 C 中的 for i<end 的循环退出后的值就是 range 的 end 参数
|
||||
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])
|
||||
# 累加到状态
|
||||
self.state[0] += a
|
||||
self.state[1] += b
|
||||
self.state[2] += c
|
||||
self.state[3] += d
|
||||
# 分批输入数据
|
||||
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)
|
||||
# 结束计算,输出16字节摘要
|
||||
def final(self, out: t.CArray[t.CUInt8T, MD5_DIGEST_LEN]):
|
||||
idx: t.CSizeT = self.count % MD5_BLOCK_LEN
|
||||
# 填充0x80结尾
|
||||
self.buf[idx] = 0x80
|
||||
idx += 1
|
||||
# 空间不够则先压缩一次
|
||||
if idx > MD5_BLOCK_LEN - 8:
|
||||
string.memset(self.buf + idx, 0, MD5_BLOCK_LEN - idx)
|
||||
self.transform(self.buf)
|
||||
idx = 0
|
||||
# 补0到末尾8字节
|
||||
string.memset(self.buf + idx, 0, MD5_BLOCK_LEN - 8 - idx)
|
||||
# 写入总比特数
|
||||
bits: t.CUInt64T = self.count << 3
|
||||
for i in range(8):
|
||||
self.buf[MD5_BLOCK_LEN - 8 + i] = (bits >> (i * 8)) & 0xFF
|
||||
self.transform(self.buf)
|
||||
# 状态转小端字节输出
|
||||
for i in range(4):
|
||||
out[i * 4 + 0] = (self.state[i] >> 0) & 0xFF
|
||||
out[i * 4 + 1] = (self.state[i] >> 8) & 0xFF
|
||||
out[i * 4 + 2] = (self.state[i] >> 16) & 0xFF
|
||||
out[i * 4 + 3] = (self.state[i] >> 24) & 0xFF
|
||||
@@ -0,0 +1,120 @@
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
|
||||
# ==============================================
|
||||
# SHA1 哈希算法
|
||||
# ==============================================
|
||||
SHA1_BLOCK_LEN: t.CDefine = 64
|
||||
SHA1_DIGEST_LEN: t.CDefine = 20
|
||||
|
||||
def sha1_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n))
|
||||
# 三轮逻辑函数
|
||||
def sha1_f1(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (~b & d)
|
||||
def sha1_f2(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return b ^ c ^ d
|
||||
def sha1_f3(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (b & d) | (c & d)
|
||||
|
||||
# SHA1 上下文
|
||||
@t.Object
|
||||
class sha1:
|
||||
state: 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
|
||||
# 单分组压缩
|
||||
def transform(self, block: t.CUInt8T | t.CPtr):
|
||||
w: t.CArray[t.CUInt32T, 80]
|
||||
data: t.CUInt8T | t.CPtr = block
|
||||
# 前16个字
|
||||
for i in range(16):
|
||||
w[i] = (((t.CUInt32T(data[i * 4 + 0])) << 24) |
|
||||
((t.CUInt32T(data[i * 4 + 1])) << 16) |
|
||||
((t.CUInt32T(data[i * 4 + 2])) << 8) |
|
||||
((t.CUInt32T(data[i * 4 + 3])) << 0))
|
||||
# 扩展到80个字
|
||||
for i in range(16, 80):
|
||||
w[i] = sha1_rotl(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16],1)
|
||||
a: t.CUInt32T = self.state[0]
|
||||
b: t.CUInt32T = self.state[1]
|
||||
c: t.CUInt32T = self.state[2]
|
||||
d: t.CUInt32T = self.state[3]
|
||||
e: t.CUInt32T = self.state[4]
|
||||
k: t.CUInt32T
|
||||
tmp: t.CUInt32T
|
||||
# 4轮迭代
|
||||
for i in range(0, 20):
|
||||
k = 0x5a827999
|
||||
tmp = sha1_rotl(a,5) + sha1_f1(b, c, d) + e + k + w[i]
|
||||
e = d; d = c
|
||||
c = sha1_rotl(b, 30)
|
||||
b = a; a = tmp
|
||||
for i in range(20, 40):
|
||||
k = 0x6ed9eba1
|
||||
tmp = sha1_rotl(a,5) + sha1_f2(b, c, d) + e + k + w[i]
|
||||
e = d; d = c
|
||||
c = sha1_rotl(b, 30)
|
||||
b = a; a = tmp
|
||||
for i in range(40, 60):
|
||||
k = 0x8f1bbcdc
|
||||
tmp = sha1_rotl(a,5) + sha1_f3(b, c, d) + e + k + w[i]
|
||||
e = d; d = c
|
||||
c = sha1_rotl(b, 30)
|
||||
b = a; a = tmp
|
||||
for i in range(60, 80):
|
||||
k = 0xca62c1d6
|
||||
tmp = sha1_rotl(a,5) + sha1_f2(b, c, d) + e + k + w[i]
|
||||
e = d; d = c
|
||||
c = sha1_rotl(b, 30)
|
||||
b = a; a = tmp
|
||||
self.state[0] += a
|
||||
self.state[1] += b
|
||||
self.state[2] += c
|
||||
self.state[3] += d
|
||||
self.state[4] += e
|
||||
def update(self, s: str):
|
||||
data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr)
|
||||
length: t.CSizeT = len(s)
|
||||
idx: t.CSizeT = self.count % SHA1_BLOCK_LEN
|
||||
self.count += length
|
||||
if idx > 0:
|
||||
left: t.CSizeT = SHA1_BLOCK_LEN - idx
|
||||
if length >= left:
|
||||
memcpy(self.buf + idx, data, left)
|
||||
self.transform(self.buf)
|
||||
data += left
|
||||
length -= left
|
||||
idx = 0
|
||||
while length >= SHA1_BLOCK_LEN:
|
||||
self.transform(data)
|
||||
data += SHA1_BLOCK_LEN
|
||||
length -= SHA1_BLOCK_LEN
|
||||
if length > 0:
|
||||
memcpy(self.buf + idx, data, length)
|
||||
def final(self, out: 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 大端写入长度
|
||||
for i in range(8):
|
||||
self.buf[SHA1_BLOCK_LEN - 8 + i] = (bits >> (56 - i * 8)) & 0xFF
|
||||
self.transform(self.buf)
|
||||
# 大端输出摘要
|
||||
for i in range(5):
|
||||
out[i * 4 + 0] = (self.state[i] >> 24) & 0xFF
|
||||
out[i * 4 + 1] = (self.state[i] >> 16) & 0xFF
|
||||
out[i * 4 + 2] = (self.state[i] >> 8) & 0xFF
|
||||
out[i * 4 + 3] = (self.state[i] >> 0) & 0xFF
|
||||
@@ -0,0 +1,123 @@
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
# SHA256 哈希算法
|
||||
# ==============================================
|
||||
SHA256_BLOCK_LEN: t.CDefine = 64
|
||||
SHA256_DIGEST_LEN: t.CDefine = 32
|
||||
|
||||
# SHA256 常量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 辅助函数
|
||||
def s0(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ ((x >> 3))
|
||||
def s1(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ ((x >> 10))
|
||||
def S0(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10))
|
||||
def S1(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7))
|
||||
def Ch(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) ^ (~x & z)
|
||||
def Maj(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) ^ (x & z) ^ (y & z)
|
||||
|
||||
# SHA256 上下文
|
||||
@t.Object
|
||||
class sha256:
|
||||
state: t.CArray[t.CUInt32T, 8]
|
||||
count: t.CUInt64T
|
||||
buf: t.CArray[t.CUInt8T, SHA256_BLOCK_LEN]
|
||||
def __init__(self):
|
||||
memset(self, 0, sha256.__sizeof__())
|
||||
self.state[0] = 0x6a09e667
|
||||
self.state[1] = 0xbb67ae85
|
||||
self.state[2] = 0x3c6ef372
|
||||
self.state[3] = 0xa54ff53a
|
||||
self.state[4] = 0x510e527f
|
||||
self.state[5] = 0x9b05688c
|
||||
self.state[6] = 0x1f83d9ab
|
||||
self.state[7] = 0x5be0cd19
|
||||
self.count = 0
|
||||
# memset(self.buf, 0, SHA256_BLOCK_LEN)
|
||||
# 单分组压缩
|
||||
def transform(self, block: t.CUInt8T | t.CPtr):
|
||||
w: 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 ))
|
||||
# 扩展64字
|
||||
for i in range(16, 64):
|
||||
w[i] = w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2])
|
||||
a: t.CUInt32T = self.state[0]
|
||||
b: t.CUInt32T = self.state[1]
|
||||
c: t.CUInt32T = self.state[2]
|
||||
d: t.CUInt32T = self.state[3]
|
||||
e: t.CUInt32T = self.state[4]
|
||||
f: t.CUInt32T = self.state[5]
|
||||
g: t.CUInt32T = self.state[6]
|
||||
h: t.CUInt32T = self.state[7]
|
||||
t1: t.CUInt32T
|
||||
t2: t.CUInt32T
|
||||
# 64步迭代
|
||||
for i in range(64):
|
||||
t1 = h + S1(e) + Ch(e,f,g) + sha256_K[i] + w[i]
|
||||
t2 = S0(a) + Maj(a,b,c)
|
||||
h = g; g = f; f = e
|
||||
e = d + t1
|
||||
d = c; c = b; b = a
|
||||
a = t1 + t2
|
||||
# 累加状态
|
||||
self.state[0] += a
|
||||
self.state[1] += b
|
||||
self.state[2] += c
|
||||
self.state[3] += d
|
||||
self.state[4] += e
|
||||
self.state[5] += f
|
||||
self.state[6] += g
|
||||
self.state[7] += h
|
||||
def update(self, s: str):
|
||||
data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr)
|
||||
length: t.CSizeT = len(s)
|
||||
idx: t.CSizeT = self.count % SHA256_BLOCK_LEN
|
||||
self.count += length
|
||||
if idx > 0:
|
||||
left: t.CSizeT = SHA256_BLOCK_LEN - idx
|
||||
if length >= left:
|
||||
memcpy(self.buf + idx, data, left)
|
||||
self.transform(self.buf)
|
||||
data += left
|
||||
length -= left
|
||||
idx = 0
|
||||
while length >= SHA256_BLOCK_LEN:
|
||||
self.transform(data)
|
||||
data += SHA256_BLOCK_LEN
|
||||
length -= SHA256_BLOCK_LEN
|
||||
if length > 0:
|
||||
memcpy(self.buf + idx, data, length)
|
||||
def final(self, out: 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:
|
||||
memset(self.buf + idx, 0, SHA256_BLOCK_LEN - idx)
|
||||
self.transform(self.buf)
|
||||
idx = 0
|
||||
memset(self.buf + idx, 0, SHA256_BLOCK_LEN - 8 - idx)
|
||||
bits: t.CUInt64T = self.count << 3
|
||||
for i in range(8):
|
||||
self.buf[SHA256_BLOCK_LEN-8+i] = (bits >> (56 - i*8)) & 0xFF
|
||||
self.transform(self.buf)
|
||||
# 大端输出32字节摘要
|
||||
for i in range(8):
|
||||
out[i * 4 + 0] = (self.state[i] >> 24) & 0xFF
|
||||
out[i * 4 + 1] = (self.state[i] >> 16) & 0xFF
|
||||
out[i * 4 + 2] = (self.state[i] >> 8) & 0xFF
|
||||
out[i * 4 + 3] = (self.state[i] >> 0) & 0xFF
|
||||
@@ -0,0 +1,148 @@
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
# SHA512 哈希算法
|
||||
# ==============================================
|
||||
SHA512_BLOCK_LEN: t.CDefine = 128
|
||||
SHA512_DIGEST_LEN: t.CDefine = 64
|
||||
|
||||
def sha512_ror(x: t.CUInt64T, n: int) -> t.CUInt64T: return (x >> n) | (x << (64 - n))
|
||||
def sha512_shr(x: t.CUInt64T, n: int) -> t.CUInt64T: return x >> n
|
||||
def sha512_Ch (x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (~x & z)
|
||||
def sha512_Maj(x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (x & z) ^ (y & z)
|
||||
def sha512_BigSigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 28) ^ sha512_ror(x, 34) ^ sha512_ror(x, 39)
|
||||
def sha512_BigSigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 14) ^ sha512_ror(x, 18) ^ sha512_ror(x, 41)
|
||||
def sha512_Sigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 1) ^ sha512_ror(x, 8) ^ sha512_shr(x, 7)
|
||||
def sha512_Sigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 19) ^ sha512_ror(x, 61) ^ sha512_shr(x, 6)
|
||||
|
||||
sha512_K: 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):
|
||||
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:
|
||||
memcpy(self.buf + idx, data, left)
|
||||
self.transform(self.buf)
|
||||
data += left
|
||||
length -= left
|
||||
idx = 0
|
||||
while length >= SHA512_BLOCK_LEN:
|
||||
self.transform(data)
|
||||
data += SHA512_BLOCK_LEN
|
||||
length -= SHA512_BLOCK_LEN
|
||||
if length > 0:
|
||||
memcpy(self.buf + idx, data, length)
|
||||
def final(self, out: 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:
|
||||
memset(self.buf + idx, 0, SHA512_BLOCK_LEN - idx)
|
||||
self.transform(self.buf)
|
||||
idx = 0
|
||||
memset(self.buf + idx, 0, SHA512_BLOCK_LEN - 16 - idx)
|
||||
for i in range(8):
|
||||
self.buf[SHA512_BLOCK_LEN - 16 + i] = t.CUInt8T(bits_hi >> (56 - i * 8))
|
||||
for i in range(8):
|
||||
self.buf[SHA512_BLOCK_LEN - 8 + i] = t.CUInt8T(bits_lo >> (56 - i * 8))
|
||||
self.transform(self.buf)
|
||||
for i in range(8):
|
||||
out[i * 8 + 0] = t.CUInt8T(self.state[i] >> 56)
|
||||
out[i * 8 + 1] = t.CUInt8T(self.state[i] >> 48)
|
||||
out[i * 8 + 2] = t.CUInt8T(self.state[i] >> 40)
|
||||
out[i * 8 + 3] = t.CUInt8T(self.state[i] >> 32)
|
||||
out[i * 8 + 4] = t.CUInt8T(self.state[i] >> 24)
|
||||
out[i * 8 + 5] = t.CUInt8T(self.state[i] >> 16)
|
||||
out[i * 8 + 6] = t.CUInt8T(self.state[i] >> 8)
|
||||
out[i * 8 + 7] = t.CUInt8T(self.state[i] >> 0)
|
||||
@@ -0,0 +1,240 @@
|
||||
# hashtable - 开放寻址哈希表库
|
||||
# 使用线性探测处理冲突,支持自动扩容和墓碑删除
|
||||
# 键类型固定为 str (i8*),值类型为 void* (通用指针)
|
||||
import t, c
|
||||
import string
|
||||
import memhub
|
||||
from stdint import *
|
||||
|
||||
# 空槽标记 (hash == 0)
|
||||
_HT_EMPTY: t.CDefine = 0
|
||||
# 墓碑标记 (hash == 1)
|
||||
_HT_TOMBSTONE: t.CDefine = 1
|
||||
# 默认初始容量 (必须是 2 的幂)
|
||||
_HT_INIT_CAP: t.CDefine = 16
|
||||
# 槽大小: hash(8) + key(8) + value(8) = 24 字节
|
||||
_HT_SLOT_SIZE: t.CDefine = 24
|
||||
# FNV-1a 64-bit 常量
|
||||
_FNV_OFFSET: t.CUInt64T = 0xcbf29ce484222325
|
||||
_FNV_PRIME: t.CUInt64T = 0x100000001b3
|
||||
|
||||
|
||||
def _fnv1a_hash(key: str) -> t.CUInt64T:
|
||||
"""FNV-1a 64-bit 哈希函数"""
|
||||
h: t.CUInt64T = _FNV_OFFSET
|
||||
k: str = key
|
||||
while k[0] != 0:
|
||||
h = h ^ t.CUInt64T(k[0])
|
||||
h = h * _FNV_PRIME
|
||||
k += 1
|
||||
# 保证 h >= 2 (避开空槽 0 和墓碑 1)
|
||||
if h < 2:
|
||||
h = 2
|
||||
return h
|
||||
|
||||
|
||||
class HashTable:
|
||||
"""开放寻址哈希表,使用线性探测处理冲突。
|
||||
|
||||
键类型固定为 str (i8*),值类型为 void* (通用指针)。
|
||||
使用 mbuddy 分配器管理内存。负载因子超过 0.75 时自动扩容。
|
||||
|
||||
用法:
|
||||
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 # 槽位数组基址
|
||||
__count__: t.CSizeT = 0 # 已用条目数
|
||||
__capacity__: t.CSizeT = 16 # 槽位总数 (2 的幂)
|
||||
__tombstones__: t.CSizeT = 0 # 墓碑数
|
||||
__mbuddy__: memhub.MemBuddy | t.CPtr
|
||||
__iter_index__: t.CSizeT = 0
|
||||
|
||||
def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr:
|
||||
# 堆分配 HashTable 对象 (6 字段 x 8 字节 = 48 字节)
|
||||
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)
|
||||
# 初始化所有槽为空 (hash = 0)
|
||||
string.memset(self.__slots__, 0, self.__capacity__ * _HT_SLOT_SIZE)
|
||||
|
||||
def _slot_hash(self, idx: t.CSizeT) -> t.CUInt64T:
|
||||
"""读取槽位的 hash 值"""
|
||||
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:
|
||||
"""读取槽位的 key 指针"""
|
||||
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:
|
||||
"""读取槽位的 value 指针"""
|
||||
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):
|
||||
"""设置槽位的三个字段"""
|
||||
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:
|
||||
"""查找 key 应该插入或已存在的槽位索引。
|
||||
|
||||
返回: 如果找到 key,返回其索引;否则返回第一个可插入的空槽/墓碑索引。
|
||||
"""
|
||||
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 sk == key:
|
||||
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):
|
||||
"""扩容并重新哈希所有条目"""
|
||||
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):
|
||||
"""插入或更新键值对。val 自动取地址 (t.CNeedPtr: 已是指针则不取)。"""
|
||||
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
|
||||
# 负载因子 > 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:
|
||||
"""查找 key,返回值指针。不存在返回 None。"""
|
||||
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
|
||||
return self._slot_value(idx)
|
||||
|
||||
def __contains__(self, key: str) -> t.CInt:
|
||||
"""检查 key 是否存在。"""
|
||||
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:
|
||||
"""删除 key。成功返回 1,key 不存在返回 0。"""
|
||||
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:
|
||||
"""返回值指针,不存在则返回 default。"""
|
||||
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):
|
||||
"""存储 int 值。值复制到 mbuddy 持久存储。"""
|
||||
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):
|
||||
"""存储 str 值。直接存储字符串指针。"""
|
||||
self[key] = val
|
||||
@@ -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 cur.key == key:
|
||||
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 cur.key == key:
|
||||
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 cur.key == key:
|
||||
cur.vtype = val.vtype
|
||||
cur.bool_val = val.bool_val
|
||||
cur.int_val = val.int_val
|
||||
cur.float_val = val.float_val
|
||||
cur.str_val = val.str_val
|
||||
cur.child = val.child
|
||||
cur.child_count = val.child_count
|
||||
return
|
||||
cur = cur.next
|
||||
klen: t.CSizeT = string.strlen(key)
|
||||
kbuf: t.CChar | t.CPtr = pool.alloc(klen + 1)
|
||||
if kbuf != None:
|
||||
string.memcpy(kbuf, key, klen + 1)
|
||||
val.key = kbuf
|
||||
obj._append_child(val)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 导入子模块
|
||||
# ============================================================
|
||||
from .__parser import parse
|
||||
from .__writer import write
|
||||
@@ -0,0 +1,291 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
from . import (
|
||||
JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT,
|
||||
JSON_STRING, JSON_ARRAY, JSON_OBJECT,
|
||||
null, bool_val, int_val, float_val, string_val, array, object,
|
||||
)
|
||||
|
||||
|
||||
class ParseState:
|
||||
src: t.CChar | t.CPtr
|
||||
pos: t.CSizeT
|
||||
len: t.CSizeT
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
|
||||
def __init__(self, src: t.CChar | t.CPtr, pool: memhub.MemManager | t.CPtr):
|
||||
self.src = src
|
||||
self.pos = 0
|
||||
self.len = string.strlen(src) if src != None else 0
|
||||
self.pool = pool
|
||||
|
||||
|
||||
def _peek(s: ParseState | t.CPtr) -> t.CChar:
|
||||
if s.pos >= s.len:
|
||||
return '\0'
|
||||
return s.src[s.pos]
|
||||
|
||||
def _advance(s: ParseState | t.CPtr) -> t.CChar:
|
||||
if s.pos >= s.len:
|
||||
return '\0'
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
s.pos += 1
|
||||
return ch
|
||||
|
||||
def _skip_whitespace(s: ParseState | t.CPtr):
|
||||
while s.pos < s.len:
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
if ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r':
|
||||
s.pos += 1
|
||||
else:
|
||||
break
|
||||
|
||||
def _expect(s: ParseState | t.CPtr, ch: t.CChar) -> bool:
|
||||
_skip_whitespace(s)
|
||||
if s.pos >= s.len:
|
||||
return False
|
||||
if s.src[s.pos] != ch:
|
||||
return False
|
||||
s.pos += 1
|
||||
return True
|
||||
|
||||
|
||||
def _parse_string(s: ParseState | t.CPtr) -> t.CChar | t.CPtr:
|
||||
if _peek(s) != '"':
|
||||
return None
|
||||
_advance(s)
|
||||
|
||||
start: t.CSizeT = s.pos
|
||||
slen: t.CSizeT = 0
|
||||
while s.pos < s.len:
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
if ch == '"':
|
||||
break
|
||||
if ch == '\\':
|
||||
s.pos += 1
|
||||
slen += 1
|
||||
slen += 1
|
||||
s.pos += 1
|
||||
|
||||
buf: t.CChar | t.CPtr = s.pool.alloc(slen + 1)
|
||||
if buf == None:
|
||||
return None
|
||||
|
||||
s.pos = start
|
||||
di: t.CSizeT = 0
|
||||
while s.pos < s.len:
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
if ch == '"':
|
||||
s.pos += 1
|
||||
break
|
||||
if ch == '\\':
|
||||
s.pos += 1
|
||||
if s.pos < s.len:
|
||||
esc: t.CChar = s.src[s.pos]
|
||||
if esc == 'n':
|
||||
buf[di] = '\n'
|
||||
elif esc == 't':
|
||||
buf[di] = '\t'
|
||||
elif esc == 'r':
|
||||
buf[di] = '\r'
|
||||
elif esc == '\\':
|
||||
buf[di] = '\\'
|
||||
elif esc == '"':
|
||||
buf[di] = '"'
|
||||
elif esc == '/':
|
||||
buf[di] = '/'
|
||||
else:
|
||||
buf[di] = esc
|
||||
di += 1
|
||||
s.pos += 1
|
||||
continue
|
||||
buf[di] = ch
|
||||
di += 1
|
||||
s.pos += 1
|
||||
|
||||
buf[di] = '\0'
|
||||
return buf
|
||||
|
||||
|
||||
def _parse_number(s: ParseState | t.CPtr) -> JsonValue | t.CPtr:
|
||||
_skip_whitespace(s)
|
||||
is_float: bool = False
|
||||
start: t.CSizeT = s.pos
|
||||
|
||||
if s.pos < s.len and s.src[s.pos] == '-':
|
||||
s.pos += 1
|
||||
|
||||
while s.pos < s.len:
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
if ch >= '0' and ch <= '9':
|
||||
s.pos += 1
|
||||
else:
|
||||
break
|
||||
|
||||
if s.pos < s.len and s.src[s.pos] == '.':
|
||||
is_float = True
|
||||
s.pos += 1
|
||||
while s.pos < s.len:
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
if ch >= '0' and ch <= '9':
|
||||
s.pos += 1
|
||||
else:
|
||||
break
|
||||
|
||||
if s.pos < s.len and (s.src[s.pos] == 'e' or s.src[s.pos] == 'E'):
|
||||
is_float = True
|
||||
s.pos += 1
|
||||
if s.pos < s.len and (s.src[s.pos] == '+' or s.src[s.pos] == '-'):
|
||||
s.pos += 1
|
||||
while s.pos < s.len:
|
||||
ch: t.CChar = s.src[s.pos]
|
||||
if ch >= '0' and ch <= '9':
|
||||
s.pos += 1
|
||||
else:
|
||||
break
|
||||
|
||||
num_len: t.CSizeT = s.pos - start
|
||||
buf: t.CChar | t.CPtr = s.pool.alloc(num_len + 1)
|
||||
if buf == None:
|
||||
return null(s.pool)
|
||||
|
||||
i: t.CSizeT = 0
|
||||
while i < num_len:
|
||||
buf[i] = s.src[start + i]
|
||||
i += 1
|
||||
buf[num_len] = '\0'
|
||||
|
||||
if is_float:
|
||||
val: t.CDouble = string.atof(buf)
|
||||
return float_val(s.pool, val)
|
||||
else:
|
||||
ival: t.CInt64T = string.atoll(buf)
|
||||
return int_val(s.pool, ival)
|
||||
|
||||
|
||||
def _parse_value(s: ParseState | t.CPtr) -> JsonValue | t.CPtr:
|
||||
_skip_whitespace(s)
|
||||
if s.pos >= s.len:
|
||||
return null(s.pool)
|
||||
|
||||
ch: t.CChar = _peek(s)
|
||||
|
||||
if ch == '"':
|
||||
sv: t.CChar | t.CPtr = _parse_string(s)
|
||||
return string_val(s.pool, sv)
|
||||
|
||||
if ch == '{':
|
||||
return _parse_object(s)
|
||||
|
||||
if ch == '[':
|
||||
return _parse_array(s)
|
||||
|
||||
if ch == '-' or (ch >= '0' and ch <= '9'):
|
||||
return _parse_number(s)
|
||||
|
||||
if ch == 't':
|
||||
if s.pos + 3 < s.len:
|
||||
if s.src[s.pos + 1] == 'r' and s.src[s.pos + 2] == 'u' and s.src[s.pos + 3] == 'e':
|
||||
s.pos += 4
|
||||
return bool_val(s.pool, True)
|
||||
return null(s.pool)
|
||||
|
||||
if ch == 'f':
|
||||
if s.pos + 4 < s.len:
|
||||
if s.src[s.pos + 1] == 'a' and s.src[s.pos + 2] == 'l' and s.src[s.pos + 3] == 's' and s.src[s.pos + 4] == 'e':
|
||||
s.pos += 5
|
||||
return bool_val(s.pool, False)
|
||||
return null(s.pool)
|
||||
|
||||
if ch == 'n':
|
||||
if s.pos + 3 < s.len:
|
||||
if s.src[s.pos + 1] == 'u' and s.src[s.pos + 2] == 'l' and s.src[s.pos + 3] == 'l':
|
||||
s.pos += 4
|
||||
return null(s.pool)
|
||||
return null(s.pool)
|
||||
|
||||
return null(s.pool)
|
||||
|
||||
|
||||
def _parse_array(s: ParseState | t.CPtr) -> JsonValue | t.CPtr:
|
||||
if not _expect(s, '['):
|
||||
return null(s.pool)
|
||||
|
||||
arr: JsonValue | t.CPtr = array(s.pool)
|
||||
|
||||
_skip_whitespace(s)
|
||||
if s.pos < s.len and _peek(s) == ']':
|
||||
_advance(s)
|
||||
return arr
|
||||
|
||||
item: JsonValue | t.CPtr = _parse_value(s)
|
||||
arr._append_child(item)
|
||||
|
||||
while True:
|
||||
_skip_whitespace(s)
|
||||
if s.pos >= s.len:
|
||||
break
|
||||
if _peek(s) != ',':
|
||||
break
|
||||
_advance(s)
|
||||
item = _parse_value(s)
|
||||
arr._append_child(item)
|
||||
|
||||
_expect(s, ']')
|
||||
return arr
|
||||
|
||||
|
||||
def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr:
|
||||
if not _expect(s, '{'):
|
||||
return null(s.pool)
|
||||
|
||||
obj: JsonValue | t.CPtr = object(s.pool)
|
||||
|
||||
_skip_whitespace(s)
|
||||
if s.pos < s.len and _peek(s) == '}':
|
||||
_advance(s)
|
||||
return obj
|
||||
|
||||
_skip_whitespace(s)
|
||||
key: t.CChar | t.CPtr = _parse_string(s)
|
||||
_expect(s, ':')
|
||||
val: JsonValue | t.CPtr = _parse_value(s)
|
||||
if key != None and val != None:
|
||||
klen: t.CSizeT = string.strlen(key)
|
||||
kbuf: t.CChar | t.CPtr = s.pool.alloc(klen + 1)
|
||||
if kbuf != None:
|
||||
string.memcpy(kbuf, key, klen + 1)
|
||||
val.key = kbuf
|
||||
obj._append_child(val)
|
||||
|
||||
while True:
|
||||
_skip_whitespace(s)
|
||||
if s.pos >= s.len:
|
||||
break
|
||||
if _peek(s) != ',':
|
||||
break
|
||||
_advance(s)
|
||||
_skip_whitespace(s)
|
||||
key = _parse_string(s)
|
||||
_expect(s, ':')
|
||||
val = _parse_value(s)
|
||||
if key != None and val != None:
|
||||
klen2: t.CSizeT = string.strlen(key)
|
||||
kbuf2: t.CChar | t.CPtr = s.pool.alloc(klen2 + 1)
|
||||
if kbuf2 != None:
|
||||
string.memcpy(kbuf2, key, klen2 + 1)
|
||||
val.key = kbuf2
|
||||
obj._append_child(val)
|
||||
|
||||
_expect(s, '}')
|
||||
return obj
|
||||
|
||||
|
||||
def parse(pool: memhub.MemManager | t.CPtr, src: t.CChar | t.CPtr) -> JsonValue | t.CPtr:
|
||||
"""解析 JSON 字符串,返回 JsonValue 树"""
|
||||
if src == None:
|
||||
return null(pool)
|
||||
s: ParseState | t.CPtr = ParseState(src, pool)
|
||||
return _parse_value(s)
|
||||
@@ -0,0 +1,119 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
from stdio import snprintf
|
||||
from . import (
|
||||
JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT,
|
||||
JSON_STRING, JSON_ARRAY, JSON_OBJECT,
|
||||
)
|
||||
|
||||
|
||||
def _write_char(buf: t.CChar | t.CPtr, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT:
|
||||
buf[pos] = ch
|
||||
return pos + 1
|
||||
|
||||
def _write_str(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT:
|
||||
if s == None: return pos
|
||||
slen: t.CSizeT = string.strlen(s)
|
||||
string.memcpy(t.CChar(t.CUInt64T(buf) + pos, t.CPtr), s, slen)
|
||||
return pos + slen
|
||||
|
||||
def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT:
|
||||
if s == None:
|
||||
pos = _write_str(buf, pos, "null")
|
||||
return pos
|
||||
pos = _write_char(buf, pos, '"')
|
||||
i: t.CSizeT = 0
|
||||
slen: t.CSizeT = string.strlen(s)
|
||||
while i < slen:
|
||||
ch: t.CChar = s[i]
|
||||
if ch == '"':
|
||||
pos = _write_str(buf, pos, "\\\"")
|
||||
elif ch == '\\':
|
||||
pos = _write_str(buf, pos, "\\\\")
|
||||
elif ch == '\n':
|
||||
pos = _write_str(buf, pos, "\\n")
|
||||
elif ch == '\r':
|
||||
pos = _write_str(buf, pos, "\\r")
|
||||
elif ch == '\t':
|
||||
pos = _write_str(buf, pos, "\\t")
|
||||
else:
|
||||
pos = _write_char(buf, pos, ch)
|
||||
i += 1
|
||||
pos = _write_char(buf, pos, '"')
|
||||
return pos
|
||||
|
||||
|
||||
def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: memhub.MemManager | t.CPtr) -> t.CSizeT:
|
||||
if val == None:
|
||||
pos = _write_str(buf, pos, "null")
|
||||
return pos
|
||||
|
||||
if val.vtype == JSON_NULL:
|
||||
pos = _write_str(buf, pos, "null")
|
||||
|
||||
elif val.vtype == JSON_BOOL:
|
||||
if val.bool_val != 0:
|
||||
pos = _write_str(buf, pos, "true")
|
||||
else:
|
||||
pos = _write_str(buf, pos, "false")
|
||||
|
||||
elif val.vtype == JSON_INT:
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if tmp != None:
|
||||
snprintf(tmp, 32, "%lld", val.int_val)
|
||||
pos = _write_str(buf, pos, tmp)
|
||||
|
||||
elif val.vtype == JSON_FLOAT:
|
||||
tmp2: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if tmp2 != None:
|
||||
snprintf(tmp2, 32, "%.6g", val.float_val)
|
||||
pos = _write_str(buf, pos, tmp2)
|
||||
|
||||
elif val.vtype == JSON_STRING:
|
||||
pos = _write_string_escaped(buf, pos, val.str_val)
|
||||
|
||||
elif val.vtype == JSON_ARRAY:
|
||||
if val.child == None:
|
||||
pos = _write_str(buf, pos, "[]")
|
||||
return pos
|
||||
pos = _write_char(buf, pos, '[')
|
||||
cur: JsonValue | t.CPtr = val.child
|
||||
first: bool = True
|
||||
while cur != None:
|
||||
if not first:
|
||||
pos = _write_char(buf, pos, ',')
|
||||
pos = _write_value(buf, pos, cur, pool)
|
||||
first = False
|
||||
cur = cur.next
|
||||
pos = _write_char(buf, pos, ']')
|
||||
|
||||
elif val.vtype == JSON_OBJECT:
|
||||
if val.child == None:
|
||||
pos = _write_str(buf, pos, "{}")
|
||||
return pos
|
||||
pos = _write_char(buf, pos, '{')
|
||||
cur2: JsonValue | t.CPtr = val.child
|
||||
first2: bool = True
|
||||
while cur2 != None:
|
||||
if not first2:
|
||||
pos = _write_char(buf, pos, ',')
|
||||
pos = _write_string_escaped(buf, pos, cur2.key)
|
||||
pos = _write_char(buf, pos, ':')
|
||||
pos = _write_value(buf, pos, cur2, pool)
|
||||
first2 = False
|
||||
cur2 = cur2.next
|
||||
pos = _write_char(buf, pos, '}')
|
||||
|
||||
return pos
|
||||
|
||||
|
||||
def write(pool: memhub.MemManager | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> t.CChar | t.CPtr:
|
||||
"""将 JsonValue 序列化为 JSON 字符串"""
|
||||
buf: t.CChar | t.CPtr = pool.alloc(4096)
|
||||
if buf == None:
|
||||
return None
|
||||
end_pos: t.CSizeT = _write_value(buf, 0, val, pool)
|
||||
buf[end_pos] = '\0'
|
||||
return buf
|
||||
@@ -0,0 +1,450 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
|
||||
# ============================================================
|
||||
# LinkedNode: 非多态继承基类(@t.NoVTable)
|
||||
#
|
||||
# 子类继承此类即"启用"标准链表/树形结构能力:
|
||||
# - 双向兄弟链表(next/prev)→ O(1) 删除
|
||||
# - 父子树结构(child/last_child/parent)→ O(1) 追加子节点
|
||||
# - 子节点计数(child_count)
|
||||
#
|
||||
# 字段展平嵌入子类,无 vtable 开销(对应 C++ 非多态继承)。
|
||||
# OOP 方法通过 _generate_inherited_method_wrappers 自动生成子类包装
|
||||
# (self bitcast 为父类指针后调用),子类可直接调用继承的方法。
|
||||
#
|
||||
# 用法:
|
||||
# class MyNode(LinkedNode):
|
||||
# value: t.CInt
|
||||
# root: MyNode = MyNode()
|
||||
# child: MyNode = MyNode()
|
||||
# root.append(child) # OOP 调用,self = root
|
||||
# child.detach() # 从兄弟链摘除(分离自己)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class LinkedNode:
|
||||
next: "LinkedNode" | t.CPtr # 下一个兄弟节点
|
||||
prev: "LinkedNode" | t.CPtr # 上一个兄弟节点(双向链表,O(1) 删除)
|
||||
child: "LinkedNode" | t.CPtr # 第一个子节点
|
||||
last_child: "LinkedNode" | t.CPtr # 最后一个子节点(O(1) 追加)
|
||||
parent: "LinkedNode" | t.CPtr # 父节点
|
||||
child_count: t.CSizeT # 子节点数
|
||||
|
||||
def append(self, node: "LinkedNode" | t.CPtr):
|
||||
"""将 node 追加为 self 的最后一个子节点(O(1))。
|
||||
|
||||
若 node 已在某链表中,调用方应先 node.detach() 再 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):
|
||||
"""将 node 插入为 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):
|
||||
"""在 node 之前插入 new_node(node 必须是 self 的子节点,O(1))"""
|
||||
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):
|
||||
"""在 node 之后插入 new_node(node 必须是 self 的子节点,O(1))"""
|
||||
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):
|
||||
"""从 self 的子链表中摘除 node(O(1))。node 必须是 self 的直接子节点。"""
|
||||
if self is None or node is None: return
|
||||
# 修复 prev.next
|
||||
if node.prev is not None:
|
||||
node.prev.next = node.next
|
||||
else:
|
||||
self.child = node.next
|
||||
# 修复 next.prev
|
||||
if node.next is not None:
|
||||
node.next.prev = node.prev
|
||||
else:
|
||||
self.last_child = node.prev
|
||||
# 清除 node 的兄弟/父链接
|
||||
node.next = None
|
||||
node.prev = None
|
||||
node.parent = None
|
||||
if self.child_count > 0:
|
||||
self.child_count -= 1
|
||||
|
||||
def detach(self):
|
||||
"""将 self 从其所在兄弟链表中摘除(O(1))。
|
||||
|
||||
调用后 self 的 next/prev/parent 被清空,child 链不受影响。
|
||||
"""
|
||||
if self is None: return
|
||||
# 修复 prev.next
|
||||
if self.prev is not None:
|
||||
self.prev.next = self.next
|
||||
elif self.parent is not None:
|
||||
self.parent.child = self.next
|
||||
# 修复 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
|
||||
# 递减父节点计数
|
||||
if self.parent is not None:
|
||||
if self.parent.child_count > 0:
|
||||
self.parent.child_count -= 1
|
||||
# 清除 self 链接
|
||||
self.next = None
|
||||
self.prev = None
|
||||
self.parent = None
|
||||
|
||||
def unlink(self):
|
||||
"""断开 self 的所有连接(兄弟 + 父子),不递归处理子节点。
|
||||
|
||||
调用后 self 成为孤立节点,但其 child 链仍指向原子节点
|
||||
(子节点的 parent 仍指向 self)。若需完全隔离,调用方应
|
||||
先逐个 self.remove_child 子节点。
|
||||
"""
|
||||
if self is None: return
|
||||
# 先从兄弟链摘除
|
||||
self.detach()
|
||||
# 再断开父子链接
|
||||
self.child = None
|
||||
self.last_child = None
|
||||
self.child_count = 0
|
||||
|
||||
def has_children(self) -> t.CInt:
|
||||
"""返回 1 若有子节点,否则 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:
|
||||
"""返回第 index 个子节点(O(n),从 0 开始),越界返回 None"""
|
||||
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:
|
||||
"""遍历计算子节点数(O(n)),用于校验 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:
|
||||
"""返回兄弟链表的头节点(沿 prev 回溯)"""
|
||||
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:
|
||||
"""返回兄弟链表的尾节点(沿 next 前进)"""
|
||||
if self is None: return None
|
||||
cur: "LinkedNode" | t.CPtr = self
|
||||
while cur.next is not None:
|
||||
cur = cur.next
|
||||
return cur
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SListNode: 单向链表节点(@t.NoVTable)
|
||||
#
|
||||
# 轻量级单向链表,仅 Next 指针,无 prev/parent/child。
|
||||
# 适用于队列/栈/简单链场景(如 llvmlite 的 Param/BasicBlock/Function/Line/Value)。
|
||||
# O(1) 追加需调用方维护 tail 指针(append_after);
|
||||
# O(n) 追加仅需 head(append)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class SListNode:
|
||||
Next: "SListNode" | t.CPtr # 下一个节点
|
||||
|
||||
def append(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr:
|
||||
"""将 node 追加到链表末尾(O(n)),返回 self(head)。
|
||||
|
||||
若 self 为 None,应直接使用 node 作为 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:
|
||||
"""将 node 追加到 self 之后(O(1)),返回新的 tail(即 node)。
|
||||
|
||||
调用方需自行维护 head 指针。若 self 为 None,返回 node 作为首节点。
|
||||
"""
|
||||
if node is None: return self
|
||||
node.Next = None
|
||||
if self is not None:
|
||||
self.Next = node
|
||||
return node
|
||||
|
||||
def count(self) -> t.CSizeT:
|
||||
"""遍历计算链表长度(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:
|
||||
"""返回第 index 个节点(O(n),从 0 开始),越界返回 None"""
|
||||
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:
|
||||
"""从链表中移除 node(O(n)),返回新的 head(self)。
|
||||
|
||||
node 的 Next 被清空。若 node 是 head,返回 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]: 泛型单向链表节点(@t.NoVTable + PEP 695 泛型)
|
||||
#
|
||||
# 相比 SListNode(非泛型,Next: SListNode|CPtr),GSListNode[T] 的 Next
|
||||
# 字段类型为 T|CPtr,特化后直接是具体节点类型,无需向下转型。
|
||||
#
|
||||
# 递归泛型用法(子类继承自身特化版本):
|
||||
# class GNode(GSListNode[GNode]):
|
||||
# value: t.CInt
|
||||
# # 此时 GNode.Next: GNode|CPtr(强类型,无转型)
|
||||
#
|
||||
# 技术验证点:
|
||||
# 1. 递归泛型 class GNode(GSListNode[GNode])
|
||||
# 2. @t.NoVTable + 泛型组合
|
||||
# 3. 泛型类作字段类型 list: GSList[GNode]
|
||||
# 4. 泛型方法继承(GSList[T].append 在特化后可用)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class GSListNode[T]:
|
||||
Next: T | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GSList[T]: 泛型单向链表容器(@t.NoVTable + PEP 695 泛型)
|
||||
#
|
||||
# 持有 Head/Tail/Count,提供 O(1) append 和 O(n) at。
|
||||
# 节点类型 T 必须继承 GSListNode[T](以获得 Next 字段)。
|
||||
#
|
||||
# 用法:
|
||||
# list: GSList[GNode] | t.CPtr = GSList[GNode]()
|
||||
# list.append(node) # 方法调用,非全局函数
|
||||
# ============================================================
|
||||
@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):
|
||||
"""将 node 追加到链表末尾(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:
|
||||
"""返回节点数(O(1))"""
|
||||
return self.Count
|
||||
|
||||
def at(self, index: t.CSizeT) -> T | t.CPtr:
|
||||
"""返回第 index 个节点(O(n),从 0 开始),越界返回 None"""
|
||||
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]: 泛型树节点(@t.NoVTable + PEP 695 泛型)
|
||||
#
|
||||
# 强类型版本的 LinkedNode,所有指针字段类型为 T|t.CPtr。
|
||||
# 提供:
|
||||
# - 双向兄弟链表(Next/Prev)→ O(1) 删除
|
||||
# - 父子树结构(Child/LastChild/Parent)→ O(1) 追加子节点
|
||||
# - 子节点计数(Count)
|
||||
#
|
||||
# 递归泛型用法(子类继承自身特化版本):
|
||||
# @t.CVTable
|
||||
# class AST(GTreeNode[AST]):
|
||||
# def kind(self) -> t.CInt:
|
||||
# return 0
|
||||
# # 此时 AST.Next/Prev/Child/LastChild/Parent 均为 AST|t.CPtr(强类型)
|
||||
#
|
||||
# 字段展平嵌入子类,无 vtable 开销(对应 C++ 非多态继承)。
|
||||
# 子类若为 @t.CVTable,则获得自己的 vtable(offset 0),
|
||||
# GTreeNode 字段展平在 vtable 之后。
|
||||
#
|
||||
# OOP 方法通过 _generate_inherited_method_wrappers 自动生成子类包装
|
||||
# (self bitcast 为父类指针后调用),子类可直接调用继承的方法。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class GTreeNode[T]:
|
||||
Next: T | t.CPtr # 下一个兄弟节点
|
||||
Prev: T | t.CPtr # 上一个兄弟节点(双向链表,O(1) 删除)
|
||||
Child: T | t.CPtr # 第一个子节点
|
||||
LastChild: T | t.CPtr # 最后一个子节点(O(1) 追加)
|
||||
Parent: T | t.CPtr # 父节点
|
||||
Count: t.CSizeT # 子节点数
|
||||
|
||||
def append(self, node: T | t.CPtr):
|
||||
"""将 node 追加为 self 的最后一个子节点(O(1))。
|
||||
|
||||
若 node 已在某链表中,调用方应先 node.detach() 再 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):
|
||||
"""将 node 插入为 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):
|
||||
"""将 self 从其所在兄弟链表中摘除(O(1))。
|
||||
|
||||
调用后 self 的 Next/Prev/Parent 被清空,Child 链不受影响。
|
||||
"""
|
||||
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:
|
||||
"""返回 1 若有子节点,否则 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:
|
||||
"""返回第 index 个子节点(O(n),从 0 开始),越界返回 None"""
|
||||
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:
|
||||
"""遍历计算子节点数(O(n)),用于校验 Count"""
|
||||
if self is None: return 0
|
||||
n: t.CSizeT = 0
|
||||
cur: T | t.CPtr = self.Child
|
||||
while cur is not None:
|
||||
n += 1
|
||||
cur = cur.Next
|
||||
return n
|
||||
@@ -0,0 +1,301 @@
|
||||
# llvmlite 设计方案
|
||||
|
||||
用 TransPyC 自身实现的轻量级 LLVM IR 文本生成库,替代 Python `llvmlite` 依赖,为自举(见 `wiki/13-bootstrapping.md` 路径 B)铺路。
|
||||
|
||||
## 1. 目标与定位
|
||||
|
||||
- **输入**:类型/值/指令的语义对象
|
||||
- **输出**:合法的 LLVM IR 文本(`.ll`),可直接喂给 `llc`
|
||||
- **不做什么**:不解析 IR、不做优化、不绑定 LLVM C API(纯文本生成)
|
||||
- **自举约束**:本库必须能用当前 TransPyC 编译器完整编译,不得依赖任何 Python 运行时
|
||||
|
||||
## 2. 核心设计决策
|
||||
|
||||
### 2.1 类型系统用 `t.REnum`(tagged union)
|
||||
|
||||
LLVM 类型变体少、无通用字段、字段都是指针/小整数、操作主要通过 `match` 分派 —— 完全契合 REnum 的 tag+union 模型。
|
||||
|
||||
### 2.2 指令 opcode 用 `t.CEnum`
|
||||
|
||||
指令类别(Binary/Unary/Cast/Memory/Terminator/Compare)与具体 opcode(Add/Sub/Load/Store/Br/Ret/...)用 `t.CEnum` 组织,类型安全且零开销。
|
||||
|
||||
### 2.3 IR 文本生成用 `viperlib.snprintf`
|
||||
|
||||
所有 IR 文本通过 `viperlib.snprintf(buf, size, fmt, *args)` 格式化写入缓冲区,避免手写逐字符拼接。`snprintf` 已支持宽度/精度/符号/`%s`/`%d`/`%x` 等,足够覆盖 IR 语法。
|
||||
|
||||
### 2.4 对象分配用普通类 + `mpool`
|
||||
|
||||
像 `mbuddy` 一样用普通类(无 `__new__`),由调用方注入 `mpool.MPool` 做批量分配。库内部不持有全局 `mbuddy`,遵循项目约定(`_mbuddy` 指针由 `os.py` 或调用方设置)。
|
||||
|
||||
---
|
||||
|
||||
## 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__.py # 公共导出 + 便捷工厂函数
|
||||
├── __types.py # LLVMType (REnum) + 类型构造/打印
|
||||
├── __values.py # Value/Constant/SSA 值表示
|
||||
├── __module.py # Module 容器(函数列表 + 目标三元组 + 输出 .ll)
|
||||
├── __function.py # Function + BasicBlock + 参数管理
|
||||
├── __builder.py # IRBuilder(指令发射 + SSA 命名 + 块跳转)
|
||||
└── README.md # 本文件
|
||||
```
|
||||
|
||||
### 职责划分
|
||||
|
||||
- `__types.py`:`LLVMType` REnum 定义 + `TypePrint(buf, ty)` 将类型序列化为 IR 文本(如 `i32`/`i32*`/`{i32, i8*}`)
|
||||
- `__values.py`:`Value` 表示一个 SSA 值(`%0`/`%result`/常量),含类型指针 + 名字 + 是否常量
|
||||
- `__module.py`:`Module` 持有函数链表 + 目标三元组 + 数据布局,`ModulePrint` 输出完整 `.ll`
|
||||
- `__function.py`:`Function` 持有基本块链表 + 参数 + 返回类型;`BasicBlock` 持有指令文本缓冲
|
||||
- `__builder.py`:`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__.py` 导出)
|
||||
|
||||
```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.py`**:提供 `snprintf` / `sprintf`
|
||||
- **`includes/mpool.py`**:提供 `MPool` 内存池
|
||||
- **`includes/string.py`**:提供 `strcpy`/`strlen`/`memcpy`
|
||||
- **`includes/ast/`**:参考其"胖节点 + mpool + CEnum 常量"的组织方式(但类型系统用 REnum 而非胖节点)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,456 @@
|
||||
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
|
||||
# ============================================================
|
||||
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) 追加。
|
||||
# ============================================================
|
||||
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=无属性
|
||||
# ============================================================
|
||||
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=无属性
|
||||
# ============================================================
|
||||
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 顺序一致。
|
||||
"""
|
||||
if func is None or block is None: return
|
||||
blocks: GSList | 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_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 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 规范:标识符以数字开头或含特殊字符(如 '.')时必须
|
||||
# 用双引号包围。SHA1 命名空间的函数名格式为 "sha1hex.funcname"
|
||||
# (含 '.'),以 hex 字符开头(可能以数字开头),因此需要加引号。
|
||||
# 普通函数名(如 printf/malloc/main)不含特殊字符,不加引号。
|
||||
# ============================================================
|
||||
def _ll_name_needs_quote(name: str) -> t.CInt:
|
||||
"""检查 LLVM 标识符是否需要加引号(以数字开头或含 '.')
|
||||
|
||||
例外: LLVM 内联函数名(如 llvm.memcpy/llvm.memset)以 'llvm.' 开头,
|
||||
虽含 '.',但不能加引号——加引号后 LLVM 解析器不识别为内联函数,
|
||||
导致 declare/call 签名不匹配(Intrinsic called with incompatible signature)。
|
||||
"""
|
||||
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)
|
||||
# 豁免 llvm.* 前缀的内联函数名
|
||||
if name_len >= 5:
|
||||
if name[0] == 'l' and name[1] == 'l' and name[2] == 'v' and name[3] == 'm' and name[4] == '.':
|
||||
return 0
|
||||
i: t.CSizeT = 0
|
||||
while i < name_len:
|
||||
if name[i] == '.':
|
||||
return 1
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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
|
||||
|
||||
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:
|
||||
_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 声明不打印参数名
|
||||
if func.IsDeclared == 0 and 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
|
||||
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")
|
||||
line = line.Next
|
||||
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)
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
remain: t.CSizeT = dst_size - dlen
|
||||
if remain <= 0: return
|
||||
i: t.CSizeT = 0
|
||||
while i < slen and i + 1 < remain:
|
||||
dst[dlen + i] = src[i]
|
||||
i += 1
|
||||
dst[dlen + i] = '\0'
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 字段访问器(供其他模块绕过 stub 类型限制使用)
|
||||
#
|
||||
# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型
|
||||
# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过
|
||||
# 字段访问(不生成 GEP,不报错),字段值永远为 null。
|
||||
#
|
||||
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问
|
||||
# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。
|
||||
# ============================================================
|
||||
def function_get_name(func: Function | t.CPtr) -> t.CChar | t.CPtr:
|
||||
"""获取函数名"""
|
||||
if func is None:
|
||||
return None
|
||||
return func.Name
|
||||
|
||||
|
||||
def function_get_ret_ty(func: Function | t.CPtr) -> LLVMType | t.CPtr:
|
||||
"""获取函数返回类型"""
|
||||
if func is None:
|
||||
return None
|
||||
return func.RetTy
|
||||
|
||||
|
||||
def function_get_params(func: Function | t.CPtr) -> GSList[Param] | t.CPtr:
|
||||
"""获取函数参数链表容器"""
|
||||
if func is None:
|
||||
return None
|
||||
return func.Params
|
||||
|
||||
|
||||
def function_get_param_head(func: Function | t.CPtr) -> Param | t.CPtr:
|
||||
"""获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)"""
|
||||
if func is None:
|
||||
return None
|
||||
if func.Params is None:
|
||||
return None
|
||||
return func.Params.Head
|
||||
|
||||
|
||||
def function_get_next(func: Function | t.CPtr) -> Function | t.CPtr:
|
||||
"""获取链表下一个函数"""
|
||||
if func is None:
|
||||
return None
|
||||
return func.Next
|
||||
|
||||
|
||||
def function_is_declared(func: Function | t.CPtr) -> t.CInt:
|
||||
"""获取函数是否为声明(1=declare 仅声明, 0=define 定义)"""
|
||||
if func is None:
|
||||
return 0
|
||||
return func.IsDeclared
|
||||
|
||||
|
||||
def param_get_name(param: Param | t.CPtr) -> t.CChar | t.CPtr:
|
||||
"""获取参数名"""
|
||||
if param is None:
|
||||
return None
|
||||
return param.Name
|
||||
|
||||
|
||||
def param_get_ty(param: Param | t.CPtr) -> LLVMType | t.CPtr:
|
||||
"""获取参数类型"""
|
||||
if param is None:
|
||||
return None
|
||||
return param.Ty
|
||||
|
||||
|
||||
def param_get_next(param: Param | t.CPtr) -> Param | t.CPtr:
|
||||
"""获取链表下一个参数"""
|
||||
if param is None:
|
||||
return None
|
||||
return param.Next
|
||||
@@ -0,0 +1,403 @@
|
||||
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,
|
||||
)
|
||||
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,
|
||||
build_alloca, 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,
|
||||
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 转义
|
||||
# 这里简单处理: 直接复制原始字节,末尾加 \00
|
||||
init_buf: t.CChar | t.CPtr = pool.alloc(slen + 8) # c"..." + \00 + "
|
||||
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:
|
||||
init_buf[pos] = text[i]
|
||||
pos += 1
|
||||
i += 1
|
||||
# 末尾 NUL 字节
|
||||
init_buf[pos] = '\\'
|
||||
pos += 1
|
||||
init_buf[pos] = '0'
|
||||
pos += 1
|
||||
init_buf[pos] = '0'
|
||||
pos += 1
|
||||
init_buf[pos] = '"'
|
||||
pos += 1
|
||||
init_buf[pos] = '\0'
|
||||
gv.Initializer = init_buf
|
||||
|
||||
module_add_global(mod, gv)
|
||||
return gv
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 便捷工厂: 创建带初始化值的整数全局变量
|
||||
# ============================================================
|
||||
def create_global_int(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
|
||||
name: t.CChar | t.CPtr, bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr:
|
||||
"""创建整数全局变量并添加到模块
|
||||
|
||||
生成 LLVM IR:
|
||||
@<name> = global i<bits> <val>
|
||||
"""
|
||||
# 创建整数类型
|
||||
ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||||
if ty is None: return None
|
||||
string.memset(ty, 0, LLVMType.__sizeof__())
|
||||
c.DerefAs(ty, LLVMType.Int(bits))
|
||||
|
||||
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
|
||||
gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, ty)
|
||||
if gv is None: return None
|
||||
|
||||
# 构造初始化值文本: "42" (类型由 _print_global 单独打印)
|
||||
init_buf: t.CChar | t.CPtr = pool.alloc(48)
|
||||
if init_buf is None: return None
|
||||
viperlib.snprintf(init_buf, 48, "%lld", val)
|
||||
gv.Initializer = init_buf
|
||||
|
||||
module_add_global(mod, gv)
|
||||
return gv
|
||||
|
||||
|
||||
# ============================================================
|
||||
# LLVMModuleCore: 模块/函数/值创建核心,封装 pool 避免重复传参
|
||||
#
|
||||
# 用法:
|
||||
# mcore: LLVMModuleCore | t.CPtr = LLVMModuleCore(pool)
|
||||
# mod: LLVMModule | t.CPtr = mcore.NewModule("test")
|
||||
# func: Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32)
|
||||
# val: Value | t.CPtr = mcore.ConstInt32(42)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class LLVMModuleCore:
|
||||
"""模块/函数/值创建核心,封装 pool 避免每次创建都传 pool"""
|
||||
Pool: memhub.MemBuddy | t.CPtr
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
|
||||
self.Pool = pool
|
||||
|
||||
# ---- 模块操作 ----
|
||||
def NewModule(self, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr:
|
||||
return new_module(self.Pool, name)
|
||||
|
||||
def CreateFunction(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
|
||||
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
|
||||
return create_function(self.Pool, mod, name, ret_ty)
|
||||
|
||||
def CreateDeclare(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
|
||||
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
|
||||
"""创建函数声明(declare,无函数体)"""
|
||||
return create_declare(self.Pool, mod, name, ret_ty)
|
||||
|
||||
def AddParam(self, func: Function | t.CPtr, ty: LLVMType | t.CPtr,
|
||||
name: t.CChar | t.CPtr) -> Param | t.CPtr:
|
||||
return add_param(self.Pool, func, ty, name)
|
||||
|
||||
def FunctionSetAttrs(self, func: Function | t.CPtr, attrs: t.CChar | t.CPtr):
|
||||
"""设置函数级属性文本"""
|
||||
function_set_attrs(func, attrs)
|
||||
|
||||
def ParamSetAttrs(self, param: Param | t.CPtr, attrs: t.CChar | t.CPtr):
|
||||
"""设置参数属性文本"""
|
||||
param_set_attrs(param, attrs)
|
||||
|
||||
def CreateBlock(self, func: Function | t.CPtr,
|
||||
name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
|
||||
return create_block(self.Pool, func, name)
|
||||
|
||||
def NewBuilder(self, func: Function | t.CPtr) -> IRBuilder | t.CPtr:
|
||||
return new_builder(self.Pool, func)
|
||||
|
||||
# ---- 全局变量 ----
|
||||
def NewGlobal(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
|
||||
ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr:
|
||||
"""创建全局变量并添加到模块"""
|
||||
name_dup: t.CChar | t.CPtr = _str_dup(self.Pool, name)
|
||||
gv: GlobalVariable | t.CPtr = new_global_variable(self.Pool, name_dup, ty)
|
||||
if gv is not None:
|
||||
module_add_global(mod, gv)
|
||||
return gv
|
||||
|
||||
def CreateGlobalString(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
|
||||
text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr:
|
||||
"""创建字符串常量全局变量"""
|
||||
return create_global_string(self.Pool, mod, name, text)
|
||||
|
||||
def CreateGlobalInt(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
|
||||
bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr:
|
||||
"""创建带初始化值的整数全局变量"""
|
||||
return create_global_int(self.Pool, mod, name, bits, val)
|
||||
|
||||
def GlobalSetConstant(self, gv: GlobalVariable | t.CPtr, is_const: t.CInt):
|
||||
global_set_constant(gv, is_const)
|
||||
|
||||
def GlobalSetLinkage(self, gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr):
|
||||
global_set_linkage(gv, linkage)
|
||||
|
||||
def GlobalSetUnnamedAddr(self, gv: GlobalVariable | t.CPtr, level: t.CInt):
|
||||
global_set_unnamed_addr(gv, level)
|
||||
|
||||
def GlobalSetSection(self, gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr):
|
||||
global_set_section(gv, section)
|
||||
|
||||
# ---- 值创建 ----
|
||||
def ConstInt(self, bits: t.CInt, val: t.CInt64T) -> Value | t.CPtr:
|
||||
return const_int(self.Pool, bits, val)
|
||||
|
||||
def ConstInt32(self, val: t.CInt64T) -> Value | t.CPtr:
|
||||
return const_int32(self.Pool, val)
|
||||
|
||||
def ConstInt64(self, val: t.CInt64T) -> Value | t.CPtr:
|
||||
return const_int64(self.Pool, val)
|
||||
|
||||
def ConstFloat(self, ty: LLVMType | t.CPtr, val: t.CDouble) -> Value | t.CPtr:
|
||||
return ConstFloat(self.Pool, ty, val)
|
||||
|
||||
def SSAValue(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr:
|
||||
return SSAValue(self.Pool, ty, name)
|
||||
|
||||
def ConstNull(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr:
|
||||
return ConstNull(self.Pool, ty, name)
|
||||
|
||||
# ---- 打印 ----
|
||||
def PrintValue(self, buf: t.CChar | t.CPtr, size: t.CSizeT, val: Value | t.CPtr):
|
||||
ValuePrint(buf, size, val, self.Pool)
|
||||
|
||||
def PrintFunction(self, buf: t.CChar | t.CPtr, size: t.CSizeT, func: Function | t.CPtr):
|
||||
FunctionPrint(buf, size, func, self.Pool)
|
||||
|
||||
def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, mod: LLVMModule | t.CPtr):
|
||||
LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL)
|
||||
|
||||
# ---- SSA 验证 ----
|
||||
def NewVerifyResult(self, buf_size: t.CSizeT) -> VerifyResult | t.CPtr:
|
||||
"""创建验证结果对象(buf_size 为错误消息缓冲区大小)"""
|
||||
return _new_verify_result(self.Pool, buf_size)
|
||||
|
||||
def VerifyFunction(self, func: Function | t.CPtr,
|
||||
result: VerifyResult | t.CPtr) -> t.CInt:
|
||||
"""验证单个函数的 SSA 正确性,返回错误数(0=通过)"""
|
||||
return verify_function(self.Pool, func, result)
|
||||
|
||||
def VerifyModule(self, mod: LLVMModule | t.CPtr,
|
||||
result: VerifyResult | t.CPtr) -> t.CInt:
|
||||
"""验证模块中所有函数的 SSA 正确性,返回错误数(0=通过)"""
|
||||
return verify_module(self.Pool, mod, result)
|
||||
@@ -0,0 +1,504 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
import memhub
|
||||
from linkedlist import GSList, GSListNode
|
||||
from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct
|
||||
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)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 工厂函数
|
||||
# ============================================================
|
||||
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):
|
||||
"""将函数追加到模块函数链表(O(1))"""
|
||||
if mod is None or func is None: return
|
||||
func.Next = None
|
||||
if mod.FuncHead is None:
|
||||
mod.FuncHead = func
|
||||
else:
|
||||
mod.FuncTail.Next = func
|
||||
mod.FuncTail = func
|
||||
mod.FuncCount += 1
|
||||
|
||||
|
||||
def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr):
|
||||
"""将全局变量追加到模块全局变量链表(O(1))"""
|
||||
if mod is None or gv is None: return
|
||||
gv.Next = None
|
||||
if mod.GlobalHead is None:
|
||||
mod.GlobalHead = gv
|
||||
else:
|
||||
mod.GlobalTail.Next = gv
|
||||
mod.GlobalTail = gv
|
||||
mod.GlobalCount += 1
|
||||
|
||||
|
||||
def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr):
|
||||
"""设置目标三元组"""
|
||||
if mod is None: return
|
||||
mod.TargetTriple = triple
|
||||
|
||||
|
||||
def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr):
|
||||
"""设置数据布局"""
|
||||
if mod is None: return
|
||||
mod.DataLayout = layout
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 命名结构体类型管理
|
||||
# ============================================================
|
||||
def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
|
||||
|
||||
非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。
|
||||
按 Name 去重,相同名称的类型只保留第一个。
|
||||
"""
|
||||
if mod 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
|
||||
# 去重检查
|
||||
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
while cur is not None:
|
||||
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
|
||||
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
|
||||
node.Next = None
|
||||
if mod.NamedTypeHead is None:
|
||||
mod.NamedTypeHead = node
|
||||
else:
|
||||
mod.NamedTypeTail.Next = node
|
||||
mod.NamedTypeTail = node
|
||||
mod.NamedTypeCount += 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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:
|
||||
"""检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义"""
|
||||
if mod is None or name is None:
|
||||
return 0
|
||||
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
while cur is not None:
|
||||
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 _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: LLVMModule | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""递归扫描类型树,为跨模块结构体引用添加 opaque 声明"""
|
||||
if ty is None or mod is None or pool is None:
|
||||
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 类型并添加到模块
|
||||
opaque_ty: LLVMType | t.CPtr = Struct(pool, None, 0, sname)
|
||||
if opaque_ty is not None:
|
||||
module_add_named_type(mod, pool, opaque_ty)
|
||||
case _:
|
||||
_scan_type_for_cross_module_refs(pool, mod, pointee)
|
||||
case LLVMType.Array(elem_ty, acount):
|
||||
if elem_ty is not None:
|
||||
_scan_type_for_cross_module_refs(pool, mod, elem_ty)
|
||||
case _:
|
||||
pass
|
||||
|
||||
|
||||
def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""为类型中的跨模块结构体引用添加 opaque 声明
|
||||
|
||||
当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时,
|
||||
如果该名称未在模块中定义,则添加 opaque 声明。
|
||||
"""
|
||||
_scan_type_for_cross_module_refs(pool, mod, 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):
|
||||
"""将模块 mod 序列化为 .ll 文本写入 buf"""
|
||||
if mod 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 mod.Name is not None:
|
||||
_append_cstr(buf, size, mod.Name)
|
||||
_append_cstr(buf, size, "'\n")
|
||||
|
||||
# 目标三元组
|
||||
if mod.TargetTriple is not None:
|
||||
_append_cstr(buf, size, "target triple = \"")
|
||||
_append_cstr(buf, size, mod.TargetTriple)
|
||||
_append_cstr(buf, size, "\"\n")
|
||||
|
||||
# 数据布局
|
||||
if mod.DataLayout is not None:
|
||||
_append_cstr(buf, size, "target datalayout = \"")
|
||||
_append_cstr(buf, size, mod.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 = mod.FuncHead
|
||||
while func_scan is not None:
|
||||
if func_scan.RetTy is not None:
|
||||
module_ensure_opaque_for_type(mod, 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:
|
||||
module_ensure_opaque_for_type(mod, pool, param_scan.Ty)
|
||||
param_scan = param_scan.Next
|
||||
func_scan = func_scan.Next
|
||||
nt: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
while nt is not None:
|
||||
if nt.Ty is not None:
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
PrintStructDefinition(ty_buf, 256, nt.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
_append_cstr(buf, size, "\n")
|
||||
nt = nt.Next
|
||||
|
||||
if mod.NamedTypeHead is not None:
|
||||
_append_cstr(buf, size, "\n")
|
||||
|
||||
# 全局变量
|
||||
gv: GlobalVariable | t.CPtr = mod.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 mod.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB):
|
||||
_append_cstr(buf, size, "\n")
|
||||
elif mod.GlobalHead is not None and mode == OUTPUT_TEXT:
|
||||
# text 模式下如果输出了全局变量,也加空行
|
||||
had_global: t.CInt = 0
|
||||
gv2: GlobalVariable | t.CPtr = mod.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 = mod.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 _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(128)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
TypePrint(ty_buf, 128, 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(128)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
TypePrint(ty_buf, 128, 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)
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
remain: t.CSizeT = dst_size - dlen
|
||||
if remain <= 0: return
|
||||
i: t.CSizeT = 0
|
||||
while i < slen and i + 1 < remain:
|
||||
dst[dlen + i] = src[i]
|
||||
i += 1
|
||||
dst[dlen + i] = '\0'
|
||||
@@ -0,0 +1,524 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import viperlib
|
||||
import string
|
||||
import memhub
|
||||
from linkedlist import GSListNode
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ParamNode: 函数参数类型链表节点
|
||||
# 继承 GSListNode[ParamNode] 获取强类型 Next: ParamNode|CPtr
|
||||
# Ty 用 t.CVoid | t.CPtr 前向引用,使用时转型为 (LLVMType | t.CPtr)
|
||||
# ============================================================
|
||||
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: LLVMType | t.CPtr = _new_type(pool)
|
||||
if ptr is None: return None
|
||||
c.DerefAs(ptr, LLVMType.Ptr(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) -> 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 用于递归打印子类型时分配临时缓冲区。
|
||||
"""
|
||||
if ty is None or buf is None or size == 0:
|
||||
return
|
||||
buf[0] = '\0'
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
viperlib.snprintf(buf, size, "i%d", bits)
|
||||
case LLVMType.Ptr(pointee):
|
||||
# 先打印 pointee,再追加 '*'
|
||||
TypePrint(buf, size, pointee, pool)
|
||||
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)
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if tmp is not None:
|
||||
TypePrint(tmp, 128, elem_ty, pool)
|
||||
_strappend(buf, size, tmp)
|
||||
_strappend(buf, size, "]")
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
if name is not None:
|
||||
# 命名结构体: %"name"
|
||||
buf[0] = '%'
|
||||
buf[1] = '"'
|
||||
buf[2] = '\0'
|
||||
_strappend(buf, size, name)
|
||||
_strappend(buf, size, "\"")
|
||||
else:
|
||||
# 匿名结构体: {ty1, ty2, ...}
|
||||
_print_struct_body(buf, size, fields, pool)
|
||||
case LLVMType.Func(ret, params, count):
|
||||
# ret (ty1, ty2, ...)
|
||||
TypePrint(buf, size, ret, pool)
|
||||
_strappend(buf, size, " (")
|
||||
cur2: ParamNode | t.CPtr = params
|
||||
first2: t.CInt = 1
|
||||
tmp3: t.CChar | t.CPtr = pool.alloc(128)
|
||||
while cur2 is not None:
|
||||
if first2 == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
if tmp3 is not None:
|
||||
TypePrint(tmp3, 128, cur2.Ty, pool)
|
||||
_strappend(buf, size, tmp3)
|
||||
cur2 = cur2.Next
|
||||
first2 = 0
|
||||
_strappend(buf, size, ")")
|
||||
case LLVMType.Void():
|
||||
string.strcpy(buf, "void")
|
||||
case LLVMType.Label():
|
||||
string.strcpy(buf, "label")
|
||||
case LLVMType.Metadata():
|
||||
string.strcpy(buf, "metadata")
|
||||
case LLVMType.Float(bits):
|
||||
if bits == 16:
|
||||
string.strcpy(buf, "half")
|
||||
elif bits == 32:
|
||||
string.strcpy(buf, "float")
|
||||
elif bits == 64:
|
||||
string.strcpy(buf, "double")
|
||||
elif bits == 128:
|
||||
string.strcpy(buf, "fp128")
|
||||
else:
|
||||
viperlib.snprintf(buf, size, "float%x", bits)
|
||||
case _:
|
||||
string.strcpy(buf, "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)
|
||||
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):
|
||||
"""打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容)"""
|
||||
if buf is None or size == 0:
|
||||
return
|
||||
_strappend(buf, size, "{")
|
||||
cur: ParamNode | t.CPtr = fields
|
||||
first: t.CInt = 1
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(128)
|
||||
while cur is not None:
|
||||
if first == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
if tmp is not None:
|
||||
TypePrint(tmp, 128, cur.Ty, pool)
|
||||
_strappend(buf, size, tmp)
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
_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==0 且 fields is None 时,输出 opaque 声明: %"name" = type opaque
|
||||
"""
|
||||
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
|
||||
buf[0] = '%'
|
||||
buf[1] = '"'
|
||||
buf[2] = '\0'
|
||||
_strappend(buf, size, name)
|
||||
# opaque 类型: fcount==0 且 fields is None(跨模块前向声明)
|
||||
if fcount == 0 and fields is None:
|
||||
_strappend(buf, size, "\" = type opaque")
|
||||
else:
|
||||
_strappend(buf, size, "\" = type ")
|
||||
_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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import viperlib
|
||||
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(值池链表)
|
||||
# ============================================================
|
||||
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 使用 "%e" 科学计数法(6 位小数)
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if name_buf is not None:
|
||||
viperlib.snprintf(name_buf, 32, "%e", val)
|
||||
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)
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
remain: t.CSizeT = dst_size - dlen
|
||||
if remain <= 0: return
|
||||
i: t.CSizeT = 0
|
||||
while i < slen and i + 1 < remain:
|
||||
dst[dlen + i] = src[i]
|
||||
i += 1
|
||||
dst[dlen + i] = '\0'
|
||||
@@ -0,0 +1,396 @@
|
||||
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 名条目(链表节点)
|
||||
# ============================================================
|
||||
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)
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
remain: t.CSizeT = dst_size - dlen
|
||||
if remain <= 0: return
|
||||
i: t.CSizeT = 0
|
||||
while i < slen and i + 1 < remain:
|
||||
dst[dlen + i] = src[i]
|
||||
i += 1
|
||||
dst[dlen + i] = '\0'
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SSA 名表操作
|
||||
# ============================================================
|
||||
def _new_name_table(pool: memhub.MemBuddy | t.CPtr) -> GSList[NameEntry] | t.CPtr:
|
||||
"""创建空名表"""
|
||||
gsl: GSList[NameEntry] | t.CPtr = pool.alloc(24) # GSList: Head+Tail+Count
|
||||
if gsl is None: return None
|
||||
string.memset(gsl, 0, 24)
|
||||
return gsl
|
||||
|
||||
|
||||
# NameEntry 硬编码大小: Next(8) + Name(8) = 16 字节
|
||||
NENTRY_SIZE: t.CDefine = 16
|
||||
|
||||
def _name_table_add(table: GSList[NameEntry] | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
name: t.CChar | t.CPtr) -> t.CInt:
|
||||
"""添加名到表。返回 1=重复, 0=成功添加"""
|
||||
if table is None or name is None: return 0
|
||||
# 检查重复
|
||||
cur: NameEntry | t.CPtr = table.Head
|
||||
while cur is not None:
|
||||
if string.strcmp(cur.Name, name) == 0:
|
||||
return 1
|
||||
cur = cur.Next
|
||||
# 添加新条目
|
||||
entry: NameEntry | t.CPtr = pool.alloc(NENTRY_SIZE)
|
||||
if entry is None: return 0
|
||||
string.memset(entry, 0, NENTRY_SIZE)
|
||||
entry.Name = name
|
||||
table.append(entry)
|
||||
return 0
|
||||
|
||||
|
||||
def _name_table_contains(table: GSList[NameEntry] | t.CPtr,
|
||||
name: t.CChar | t.CPtr) -> t.CInt:
|
||||
"""检查名是否在表中。返回 1=存在, 0=不存在"""
|
||||
if table is None or name is None: return 0
|
||||
cur: NameEntry | t.CPtr = table.Head
|
||||
while cur is not None:
|
||||
if string.strcmp(cur.Name, name) == 0:
|
||||
return 1
|
||||
cur = cur.Next
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 文本分析辅助
|
||||
# ============================================================
|
||||
def _is_char_name(ch: t.CChar) -> t.CInt:
|
||||
"""判断字符是否为 SSA 名字符 [a-zA-Z0-9._]"""
|
||||
if ch >= 'a' and ch <= 'z': return 1
|
||||
if ch >= 'A' and ch <= 'Z': return 1
|
||||
if ch >= '0' and ch <= '9': return 1
|
||||
if ch == '.' or ch == '_': return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _extract_def_name(pool: memhub.MemBuddy | t.CPtr,
|
||||
text: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
|
||||
"""从定义行提取被定义的 SSA 名。
|
||||
|
||||
定义行格式: "%<name> = <instruction>"
|
||||
返回分配的 NUL 结尾名串(如 "%0"),或 None 若非定义行。
|
||||
"""
|
||||
if text is None: return None
|
||||
if text[0] != '%': return None
|
||||
# 扫描 " = " 模式
|
||||
i: t.CInt = 1
|
||||
while text[i] != '\0':
|
||||
if text[i] == ' ' and text[i + 1] == '=' and text[i + 2] == ' ':
|
||||
# 找到 " = " 在位置 i
|
||||
name_len: t.CInt = i
|
||||
name: t.CChar | t.CPtr = pool.alloc(name_len + 1)
|
||||
if name is None: return None
|
||||
j: t.CInt = 0
|
||||
while j < name_len:
|
||||
name[j] = text[j]
|
||||
j += 1
|
||||
name[name_len] = '\0'
|
||||
return name
|
||||
i += 1
|
||||
return None
|
||||
|
||||
|
||||
def _is_terminator(text: t.CChar | t.CPtr) -> t.CInt:
|
||||
"""判断文本是否为终止指令"""
|
||||
if text is None: return 0
|
||||
if string.strncmp(text, "ret", 3) == 0: return 1
|
||||
if string.strncmp(text, "br ", 3) == 0: return 1
|
||||
if string.strncmp(text, "switch ", 7) == 0: return 1
|
||||
if string.strncmp(text, "unreachable", 11) == 0: return 1
|
||||
if string.strncmp(text, "indirectbr ", 11) == 0: return 1
|
||||
if string.strncmp(text, "resume ", 7) == 0: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _is_phi(text: t.CChar | t.CPtr) -> t.CInt:
|
||||
"""判断文本是否为 phi 指令"""
|
||||
if text is None: return 0
|
||||
if string.strstr(text, " = phi ") is not None: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _check_uses_in_line(table: GSList[NameEntry] | t.CPtr,
|
||||
text: t.CChar | t.CPtr,
|
||||
def_name: t.CChar | t.CPtr) -> t.CInt:
|
||||
"""检查行中所有 SSA 名使用是否已定义。
|
||||
|
||||
跳过 def_name(定义位置的名字)。
|
||||
返回未定义使用数量。
|
||||
"""
|
||||
if text is None: return 0
|
||||
i: t.CInt = 0
|
||||
undef_count: t.CInt = 0
|
||||
while text[i] != '\0':
|
||||
if text[i] == '%':
|
||||
# 提取名
|
||||
name_start: t.CInt = i
|
||||
i += 1
|
||||
while text[i] != '\0' and _is_char_name(text[i]) == 1:
|
||||
i += 1
|
||||
name_len: t.CInt = i - name_start
|
||||
if name_len > 1:
|
||||
# 构建临时名串进行比较
|
||||
# 由于无法在栈上分配,用 strstr 进行简化检查
|
||||
# 这里采用逐字符比较方式
|
||||
if _name_matches_at(text, name_start, name_len, table) == 0:
|
||||
# 检查是否是 def_name(定义本身的位置)
|
||||
if def_name is not None:
|
||||
if _str_matches_at(text, name_start, name_len, def_name) == 0:
|
||||
undef_count += 1
|
||||
else:
|
||||
undef_count += 1
|
||||
else:
|
||||
i += 1
|
||||
return undef_count
|
||||
|
||||
|
||||
def _name_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt,
|
||||
table: GSList[NameEntry] | t.CPtr) -> t.CInt:
|
||||
"""检查 text[start:start+length] 是否匹配名表中的某个条目。
|
||||
返回 1=匹配, 0=不匹配
|
||||
"""
|
||||
if table is None: return 0
|
||||
cur: NameEntry | t.CPtr = table.Head
|
||||
while cur is not None:
|
||||
if cur.Name is not None:
|
||||
if _str_matches_at(text, start, length, cur.Name) == 1:
|
||||
return 1
|
||||
cur = cur.Next
|
||||
return 0
|
||||
|
||||
|
||||
def _str_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt,
|
||||
target: t.CChar | t.CPtr) -> t.CInt:
|
||||
"""检查 text[start:start+length] 是否等于 target 字符串。
|
||||
返回 1=匹配, 0=不匹配
|
||||
"""
|
||||
if text is None or target is None: return 0
|
||||
# 检查 target 长度
|
||||
target_len: t.CInt = string.strlen(target)
|
||||
if target_len != length: return 0
|
||||
i: t.CInt = 0
|
||||
while i < length:
|
||||
if text[start + i] != target[i]: return 0
|
||||
i += 1
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主验证函数
|
||||
# ============================================================
|
||||
def verify_function(pool: memhub.MemBuddy | t.CPtr,
|
||||
func: Function | t.CPtr,
|
||||
result: VerifyResult | t.CPtr) -> t.CInt:
|
||||
"""验证函数的 SSA 正确性。
|
||||
|
||||
参数:
|
||||
pool: 内存池
|
||||
func: 要验证的函数
|
||||
result: 验证结果(调用前需用 _new_verify_result 创建)
|
||||
|
||||
返回: 错误数量(0 = 验证通过)
|
||||
"""
|
||||
if func is None or result is None: return 1
|
||||
|
||||
# 创建名表
|
||||
name_table: GSList[NameEntry] | t.CPtr = _new_name_table(pool)
|
||||
if name_table is None: return 1
|
||||
|
||||
# 1. 将函数参数加入名表(参数是已定义的)
|
||||
param: Param | t.CPtr = None
|
||||
if func.Params is not None:
|
||||
param = func.Params.Head
|
||||
while param is not None:
|
||||
if param.Name is not None:
|
||||
_name_table_add(name_table, pool, param.Name)
|
||||
param = param.Next
|
||||
|
||||
# 1b. 将基本块名加入名表(块标签如 %then 是 br/phi 的合法引用目标)
|
||||
blk_iter: BasicBlock | t.CPtr = None
|
||||
if func.Blocks is not None:
|
||||
blk_iter = func.Blocks.Head
|
||||
while blk_iter is not None:
|
||||
if blk_iter.Name is not None:
|
||||
blk_name_len: t.CSizeT = string.strlen(blk_iter.Name)
|
||||
blk_ref: t.CChar | t.CPtr = pool.alloc(blk_name_len + 2)
|
||||
if blk_ref is not None:
|
||||
# 构造 "%<name>" 字符串
|
||||
blk_ref[0] = '%'
|
||||
k: t.CSizeT = 0
|
||||
while k < blk_name_len:
|
||||
blk_ref[k + 1] = blk_iter.Name[k]
|
||||
k += 1
|
||||
blk_ref[blk_name_len + 1] = '\0'
|
||||
_name_table_add(name_table, pool, blk_ref)
|
||||
blk_iter = blk_iter.Next
|
||||
|
||||
# 2. 遍历所有块
|
||||
blk: BasicBlock | t.CPtr = None
|
||||
if func.Blocks is not None:
|
||||
blk = func.Blocks.Head
|
||||
while blk is not None:
|
||||
# 检查终止指令
|
||||
if blk.IsTerminated == 0:
|
||||
# 进一步检查最后一行是否为终止指令
|
||||
has_term: t.CInt = 0
|
||||
line_check: Line | t.CPtr = None
|
||||
if blk.Lines is not None:
|
||||
line_check = blk.Lines.Head
|
||||
while line_check is not None:
|
||||
if line_check.Buf is not None:
|
||||
if _is_terminator(line_check.Buf) == 1:
|
||||
has_term = 1
|
||||
line_check = line_check.Next
|
||||
if has_term == 0:
|
||||
blk_name: t.CChar | t.CPtr = "<unnamed>"
|
||||
if blk.Name is not None:
|
||||
blk_name = blk.Name
|
||||
err_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 128, "ERROR: block '%s' missing terminator", blk_name)
|
||||
_report_error(result, VERIFY_ERR_NO_TERMINATOR, err_buf)
|
||||
|
||||
# 遍历块内指令行
|
||||
seen_non_phi: t.CInt = 0
|
||||
line: Line | t.CPtr = None
|
||||
if blk.Lines is not None:
|
||||
line = blk.Lines.Head
|
||||
while line is not None:
|
||||
if line.Buf is not None:
|
||||
text: t.CChar | t.CPtr = line.Buf
|
||||
|
||||
# 检查 phi 位置
|
||||
if _is_phi(text) == 1:
|
||||
if seen_non_phi == 1:
|
||||
phi_err: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if phi_err is not None:
|
||||
viperlib.snprintf(phi_err, 128, "ERROR: phi not at block start")
|
||||
_report_error(result, VERIFY_ERR_PHI_NOT_FIRST, phi_err)
|
||||
else:
|
||||
# 非空行且非 phi 标记为已见非 phi
|
||||
if string.strlen(text) > 0:
|
||||
seen_non_phi = 1
|
||||
|
||||
# 提取定义名
|
||||
def_name: t.CChar | t.CPtr = _extract_def_name(pool, text)
|
||||
if def_name is not None:
|
||||
# 检查重复定义
|
||||
dup: t.CInt = _name_table_add(name_table, pool, def_name)
|
||||
if dup == 1:
|
||||
dup_err: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if dup_err is not None:
|
||||
viperlib.snprintf(dup_err, 128, "ERROR: duplicate definition '%s'", def_name)
|
||||
_report_error(result, VERIFY_ERR_DUPLICATE_DEF, dup_err)
|
||||
|
||||
# 检查未定义使用
|
||||
undef: t.CInt = _check_uses_in_line(name_table, text, def_name)
|
||||
if undef > 0:
|
||||
use_err: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if use_err is not None:
|
||||
viperlib.snprintf(use_err, 128, "ERROR: %d undefined use(s) in: %s", undef, text)
|
||||
_report_error(result, VERIFY_ERR_UNDEFINED_USE, use_err)
|
||||
|
||||
line = line.Next
|
||||
|
||||
blk = blk.Next
|
||||
|
||||
return result.ErrorCount
|
||||
|
||||
|
||||
def verify_module(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, result: VerifyResult | t.CPtr) -> t.CInt:
|
||||
"""验证模块中所有函数的 SSA 正确性。
|
||||
|
||||
返回: 错误总数
|
||||
"""
|
||||
if mod is None or result is None: return 1
|
||||
func: Function | t.CPtr = mod.FuncHead
|
||||
while func is not None:
|
||||
if func.IsDeclared == 0:
|
||||
# 只验证有函数体的定义,跳过声明
|
||||
verify_function(pool, func, result)
|
||||
func = func.Next
|
||||
return result.ErrorCount
|
||||
@@ -0,0 +1,39 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import CRITICAL_SECTION, InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, TryEnterCriticalSection
|
||||
|
||||
|
||||
@t.Object
|
||||
class Lock:
|
||||
"""基于 CRITICAL_SECTION 的互斥锁,支持递归加锁。
|
||||
|
||||
用法:
|
||||
lock: Lock = Lock()
|
||||
with lock:
|
||||
# 临界区
|
||||
pass
|
||||
"""
|
||||
cs: CRITICAL_SECTION
|
||||
|
||||
def __init__(self):
|
||||
InitializeCriticalSection(c.Addr(self.cs))
|
||||
|
||||
def acquire(self):
|
||||
EnterCriticalSection(c.Addr(self.cs))
|
||||
|
||||
def release(self):
|
||||
LeaveCriticalSection(c.Addr(self.cs))
|
||||
|
||||
def try_acquire(self) -> BOOL:
|
||||
return TryEnterCriticalSection(c.Addr(self.cs))
|
||||
|
||||
def __enter__(self) -> 'Lock' | t.CPtr:
|
||||
self.acquire()
|
||||
return self
|
||||
|
||||
def __exit__(self):
|
||||
self.release()
|
||||
|
||||
def delete(self):
|
||||
DeleteCriticalSection(c.Addr(self.cs))
|
||||
@@ -0,0 +1,479 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import atom
|
||||
import viperio
|
||||
|
||||
# ============================================================
|
||||
# memhub - 统一内存管理库
|
||||
# MemManager (多态基类, vtable)
|
||||
# ├─ MemPool (arena bump 分配器, 不支持单个 free)
|
||||
# ├─ MemSlab (定长块池, 支持 alloc/free 位图跟踪)
|
||||
# └─ MemBuddy (伙伴系统, 支持 alloc/free/realloc 合并)
|
||||
# 所有子类通过 vtable 覆盖 alloc/free/reset, 可用 MemManager 指针多态调用
|
||||
# ============================================================
|
||||
|
||||
MEMHUB_ALIGN: t.CDefine = 8
|
||||
|
||||
# MemSlab 位图常量
|
||||
MEMSLAB_MIN_BLOCK: t.CDefine = 16
|
||||
MEMSLAB_BITMAP_BYTES: t.CDefine = 256
|
||||
|
||||
# MemBuddy 伙伴系统常量
|
||||
MEMBUDDY_MIN_BLOCK: t.CDefine = 32
|
||||
MEMBUDDY_MAX_ORDERS: t.CDefine = 32
|
||||
MEMBUDDY_HEADER_SIZE: t.CDefine = 8
|
||||
|
||||
|
||||
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 - 多态基类
|
||||
# @t.CVTable 显式标记, 确保跨模块导入时也被识别为 vtable 类
|
||||
# (HandlesImports 只通过装饰器检测 IsCVTable, 不像同模块自动推断)
|
||||
# ============================================================
|
||||
@t.CVTable
|
||||
class MemManager:
|
||||
__provides__: list[str] = ['__memmgr__']
|
||||
base: t.CVoid | t.CPtr # 内存区起始地址
|
||||
size: t.CSizeT # 内存区总大小
|
||||
|
||||
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT):
|
||||
self.base = base
|
||||
self.size = size
|
||||
|
||||
# === 虚函数 (子类覆盖) ===
|
||||
|
||||
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
# 默认: 不支持分配
|
||||
return None
|
||||
|
||||
def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
# 默认: 无操作
|
||||
return 0
|
||||
|
||||
def reset(self) -> t.CInt:
|
||||
# 默认: 无操作
|
||||
return 0
|
||||
|
||||
# === 具体方法 (调用虚函数, 自动多态分派) ===
|
||||
|
||||
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, old_size: t.CSizeT, 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
|
||||
copy_size: t.CSizeT = old_size
|
||||
if new_size < old_size:
|
||||
copy_size = new_size
|
||||
string.memcpy(new_ptr, ptr, copy_size)
|
||||
self.free(ptr)
|
||||
return new_ptr
|
||||
|
||||
def __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 分配器
|
||||
# 不支持单个 free, reset 一次性回收全部
|
||||
# ============================================================
|
||||
class MemPool(MemManager):
|
||||
offset: t.CSizeT # bump 游标
|
||||
high_water: t.CSizeT # 峰值水位
|
||||
|
||||
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: return None
|
||||
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 分配器不支持单个 free
|
||||
return 1
|
||||
|
||||
def reset(self) -> t.CInt:
|
||||
self.offset = 0
|
||||
self.high_water = 0
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MemSlab - 定长块池
|
||||
# arena 开头存位图, 后续区域按 block_size 切分, 空闲链管理
|
||||
# ============================================================
|
||||
class MemSlab(MemManager):
|
||||
block_size: t.CSizeT # 每块大小 (对齐后)
|
||||
block_count: t.CSizeT # 总块数
|
||||
used_count: t.CSizeT # 已用块数
|
||||
free_list: t.CVoid | t.CPtr # 空闲链头
|
||||
alloc_map: t.CUInt8T | t.CPtr # 分配位图 (位于 arena 开头)
|
||||
alloc_map_size: t.CSizeT # 位图字节数
|
||||
usable: t.CVoid | t.CPtr # 可用块区起始 (跳过位图)
|
||||
usable_size: t.CSizeT # 可用块区大小
|
||||
|
||||
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
|
||||
|
||||
# 清零位图
|
||||
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
|
||||
|
||||
# 构建空闲链: 每块首 8 字节存下一块指针
|
||||
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 模式: 仅当请求 <= block_size 时分配一块
|
||||
if self.free_list is None: return None
|
||||
if 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 - 伙伴系统分配器
|
||||
# arena 开头存空闲链头数组, 后续区域按 2 的幂管理
|
||||
# 线程安全 (自旋锁), 支持合并
|
||||
# ============================================================
|
||||
class MemBuddy(MemManager):
|
||||
max_order: t.CInt # 最大阶数
|
||||
free_lists: t.CUInt64T | t.CPtr # 空闲链头数组 (位于 arena 开头)
|
||||
lock_val: t.CVolatile | t.CInt # 自旋锁
|
||||
usable: t.CVoid | t.CPtr # 可用区起始 (跳过 free_lists)
|
||||
usable_size: t.CSizeT # 可用区大小 (2 的幂)
|
||||
|
||||
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.lock_val = 0
|
||||
fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8
|
||||
self.free_lists = base
|
||||
|
||||
# 初始化所有空闲链头为 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
|
||||
usable: t.CSizeT = _largest_pow2_le(remaining)
|
||||
|
||||
if usable < 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)
|
||||
self.usable_size = usable
|
||||
|
||||
# 计算 max_order: log2(usable / MIN_BLOCK)
|
||||
self.max_order = 0
|
||||
bs: t.CSizeT = MEMBUDDY_MIN_BLOCK
|
||||
while bs < usable:
|
||||
bs = bs << 1
|
||||
self.max_order += 1
|
||||
|
||||
# 整个可用区作为 max_order 阶空闲块
|
||||
self._fl_push(self.max_order, self.usable)
|
||||
|
||||
# === 空闲链操作 ===
|
||||
|
||||
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 cur is not None:
|
||||
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
|
||||
|
||||
# === 伙伴系统核心 ===
|
||||
|
||||
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
|
||||
return 1
|
||||
|
||||
# === 锁 ===
|
||||
|
||||
def _lock(self):
|
||||
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)
|
||||
|
||||
# === 虚函数覆盖 ===
|
||||
|
||||
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
self._lock()
|
||||
result: t.CVoid | t.CPtr = None
|
||||
if self.usable is not None:
|
||||
if size != 0:
|
||||
needed: t.CSizeT = size + MEMBUDDY_HEADER_SIZE
|
||||
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)
|
||||
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 reset(self) -> t.CInt:
|
||||
if self.usable is None:
|
||||
return 0
|
||||
i: t.CInt
|
||||
for i in range(MEMBUDDY_MAX_ORDERS + 1):
|
||||
self.free_lists[i] = 0
|
||||
self._fl_push(self.max_order, self.usable)
|
||||
return 1
|
||||
|
||||
# realloc 覆盖: 伙伴系统从块头读取旧阶数, 无需 old_size
|
||||
def realloc(self, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, 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
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,133 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import platmacro
|
||||
import memhub
|
||||
import os.path
|
||||
import os._win32
|
||||
import os._posix
|
||||
|
||||
|
||||
# os 包入口
|
||||
# 根据 platmacro.IS_WINDOWS 分派到 _win32 或 _posix 后端
|
||||
# os.path 为跨平台纯字符串操作,直接可用
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件/目录属性查询
|
||||
# =============================================================================
|
||||
|
||||
def exists(path: str) -> bool:
|
||||
"""检查文件/目录是否存在"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.exists(path)
|
||||
return os._posix.exists(path)
|
||||
|
||||
|
||||
def isdir(path: str) -> bool:
|
||||
"""检查路径是否为目录"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.isdir(path)
|
||||
return os._posix.isdir(path)
|
||||
|
||||
|
||||
def isfile(path: str) -> bool:
|
||||
"""检查路径是否为普通文件"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.isfile(path)
|
||||
return os._posix.isfile(path)
|
||||
|
||||
|
||||
def getsize(path: str) -> t.CInt64T:
|
||||
"""返回文件大小(字节)。失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.getsize(path)
|
||||
return os._posix.getsize(path)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 工作目录
|
||||
# =============================================================================
|
||||
|
||||
def getcwd() -> str:
|
||||
"""返回当前工作目录(通过 _mbuddy 分配内存)"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.getcwd()
|
||||
return os._posix.getcwd_impl()
|
||||
|
||||
|
||||
def chdir(path: str) -> int:
|
||||
"""切换当前工作目录。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.chdir(path)
|
||||
return os._posix.chdir_impl(path)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件/目录操作
|
||||
# =============================================================================
|
||||
|
||||
def mkdir(path: str) -> int:
|
||||
"""创建目录。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.mkdir(path)
|
||||
return os._posix.mkdir_impl(path)
|
||||
|
||||
|
||||
def remove(path: str) -> int:
|
||||
"""删除文件。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.remove(path)
|
||||
return os._posix.remove(path)
|
||||
|
||||
|
||||
def rmdir(path: str) -> int:
|
||||
"""删除空目录。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.rmdir(path)
|
||||
return os._posix.rmdir_impl(path)
|
||||
|
||||
|
||||
def rename(old_path: str, new_path: str) -> int:
|
||||
"""重命名/移动文件或目录。成功返回 0,失败返回 -1。"""
|
||||
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:
|
||||
"""修改文件权限。成功返回 0,失败返回 -1。
|
||||
Windows 上只处理只读位(S_IWUSR);POSIX 上使用完整权限位。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.chmod(path, mode)
|
||||
return os._posix.chmod_impl(path, mode)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 目录列举
|
||||
# =============================================================================
|
||||
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,316 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import memhub
|
||||
import platmacro
|
||||
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 路径分隔符
|
||||
# =============================================================================
|
||||
|
||||
def sep() -> t.CChar:
|
||||
"""返回当前平台的路径分隔符(Windows: \\,POSIX: /)"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return '\\'
|
||||
return '/'
|
||||
|
||||
|
||||
def _is_sep(ch: t.CChar) -> bool:
|
||||
"""判断字符是否为路径分隔符(/ 或 \\,跨平台识别)"""
|
||||
return ch == '/' or ch == '\\'
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 内部辅助函数
|
||||
# =============================================================================
|
||||
|
||||
def _dup_str(s: str) -> str:
|
||||
"""复制字符串(通过全局 MBuddy 分配内存)"""
|
||||
if s == None: return None
|
||||
length: t.CSizeT = len(s)
|
||||
buf: bytes = _mbuddy.alloc(length + 1)
|
||||
if buf == None: return None
|
||||
i: t.CSizeT = 0
|
||||
for ch in s:
|
||||
buf[i] = ch
|
||||
i += 1
|
||||
buf[length] = 0
|
||||
return str(buf)
|
||||
|
||||
|
||||
def _substr(s: str, start: t.CSizeT, end: t.CSizeT) -> str:
|
||||
"""提取子串 s[start:end](通过全局 MBuddy 分配内存)"""
|
||||
if s == None: return None
|
||||
if start >= end: return _dup_str("")
|
||||
result_len: t.CSizeT = end - start
|
||||
buf: bytes = _mbuddy.alloc(result_len + 1)
|
||||
if buf == None: return None
|
||||
i: t.CSizeT = 0
|
||||
k: t.CSizeT = start
|
||||
while k < end:
|
||||
buf[i] = s[k]
|
||||
i += 1
|
||||
k += 1
|
||||
buf[i] = 0
|
||||
return str(buf)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 路径判断
|
||||
# =============================================================================
|
||||
|
||||
def isabs(path: str) -> bool:
|
||||
"""判断路径是否为绝对路径。
|
||||
POSIX: 以 / 开头。
|
||||
Windows: 以 \\ 开头(UNC)或 X:\\ / X:/ 开头(盘符)。"""
|
||||
if path == None: return False
|
||||
if path[0] == 0: return False
|
||||
if path[0] == '/' or path[0] == '\\': return True
|
||||
if platmacro.IS_WINDOWS:
|
||||
# 检查 X:\ 或 X:/ 模式
|
||||
c0: t.CChar = path[0]
|
||||
if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'):
|
||||
if path[1] == ':':
|
||||
if path[2] == '\\' or path[2] == '/':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 路径拼接与分割
|
||||
# =============================================================================
|
||||
|
||||
def join(path1: str, path2: str) -> str:
|
||||
"""拼接两个路径。如果 path2 是绝对路径,返回 path2 的副本。"""
|
||||
if path1 == None or path1[0] == 0:
|
||||
return _dup_str(path2)
|
||||
if path2 == None or path2[0] == 0:
|
||||
return _dup_str(path1)
|
||||
if isabs(path2):
|
||||
return _dup_str(path2)
|
||||
|
||||
len1: t.CSizeT = len(path1)
|
||||
len2: t.CSizeT = len(path2)
|
||||
|
||||
# 检查 path1 是否以分隔符结尾
|
||||
need_sep: bool = True
|
||||
if _is_sep(path1[len1 - 1]):
|
||||
need_sep = False
|
||||
|
||||
total: t.CSizeT = len1 + len2 + 1
|
||||
if need_sep:
|
||||
total += 1
|
||||
|
||||
buf: bytes = _mbuddy.alloc(total)
|
||||
if buf == None: return None
|
||||
|
||||
# 复制 path1
|
||||
i: t.CSizeT = 0
|
||||
for ch in path1:
|
||||
buf[i] = ch
|
||||
i += 1
|
||||
|
||||
# 添加分隔符
|
||||
if need_sep:
|
||||
buf[i] = sep()
|
||||
i += 1
|
||||
|
||||
# 复制 path2
|
||||
for ch in path2:
|
||||
buf[i] = ch
|
||||
i += 1
|
||||
|
||||
buf[i] = 0
|
||||
return str(buf)
|
||||
|
||||
|
||||
def basename(path: str) -> str:
|
||||
"""返回路径的文件名部分(最后一个分隔符之后的内容)"""
|
||||
if path == None: return None
|
||||
length: t.CSizeT = len(path)
|
||||
if length == 0: return _dup_str("")
|
||||
|
||||
# 从后向前找分隔符
|
||||
i: t.CSizeT = length
|
||||
while i > 0:
|
||||
i -= 1
|
||||
if _is_sep(path[i]):
|
||||
return _substr(path, i + 1, length)
|
||||
|
||||
# 没有分隔符,返回整个路径的副本
|
||||
return _dup_str(path)
|
||||
|
||||
|
||||
def dirname(path: str) -> str:
|
||||
"""返回路径的目录部分(最后一个分隔符之前的内容)"""
|
||||
if path == None: return None
|
||||
length: t.CSizeT = len(path)
|
||||
if length == 0: return _dup_str("")
|
||||
|
||||
# 从后向前找分隔符
|
||||
i: t.CSizeT = length
|
||||
while i > 0:
|
||||
i -= 1
|
||||
if _is_sep(path[i]):
|
||||
if i == 0:
|
||||
# 路径以分隔符开头,返回根目录
|
||||
return _dup_str("/")
|
||||
return _substr(path, 0, i)
|
||||
|
||||
# 没有分隔符,返回空字符串
|
||||
return _dup_str("")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 扩展名处理
|
||||
# =============================================================================
|
||||
|
||||
def splitext_name(path: str) -> str:
|
||||
"""返回路径去除扩展名后的主名部分。
|
||||
扩展名从最后一个 '.' 开始(该 '.' 不能是路径最后一个组件的第一个字符)。"""
|
||||
if path == None: return None
|
||||
length: t.CSizeT = len(path)
|
||||
if length == 0: return _dup_str("")
|
||||
|
||||
# 从后向前找 '.',遇到分隔符停止
|
||||
i: t.CSizeT = length
|
||||
while i > 0:
|
||||
i -= 1
|
||||
if path[i] == '.':
|
||||
return _substr(path, 0, i)
|
||||
if _is_sep(path[i]):
|
||||
break
|
||||
|
||||
# 没有扩展名,返回整个路径的副本
|
||||
return _dup_str(path)
|
||||
|
||||
|
||||
def splitext_ext(path: str) -> str:
|
||||
"""返回路径的扩展名部分(包含 '.')。无扩展名时返回空字符串。"""
|
||||
if path == None: return None
|
||||
length: t.CSizeT = len(path)
|
||||
if length == 0: return _dup_str("")
|
||||
|
||||
# 从后向前找 '.',遇到分隔符停止
|
||||
i: t.CSizeT = length
|
||||
while i > 0:
|
||||
i -= 1
|
||||
if path[i] == '.':
|
||||
return _substr(path, i, length)
|
||||
if _is_sep(path[i]):
|
||||
break
|
||||
|
||||
# 没有扩展名,返回空字符串
|
||||
return _dup_str("")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 路径规范化
|
||||
# =============================================================================
|
||||
|
||||
def normpath(path: str) -> str:
|
||||
"""规范化路径:统一分隔符、消除多余的 . 和 .. 组件、合并连续分隔符。
|
||||
注意:不解析符号链接,不调用系统 API。"""
|
||||
if path == None: return None
|
||||
length: t.CSizeT = len(path)
|
||||
if length == 0: return _dup_str(".")
|
||||
|
||||
# 分配输出缓冲区(最坏情况:长度不变 + 前缀 /)
|
||||
buf: bytes = _mbuddy.alloc(length + 2)
|
||||
if buf == None: return None
|
||||
|
||||
out_pos: t.CSizeT = 0
|
||||
i: t.CSizeT = 0
|
||||
s: str = sep()
|
||||
|
||||
# 处理绝对路径前缀
|
||||
is_absolute: bool = False
|
||||
if _is_sep(path[0]):
|
||||
is_absolute = True
|
||||
buf[out_pos] = s
|
||||
out_pos += 1
|
||||
i = 1
|
||||
|
||||
# Windows 盘符前缀(X:\ 或 X:/)
|
||||
drive_prefix_len: t.CSizeT = 0
|
||||
if platmacro.IS_WINDOWS:
|
||||
if length >= 3:
|
||||
c0: t.CChar = path[0]
|
||||
if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'):
|
||||
if path[1] == ':':
|
||||
if _is_sep(path[2]):
|
||||
buf[out_pos] = path[0]
|
||||
out_pos += 1
|
||||
buf[out_pos] = ':'
|
||||
out_pos += 1
|
||||
buf[out_pos] = s
|
||||
out_pos += 1
|
||||
drive_prefix_len = 3
|
||||
i = 3
|
||||
is_absolute = True
|
||||
|
||||
# 逐组件处理
|
||||
while i < length:
|
||||
# 跳过连续分隔符
|
||||
while i < length and _is_sep(path[i]):
|
||||
i += 1
|
||||
if i >= length:
|
||||
break
|
||||
|
||||
# 提取组件
|
||||
comp_start: t.CSizeT = i
|
||||
while i < length and not _is_sep(path[i]):
|
||||
i += 1
|
||||
comp_len: t.CSizeT = i - comp_start
|
||||
|
||||
# 处理 "." 组件:跳过
|
||||
if comp_len == 1 and path[comp_start] == '.':
|
||||
continue
|
||||
|
||||
# 处理 ".." 组件:回退一级
|
||||
if comp_len == 2 and path[comp_start] == '.' and path[comp_start + 1] == '.':
|
||||
if out_pos > drive_prefix_len:
|
||||
# 回退到上一个分隔符前
|
||||
out_pos -= 1
|
||||
while out_pos > drive_prefix_len and not _is_sep(buf[out_pos - 1]):
|
||||
out_pos -= 1
|
||||
# 如果回退到了根目录前缀,不删除前缀
|
||||
if out_pos == drive_prefix_len and is_absolute:
|
||||
out_pos = drive_prefix_len
|
||||
if drive_prefix_len == 0:
|
||||
# POSIX 根:保留 /
|
||||
buf[out_pos] = s
|
||||
out_pos += 1
|
||||
continue
|
||||
|
||||
# 普通组件:复制到输出
|
||||
if out_pos > drive_prefix_len and not (drive_prefix_len == 0 and out_pos == 1 and is_absolute):
|
||||
buf[out_pos] = s
|
||||
out_pos += 1
|
||||
elif out_pos == 0 and not is_absolute:
|
||||
pass # 第一个组件,不需要前导分隔符
|
||||
elif is_absolute and out_pos == drive_prefix_len:
|
||||
# 已经有前导分隔符,不重复添加
|
||||
pass
|
||||
else:
|
||||
buf[out_pos] = s
|
||||
out_pos += 1
|
||||
|
||||
j: t.CSizeT = comp_start
|
||||
while j < comp_start + comp_len:
|
||||
buf[out_pos] = path[j]
|
||||
out_pos += 1
|
||||
j += 1
|
||||
|
||||
# 处理空结果
|
||||
if out_pos == 0:
|
||||
buf[out_pos] = '.'
|
||||
out_pos += 1
|
||||
|
||||
buf[out_pos] = 0
|
||||
return str(buf)
|
||||
@@ -0,0 +1,57 @@
|
||||
import t, c
|
||||
|
||||
|
||||
IS_WINDOWS: t.CDefine = 1
|
||||
IS_WIN64: t.CDefine = 1
|
||||
IS_X86_64: t.CDefine = 1
|
||||
IS_LP64: t.CDefine = 1
|
||||
IS_LITTLE_ENDIAN: t.CDefine = 1
|
||||
|
||||
IS_LINUX: t.CDefine = 0
|
||||
IS_MACOS: t.CDefine = 0
|
||||
IS_ARM64: t.CDefine = 0
|
||||
IS_BIG_ENDIAN: t.CDefine = 0
|
||||
IS_ILP32: t.CDefine = 0
|
||||
|
||||
PTR_SIZE: t.CDefine = t.CSizeT().Size
|
||||
INT_SIZE: t.CDefine = 4
|
||||
LONG_SIZE: t.CDefine = t.CLong().Size
|
||||
WORD_SIZE: t.CDefine = t.CSizeT().Size
|
||||
|
||||
CACHE_LINE_SIZE: t.CDefine = 64
|
||||
PAGE_SIZE: t.CDefine = 4096
|
||||
STACK_ALIGN: t.CDefine = 16
|
||||
MAX_PATH_LEN: t.CDefine = 260
|
||||
|
||||
PLATFORM_NAME: t.CDefine = 1
|
||||
ARCH_NAME: t.CDefine = 1
|
||||
|
||||
WINVER: t.CDefine = 0x0A00
|
||||
_WIN32_WINNT: t.CDefine = 0x0A00
|
||||
NTDDI_VERSION: t.CDefine = 0x0A000006
|
||||
|
||||
HAS_SSE2: t.CDefine = 1
|
||||
HAS_AVX: t.CDefine = 1
|
||||
HAS_AVX2: t.CDefine = 1
|
||||
HAS_FMA: t.CDefine = 1
|
||||
HAS_NEON: t.CDefine = 0
|
||||
|
||||
ALIGNOF_INT: t.CDefine = 4
|
||||
ALIGNOF_LONG: t.CDefine = t.CLong().Size // 8
|
||||
ALIGNOF_PTR: t.CDefine = t.CSizeT().Size // 8
|
||||
ALIGNOF_DOUBLE: t.CDefine = 8
|
||||
ALIGNOF_LONG_DOUBLE: t.CDefine = 16
|
||||
|
||||
SIZEOF_SHORT: t.CDefine = 2
|
||||
SIZEOF_INT: t.CDefine = 4
|
||||
SIZEOF_LONG: t.CDefine = t.CLong().Size // 8
|
||||
SIZEOF_LONG_LONG: t.CDefine = 8
|
||||
SIZEOF_FLOAT: t.CDefine = 4
|
||||
SIZEOF_DOUBLE: t.CDefine = 8
|
||||
SIZEOF_LONG_DOUBLE: t.CDefine = 16
|
||||
SIZEOF_POINTER: t.CDefine = t.CSizeT().Size // 8
|
||||
SIZEOF_SIZE_T: t.CDefine = t.CSizeT().Size // 8
|
||||
SIZEOF_PTRDIFF_T: t.CDefine = t.CPtrDiffT().Size // 8
|
||||
|
||||
BYTE_ORDER_LE: t.CDefine = 1
|
||||
BYTE_ORDER_BE: t.CDefine = 0
|
||||
@@ -0,0 +1,5 @@
|
||||
import t, c
|
||||
|
||||
|
||||
#class PList:
|
||||
# def
|
||||
@@ -0,0 +1,265 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# POSIX 类型别名
|
||||
# 注意:ssize_t 已在 stdint.py 中定义为 t.CPtrDiffT,此处不再重复
|
||||
# =============================================================================
|
||||
DIR: t.CTypedef = t.CVoid | t.CPtr # 不透明目录流句柄
|
||||
mode_t: t.CTypedef = t.CUInt32T # 文件模式/权限位
|
||||
pid_t: t.CTypedef = t.CInt32T # 进程 ID
|
||||
off_t: t.CTypedef = t.CInt64T # 文件偏移量(Linux x86_64)
|
||||
dev_t: t.CTypedef = t.CUInt64T # 设备号
|
||||
ino_t: t.CTypedef = t.CUInt64T # inode 号
|
||||
nlink_t: t.CTypedef = t.CUInt64T # 硬链接数
|
||||
uid_t: t.CTypedef = t.CUInt32T # 用户 ID
|
||||
gid_t: t.CTypedef = t.CUInt32T # 组 ID
|
||||
blksize_t: t.CTypedef = t.CInt64T # 文件系统 I/O 块大小
|
||||
blkcnt_t: t.CTypedef = t.CInt64T # 已分配块数
|
||||
time_t: t.CTypedef = t.CInt64T # 日历时间秒数
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# open() 标志位
|
||||
# =============================================================================
|
||||
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() 测试标志
|
||||
# =============================================================================
|
||||
F_OK: t.CDefine = 0 # 文件存在
|
||||
R_OK: t.CDefine = 4 # 可读
|
||||
W_OK: t.CDefine = 2 # 可写
|
||||
X_OK: t.CDefine = 1 # 可执行
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# stat 结构体的 st_mode 掩码与类型位
|
||||
# =============================================================================
|
||||
S_IFMT: t.CDefine = 0o170000 # 类型掩码
|
||||
S_IFSOCK: t.CDefine = 0o140000 # 套接字
|
||||
S_IFLNK: t.CDefine = 0o120000 # 符号链接
|
||||
S_IFREG: t.CDefine = 0o100000 # 普通文件
|
||||
S_IFBLK: t.CDefine = 0o060000 # 块设备
|
||||
S_IFDIR: t.CDefine = 0o040000 # 目录
|
||||
S_IFCHR: t.CDefine = 0o020000 # 字符设备
|
||||
S_IFIFO: t.CDefine = 0o010000 # FIFO/管道
|
||||
|
||||
# 权限位
|
||||
S_ISUID: t.CDefine = 0o4000 # set-user-ID
|
||||
S_ISGID: t.CDefine = 0o2000 # set-group-ID
|
||||
S_ISVTX: t.CDefine = 0o1000 # sticky 位
|
||||
S_IRWXU: t.CDefine = 0o700 # 用户读写执行
|
||||
S_IRUSR: t.CDefine = 0o400 # 用户读
|
||||
S_IWUSR: t.CDefine = 0o200 # 用户写
|
||||
S_IXUSR: t.CDefine = 0o100 # 用户执行
|
||||
S_IRWXG: t.CDefine = 0o070 # 组读写执行
|
||||
S_IRGRP: t.CDefine = 0o040 # 组读
|
||||
S_IWGRP: t.CDefine = 0o020 # 组写
|
||||
S_IXGRP: t.CDefine = 0o010 # 组执行
|
||||
S_IRWXO: t.CDefine = 0o007 # 其他读写执行
|
||||
S_IROTH: t.CDefine = 0o004 # 其他读
|
||||
S_IWOTH: t.CDefine = 0o002 # 其他写
|
||||
S_IXOTH: t.CDefine = 0o001 # 其他执行
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# lseek() whence 值
|
||||
# =============================================================================
|
||||
SEEK_SET: t.CDefine = 0
|
||||
SEEK_CUR: t.CDefine = 1
|
||||
SEEK_END: t.CDefine = 2
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 路径/名称长度限制
|
||||
# =============================================================================
|
||||
PATH_MAX: t.CDefine = 4096
|
||||
NAME_MAX: t.CDefine = 255
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# sysconf() 参数
|
||||
# =============================================================================
|
||||
_SC_NPROCESSORS_ONLN: t.CDefine = 84
|
||||
_SC_PAGESIZE: t.CDefine = 30
|
||||
_SC_CLK_TCK: t.CDefine = 2
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# dirent 结构体的 d_type 值
|
||||
# =============================================================================
|
||||
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() 选项
|
||||
# =============================================================================
|
||||
WNOHANG: t.CDefine = 1
|
||||
WUNTRACED: t.CDefine = 2
|
||||
WCONTINUED: t.CDefine = 8
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 结构体:Linux x86_64 布局
|
||||
# =============================================================================
|
||||
|
||||
# struct stat(144 字节,Linux x86_64 glibc 布局)
|
||||
# 注意:st_atim/st_mtim/st_ctim 在 C 中是 struct timespec { tv_sec; tv_nsec; }
|
||||
# 此处拆分为 _sec/_nsec 两个 LONGLONG 字段以保持二进制兼容
|
||||
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 为 char[256])
|
||||
# 注意:d_name 实际是定长 char[256],TransPyC 用 CHARPTR 占位(8 字节)。
|
||||
# 用户通常通过 readdir 返回的只读指针访问,不直接分配 Dirent 结构体。
|
||||
class Dirent():
|
||||
d_ino: ino_t # @ 0
|
||||
d_off: off_t # @ 8
|
||||
d_reclen: USHORT # @ 16
|
||||
d_type: BYTE # @ 18
|
||||
d_name: CHARPTR # @ 19(实际为 char[256],此处占位)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件操作函数(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 系列(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
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 目录操作(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
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 进程/管道(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
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 环境/系统(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
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 内联宏(C 宏,用 TransPyC 普通函数实现,不标记 t.CExtern)
|
||||
# =============================================================================
|
||||
|
||||
# st_mode 类型判定
|
||||
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 状态解析
|
||||
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
|
||||
@@ -0,0 +1,361 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import socket
|
||||
import memhub
|
||||
import stdio
|
||||
|
||||
|
||||
# ============================================================
|
||||
# requests.py — HTTP 客户端库(Python 原版风格)
|
||||
#
|
||||
# 用法:
|
||||
# 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)
|
||||
# ============================================================
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# Socket 初始化标记
|
||||
_socket_ready: bool = False
|
||||
|
||||
HTTP_PORT: t.CDefine = 80
|
||||
HTTP_BUFSIZ: t.CDefine = 4096
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Response — HTTP 响应对象
|
||||
# ============================================================
|
||||
|
||||
class Response:
|
||||
"""HTTP 响应对象,贴近 Python requests.Response 用法。
|
||||
|
||||
从 _mbuddy 分配,使用完毕后调用 release(resp) 释放。
|
||||
"""
|
||||
status_code: INT # HTTP 状态码(如 200、404)
|
||||
text: str # 响应体文本(指向 _raw_buf 内部)
|
||||
body_len: INT # 响应体长度
|
||||
_raw_buf: str # 原始缓冲区指针
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内部辅助函数
|
||||
# ============================================================
|
||||
|
||||
def _EnsureSocketInit() -> INT:
|
||||
"""确保 Socket 库已初始化(幂等)。"""
|
||||
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:
|
||||
"""从 _mbuddy 分配 Response 结构体并就地初始化。"""
|
||||
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:
|
||||
"""解析 URL,提取 host、port、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
|
||||
|
||||
# 跳过 "http://"
|
||||
if string.strncmp(p, "http://", 7) == 0:
|
||||
p += 7
|
||||
|
||||
# 解析 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
|
||||
|
||||
# 解析 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)
|
||||
|
||||
# 解析 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:
|
||||
"""解析 HTTP 状态行,提取状态码。返回状态行结束偏移。"""
|
||||
if resp_text is None or out_code is None: return -1
|
||||
|
||||
p: str = resp_text
|
||||
|
||||
# 跳过 "HTTP/x.x "
|
||||
while p[0] != '\0' and p[0] != ' ':
|
||||
p += 1
|
||||
if p[0] == ' ': p += 1
|
||||
|
||||
# 解析状态码
|
||||
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)
|
||||
|
||||
# 找到 \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:
|
||||
"""找到 HTTP 响应体起始位置(\\r\\n\\r\\n 之后)。"""
|
||||
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 请求。
|
||||
|
||||
Args:
|
||||
url: 完整 URL (如 "http://example.com/path")
|
||||
Returns:
|
||||
Response 对象指针(从 _mbuddy 分配),失败返回 None。
|
||||
使用完毕后调用 release(resp) 释放。
|
||||
"""
|
||||
if _mbuddy is None: return None
|
||||
|
||||
resp: Response | t.CPtr = _AllocResponse()
|
||||
if resp is None: return None
|
||||
|
||||
if _EnsureSocketInit() != 0:
|
||||
release(resp)
|
||||
return None
|
||||
|
||||
# 解析 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
|
||||
|
||||
# 创建并连接 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
|
||||
|
||||
# 构建 HTTP 请求
|
||||
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
|
||||
|
||||
# 接收响应
|
||||
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
|
||||
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 请求。
|
||||
|
||||
Args:
|
||||
url: 完整 URL
|
||||
data: 请求体数据
|
||||
content_type: Content-Type 头(默认 "application/x-www-form-urlencoded")
|
||||
Returns:
|
||||
Response 对象指针(从 _mbuddy 分配),失败返回 None。
|
||||
"""
|
||||
if _mbuddy is None: return None
|
||||
|
||||
resp: Response | t.CPtr = _AllocResponse()
|
||||
if resp is None: return None
|
||||
|
||||
if _EnsureSocketInit() != 0:
|
||||
release(resp)
|
||||
return None
|
||||
|
||||
# 解析 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"
|
||||
|
||||
# 创建并连接 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
|
||||
|
||||
# 构建 HTTP 请求
|
||||
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))
|
||||
|
||||
# 发送头部 + 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)
|
||||
|
||||
# 接收响应
|
||||
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):
|
||||
"""释放 Response 对象及其内部缓冲区。
|
||||
|
||||
Args:
|
||||
resp: 要释放的 Response 对象
|
||||
"""
|
||||
if resp is None: return
|
||||
if _mbuddy is None: return
|
||||
if resp._raw_buf is not None:
|
||||
_mbuddy.free(resp._raw_buf)
|
||||
_mbuddy.free(t.CVoid(t.CUInt64T(resp), t.CPtr))
|
||||
@@ -0,0 +1,46 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import (
|
||||
InitializeSRWLock,
|
||||
AcquireSRWLockExclusive, ReleaseSRWLockExclusive,
|
||||
AcquireSRWLockShared, ReleaseSRWLockShared
|
||||
)
|
||||
|
||||
|
||||
@t.Object
|
||||
class RWLock:
|
||||
"""基于 SRWLock 的读写锁,支持多读单写,不支持递归。
|
||||
|
||||
用法:
|
||||
rwlock: RWLock = RWLock()
|
||||
rwlock.acquire_read()
|
||||
# ... 读取共享数据
|
||||
rwlock.release_read()
|
||||
rwlock.acquire_write()
|
||||
# ... 修改共享数据
|
||||
rwlock.release_write()
|
||||
"""
|
||||
lock: VOIDPTR
|
||||
|
||||
def __init__(self):
|
||||
InitializeSRWLock(c.Addr(self.lock))
|
||||
|
||||
def acquire_read(self):
|
||||
AcquireSRWLockShared(c.Addr(self.lock))
|
||||
|
||||
def release_read(self):
|
||||
ReleaseSRWLockShared(c.Addr(self.lock))
|
||||
|
||||
def acquire_write(self):
|
||||
AcquireSRWLockExclusive(c.Addr(self.lock))
|
||||
|
||||
def release_write(self):
|
||||
ReleaseSRWLockExclusive(c.Addr(self.lock))
|
||||
|
||||
def __enter__(self) -> 'RWLock' | t.CPtr:
|
||||
self.acquire_write()
|
||||
return self
|
||||
|
||||
def __exit__(self):
|
||||
self.release_write()
|
||||
@@ -0,0 +1,283 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import platmacro
|
||||
import memhub
|
||||
import string
|
||||
|
||||
# Windows 后端依赖
|
||||
import w32.win32base
|
||||
import w32.win32file
|
||||
|
||||
# POSIX 后端依赖
|
||||
import posix
|
||||
|
||||
|
||||
# 文件拷贝缓冲区大小
|
||||
COPY_BUF_SIZE: t.CDefine = 65536
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# copyfile:拷贝文件内容(不保留权限/元数据)
|
||||
# =============================================================================
|
||||
|
||||
def copyfile(src: str, dst: str) -> int:
|
||||
"""拷贝文件内容。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _copyfile_win32(src, dst)
|
||||
return _copyfile_posix(src, dst)
|
||||
|
||||
|
||||
def _copyfile_win32(src: str, dst: str) -> int:
|
||||
"""Windows:使用 CopyFileA 内核实现(高效)"""
|
||||
result: BOOL = w32.win32file.CopyFileA(src, dst, 0)
|
||||
if result == 0:
|
||||
return -1
|
||||
return 0
|
||||
|
||||
|
||||
def _copyfile_posix(src: str, dst: str) -> int:
|
||||
"""POSIX:手动 read/write 循环拷贝"""
|
||||
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:拷贝文件并保留权限
|
||||
# =============================================================================
|
||||
|
||||
def copy(src: str, dst: str) -> int:
|
||||
"""拷贝文件并保留权限(POSIX 上调用 stat+chmod)。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _copy_win32(src, dst)
|
||||
return _copy_posix(src, dst)
|
||||
|
||||
|
||||
def _copy_win32(src: str, dst: str) -> int:
|
||||
"""Windows:拷贝文件(CopyFileA,Windows 权限模型简单,直接委托 copyfile)"""
|
||||
return _copyfile_win32(src, dst)
|
||||
|
||||
|
||||
def _copy_posix(src: str, dst: str) -> int:
|
||||
"""POSIX:拷贝文件并保留权限(stat+chmod)"""
|
||||
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:递归删除目录树
|
||||
# =============================================================================
|
||||
|
||||
def rmtree(path: str) -> int:
|
||||
"""递归删除目录树。成功返回 0,失败返回 -1。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _rmtree_win32(path)
|
||||
return _rmtree_posix(path)
|
||||
|
||||
|
||||
def _rmtree_win32(path: str) -> int:
|
||||
"""Windows:FindFirstFileA/FindNextFileA 递归删除"""
|
||||
path_len: t.CSizeT = len(path)
|
||||
# 构造搜索模式 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: bool = False
|
||||
if name[0] == '.':
|
||||
if name[1] == 0:
|
||||
skip = True
|
||||
elif name[1] == '.' and name[2] == 0:
|
||||
skip = True
|
||||
if not skip:
|
||||
# 构造完整路径 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
|
||||
# 判断是文件还是目录
|
||||
if (find_data.dwFileAttributes & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
|
||||
# 递归删除子目录
|
||||
sub_result: int = _rmtree_win32(str(full_path))
|
||||
if sub_result != 0:
|
||||
result = -1
|
||||
else:
|
||||
# 删除文件
|
||||
if w32.win32file.DeleteFileA(str(full_path)) == 0:
|
||||
result = -1
|
||||
_mbuddy.free(full_path)
|
||||
# 继续搜索下一个条目
|
||||
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
|
||||
has_more = 0
|
||||
|
||||
w32.win32file.FindClose(handle)
|
||||
# 最后删除空目录本身
|
||||
if result == 0:
|
||||
if w32.win32file.RemoveDirectoryA(path) == 0:
|
||||
result = -1
|
||||
return result
|
||||
|
||||
|
||||
def _rmtree_posix(path: str) -> int:
|
||||
"""POSIX: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 = posix.readdir(dirp)
|
||||
while entry != None:
|
||||
name: str = entry.d_name
|
||||
# 跳过 . 和 ..
|
||||
skip: bool = False
|
||||
if name[0] == '.':
|
||||
if name[1] == 0:
|
||||
skip = True
|
||||
elif name[1] == '.' and name[2] == 0:
|
||||
skip = True
|
||||
if not skip:
|
||||
# 构造完整路径 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
|
||||
# 判断条目类型
|
||||
if entry.d_type == posix.DT_DIR:
|
||||
# 递归删除子目录
|
||||
sub_result: int = _rmtree_posix(str(full_path))
|
||||
if sub_result != 0:
|
||||
result = -1
|
||||
else:
|
||||
# 删除文件/符号链接等
|
||||
if posix.unlink(str(full_path)) != 0:
|
||||
result = -1
|
||||
_mbuddy.free(full_path)
|
||||
entry = posix.readdir(dirp)
|
||||
|
||||
posix.closedir(dirp)
|
||||
# 最后删除空目录本身
|
||||
if result == 0:
|
||||
if posix.rmdir(path) != 0:
|
||||
result = -1
|
||||
return result
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# move:移动文件/目录
|
||||
# =============================================================================
|
||||
|
||||
def move(src: str, dst: str) -> int:
|
||||
"""移动/重命名文件或目录。同分区时直接 rename,跨分区时 copy+delete。
|
||||
成功返回 0,失败返回 -1。"""
|
||||
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,跨分区 copy+delete)"""
|
||||
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 失败,尝试 copy + 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(同分区),跨分区 copy+unlink"""
|
||||
if posix.rename(src, dst) == 0:
|
||||
return 0
|
||||
# rename 失败(可能跨分区),尝试 copy + unlink
|
||||
if copyfile(src, dst) != 0:
|
||||
return -1
|
||||
if posix.unlink(src) != 0:
|
||||
return -1
|
||||
return 0
|
||||
@@ -0,0 +1,451 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import platmacro
|
||||
import stdio
|
||||
import w32.winsock2
|
||||
|
||||
|
||||
# ============================================================
|
||||
# socket.py — 跨平台 Socket 封装
|
||||
# Python 风格 OOP API + 兼容旧版过程式函数
|
||||
#
|
||||
# 用法示例:
|
||||
# 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()
|
||||
#
|
||||
# 仅 3 处平台差异(通过 platmacro.IS_WINDOWS 分支):
|
||||
# 1. WSAStartup() / WSACleanup()
|
||||
# 2. closesocket() vs close()
|
||||
# 3. WSAGetLastError() vs errno
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 常量
|
||||
# ============================================================
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 结构体
|
||||
# ============================================================
|
||||
|
||||
class SocketAddr:
|
||||
"""sockaddr_in — IPv4 地址(16 字节,POSIX 布局)"""
|
||||
family: u16
|
||||
port: u16
|
||||
addr: u32
|
||||
zero: u64
|
||||
|
||||
|
||||
class HostEnt:
|
||||
"""struct hostent — DNS 解析结果"""
|
||||
h_name: CHARPTR
|
||||
h_aliases: CHARPTR
|
||||
h_addrtype: INT
|
||||
h_length: INT
|
||||
h_addr_list: CHARPTR
|
||||
|
||||
|
||||
class timeval:
|
||||
"""struct timeval — 超时设置"""
|
||||
tv_sec: INT
|
||||
tv_usec: INT
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 外部 C 函数 — 使用 u64 句柄,跨平台兼容
|
||||
# (Windows SOCKET=u64, POSIX fd=int → u64 零扩展兼容)
|
||||
# ============================================================
|
||||
|
||||
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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内部辅助函数
|
||||
# ============================================================
|
||||
|
||||
def _CloseFd(fd: INT) -> INT:
|
||||
"""平台差异:Windows 用 closesocket,POSIX 用 close。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return w32.winsock2.closesocket(u64(fd))
|
||||
return close(fd)
|
||||
|
||||
|
||||
def _MakeAddr(host: str, port: INT) -> SocketAddr:
|
||||
"""构建 SocketAddr。先尝试点分十进制 IP,失败则 DNS 解析。"""
|
||||
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 解析 — gethostbyname 返回 struct hostent*
|
||||
# h_addr_list 是 char** → h_addr_list[0] 是 char* → *(uint32_t*)h_addr_list[0] 是 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:
|
||||
"""解析点分十进制 IPv4 地址。"""
|
||||
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 类 — Python 风格 OOP API
|
||||
# ============================================================
|
||||
|
||||
class Socket:
|
||||
"""跨平台 Socket 封装,贴近 Python socket.socket 用法。
|
||||
|
||||
用法:
|
||||
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):
|
||||
"""创建 Socket。
|
||||
|
||||
Args:
|
||||
family: 地址族 (AF_INET)
|
||||
type: 套接字类型 (SOCK_STREAM)
|
||||
protocol: 协议 (默认 0,自动匹配)
|
||||
"""
|
||||
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:
|
||||
"""连接到远程主机。
|
||||
|
||||
Args:
|
||||
host: 主机名或 IP
|
||||
port: 端口号
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
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:
|
||||
"""发送数据。
|
||||
|
||||
Returns:
|
||||
已发送字节数,SOCKET_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:
|
||||
"""接收数据。
|
||||
|
||||
Returns:
|
||||
已接收字节数,SOCKET_ERROR 失败,0 表示连接关闭
|
||||
"""
|
||||
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:
|
||||
"""发送全部数据(循环发送直到完成或出错)。
|
||||
|
||||
Returns:
|
||||
0 成功,SOCKET_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:
|
||||
"""关闭 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:
|
||||
"""绑定地址和端口(服务器端)。
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
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:
|
||||
"""开始监听连接(服务器端)。
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
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:
|
||||
"""接受一个客户端连接。
|
||||
|
||||
Args:
|
||||
out_client: 输出参数,接收客户端 Socket
|
||||
Returns:
|
||||
客户端 fd(>= 0 成功),SOCKET_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:
|
||||
"""设置接收和发送超时(毫秒)。0 表示无超时。
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
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:
|
||||
"""返回底层文件描述符 / SOCKET 句柄。"""
|
||||
return self.fd
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 平台初始化
|
||||
# ============================================================
|
||||
|
||||
def SocketInit() -> INT:
|
||||
"""初始化 Socket 库。Windows 下调用 WSAStartup,POSIX 无操作。"""
|
||||
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:
|
||||
"""清理 Socket 库。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return w32.winsock2.WSACleanup()
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 兼容旧版过程式 API(委托到 Socket 方法)
|
||||
# ============================================================
|
||||
|
||||
def SocketCreate(family: INT, type: INT, protocol: INT, out_sock: Socket | t.CPtr) -> INT:
|
||||
"""创建 Socket 句柄(兼容旧版 API)。建议使用 Socket(...) 构造。"""
|
||||
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
|
||||
|
||||
|
||||
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:
|
||||
"""检查 Socket 是否有效。"""
|
||||
if sock is None: return False
|
||||
return sock.fd != INVALID_SOCKET
|
||||
@@ -0,0 +1,18 @@
|
||||
import t, c
|
||||
import atom
|
||||
|
||||
|
||||
@t.Object
|
||||
class _spinlock:
|
||||
locked: t.CVolatile | t.CInt
|
||||
name: t.CArray[t.CChar, 32]
|
||||
|
||||
def __init__(self):
|
||||
self.locked = 0
|
||||
|
||||
def lock(self):
|
||||
while atom.__atomic_test_and_set(c.Addr(self.locked), atom.ATOMIC_ACQUIRE):
|
||||
pass
|
||||
|
||||
def unlock(self):
|
||||
atom.__atomic_clear(c.Addr(self.locked), atom.ATOMIC_RELEASE)
|
||||
@@ -0,0 +1,9 @@
|
||||
import t
|
||||
|
||||
def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State: pass
|
||||
def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr | t.State: pass
|
||||
def va_end(args: t.CPtr) -> t.State | t.State: pass
|
||||
|
||||
va_list: t.CTypedef = t.CUnsignedChar | t.CPtr
|
||||
|
||||
def arg(type: t.CType) -> t.State: pass
|
||||
@@ -0,0 +1,133 @@
|
||||
import t
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 大写别名(Win32/TransPyC 风格)
|
||||
# 注意:INTPTR/UINTPTR 在此模块中是 int*/unsigned int* 指针类型(历史命名)。
|
||||
# 它们与 C 标准的 intptr_t/uintptr_t 整数类型不同,后者见下方小写 _t 区域。
|
||||
# =============================================================================
|
||||
INT: t.CTypedef = t.CInt
|
||||
INTPTR: t.CTypedef = t.CInt | t.CPtr
|
||||
|
||||
BOOL: t.CTypedef = t.CInt
|
||||
UINT: t.CTypedef = t.CUnsignedInt
|
||||
UINTPTR: t.CTypedef = UINT | t.CPtr
|
||||
BYTE: t.CTypedef = t.CUnsignedChar
|
||||
BYTEPTR: t.CTypedef = BYTE | t.CPtr
|
||||
WORD: t.CTypedef = t.CUInt16T
|
||||
DWORD: t.CTypedef = t.CUInt32T
|
||||
QWORD: t.CTypedef = t.CUInt64T
|
||||
TCHAR: t.CTypedef = t.CChar
|
||||
CHARLIST: t.CTypedef = str | t.CPtr
|
||||
VOID: t.CTypedef = t.CVoid
|
||||
|
||||
SHORT: t.CTypedef = t.CShort
|
||||
SHORTPTR: t.CTypedef = t.CShort | t.CPtr
|
||||
USHORT: t.CTypedef = t.CUnsignedShort
|
||||
USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr
|
||||
|
||||
LONGLONG: t.CTypedef = t.CLongLong
|
||||
ULONGLONG: t.CTypedef = t.CUnsignedLongLong
|
||||
LONG: t.CTypedef = t.CLong
|
||||
ULONG: t.CTypedef = t.CUnsignedLong
|
||||
|
||||
WCHAR: t.CTypedef = WORD
|
||||
WCHARPTR: t.CTypedef = WORD | t.CPtr
|
||||
CHARPTR: t.CTypedef = t.CChar | t.CPtr
|
||||
FSIZE_t: t.CTypedef = DWORD
|
||||
LBA_t: t.CTypedef = DWORD
|
||||
|
||||
VOIDPTR: t.CTypedef = t.CVoid | t.CPtr
|
||||
FLOAT: t.CTypedef = t.CFloat
|
||||
DOUBLE: t.CTypedef = t.CDouble
|
||||
|
||||
FLOAT8: t.CTypedef = t.CFloat8T
|
||||
FLOAT16: t.CTypedef = t.CFloat16T
|
||||
FLOAT32: t.CTypedef = t.CFloat32T
|
||||
FLOAT64: t.CTypedef = t.CFloat64T
|
||||
FLOAT128: t.CTypedef = t.CFloat128T
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 定长整数大写别名
|
||||
# =============================================================================
|
||||
INT8: t.CTypedef = t.CInt8T
|
||||
INT16: t.CTypedef = t.CInt16T
|
||||
INT32: t.CTypedef = t.CInt32T
|
||||
INT64: t.CTypedef = t.CInt64T
|
||||
|
||||
UINT8: t.CTypedef = t.CUInt8T
|
||||
UINT16: t.CTypedef = t.CUInt16T
|
||||
UINT32: t.CTypedef = t.CUInt32T
|
||||
UINT64: t.CTypedef = t.CUInt64T
|
||||
|
||||
INT8PTR: t.CTypedef = t.CInt8T | t.CPtr
|
||||
INT16PTR: t.CTypedef = t.CInt16T | t.CPtr
|
||||
INT32PTR: t.CTypedef = t.CInt32T | t.CPtr
|
||||
INT64PTR: t.CTypedef = t.CInt64T | t.CPtr
|
||||
|
||||
UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr
|
||||
UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr
|
||||
UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr
|
||||
UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr
|
||||
|
||||
CHAR8: t.CTypedef = t.CChar8T
|
||||
CHAR16: t.CTypedef = t.CChar16T
|
||||
CHAR32: t.CTypedef = t.CChar32T
|
||||
CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr
|
||||
CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr
|
||||
CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr
|
||||
|
||||
i8: t.CTypedef = t.CInt8T
|
||||
i16: t.CTypedef = t.CInt16T
|
||||
i32: t.CTypedef = t.CInt32T
|
||||
i64: t.CTypedef = t.CInt64T
|
||||
|
||||
u8: t.CTypedef = t.CUInt8T
|
||||
u16: t.CTypedef = t.CUInt16T
|
||||
u32: t.CTypedef = t.CUInt32T
|
||||
u64: t.CTypedef = t.CUInt64T
|
||||
|
||||
SIZE_T: t.CTypedef = t.CSizeT
|
||||
SSIZE_T: t.CTypedef = t.CPtrDiffT
|
||||
PTRDIFF_T: t.CTypedef = t.CPtrDiffT
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# C 标准库 <stdint.h> 类型名(小写 _t 后缀)
|
||||
# 这些是 C 语言标准类型名,从 _CNAME_ALIAS 挪到此处作为 typedef 提供。
|
||||
# 用户 `from stdint import *` 后即可直接使用 int8_t / size_t 等。
|
||||
# =============================================================================
|
||||
int8_t: t.CTypedef = t.CInt8T
|
||||
int16_t: t.CTypedef = t.CInt16T
|
||||
int32_t: t.CTypedef = t.CInt32T
|
||||
int64_t: t.CTypedef = t.CInt64T
|
||||
|
||||
uint8_t: t.CTypedef = t.CUInt8T
|
||||
uint16_t: t.CTypedef = t.CUInt16T
|
||||
uint32_t: t.CTypedef = t.CUInt32T
|
||||
uint64_t: t.CTypedef = t.CUInt64T
|
||||
|
||||
size_t: t.CTypedef = t.CSizeT
|
||||
ssize_t: t.CTypedef = t.CPtrDiffT
|
||||
ptrdiff_t: t.CTypedef = t.CPtrDiffT
|
||||
|
||||
# intptr_t/uintptr_t 是足以容纳指针的整数类型(不是指针!)
|
||||
# 与上方的 INTPTR/UINTPTR(int 指针)语义不同。
|
||||
intptr_t: t.CTypedef = t.CIntPtrT
|
||||
uintptr_t: t.CTypedef = t.CUIntPtrT
|
||||
|
||||
# 宽字符 / 字符类型
|
||||
wchar_t: t.CTypedef = t.CWCharT
|
||||
char8_t: t.CTypedef = t.CChar8T
|
||||
char16_t: t.CTypedef = t.CChar16T
|
||||
char32_t: t.CTypedef = t.CChar32T
|
||||
|
||||
# 浮点特化类型
|
||||
float8_t: t.CTypedef = t.CFloat8T
|
||||
float16_t: t.CTypedef = t.CFloat16T
|
||||
float32_t: t.CTypedef = t.CFloat32T
|
||||
float64_t: t.CTypedef = t.CFloat64T
|
||||
float128_t: t.CTypedef = t.CFloat128T
|
||||
|
||||
_Bool: t.CTypedef = t.CBool
|
||||
@@ -0,0 +1,16 @@
|
||||
import t, c
|
||||
|
||||
|
||||
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
|
||||
def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
|
||||
def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
|
||||
def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
|
||||
def puts(s: t.CConst | str) -> t.CInt | t.State: pass
|
||||
def fputs(s: t.CConst | str, stream: bytes) -> t.CInt | t.State: pass
|
||||
def fgets(buf: bytes, size: t.CInt, stream: bytes) -> bytes | t.State: pass
|
||||
def fflush(stream: bytes) -> t.CInt | t.State: pass
|
||||
|
||||
# 标准流指针(全局变量,仅声明供 printf 等函数使用)
|
||||
stdin: bytes = 0
|
||||
stdout: bytes = 0
|
||||
stderr: bytes = 0
|
||||
@@ -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
|
||||
@@ -0,0 +1,354 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
|
||||
|
||||
# 字符串复制函数
|
||||
def strcpy(dest: str, src: str) -> str:
|
||||
if dest == None or src == None: return None
|
||||
original_dest: str = dest
|
||||
for s in src:
|
||||
dest[0] = s
|
||||
dest += 1
|
||||
dest[0] = 0
|
||||
return original_dest
|
||||
|
||||
|
||||
# 字符串拼接函数: 将 src 追加到 dest 末尾
|
||||
def strcat(dest: str, src: str) -> str:
|
||||
if dest == None or src == None: return dest
|
||||
original_dest: str = dest
|
||||
# 找到 dest 末尾
|
||||
while dest[0] != '\0':
|
||||
dest += 1
|
||||
# 复制 src
|
||||
for s in src:
|
||||
dest[0] = s
|
||||
dest += 1
|
||||
dest[0] = 0
|
||||
return original_dest
|
||||
|
||||
|
||||
# 有限长度字符串复制函数
|
||||
def strncpy(dest: str, src: str, n: t.CSizeT) -> str:
|
||||
if dest == None or src == None or n == 0: return dest
|
||||
original_dest: str = dest
|
||||
i: t.CSizeT = 0
|
||||
for s in src:
|
||||
if i >= n: break
|
||||
dest[0] = s
|
||||
dest += 1
|
||||
i += 1
|
||||
# 填充剩余空间为 '\0'
|
||||
while i < n:
|
||||
dest[0] = 0
|
||||
dest += 1
|
||||
i += 1
|
||||
return original_dest
|
||||
|
||||
|
||||
# 字符串长度函数
|
||||
def strlen(src: str) -> t.CSizeT | t.CExport:
|
||||
length: t.CSizeT = 0
|
||||
for _ in src:
|
||||
length += 1
|
||||
return length
|
||||
|
||||
# 字符串比较函数
|
||||
def strcmp(str1: str, str2: str) -> t.CInt:
|
||||
while str1[0] != '\0' and str2[0] != '\0':
|
||||
if str1[0] != str2[0]:
|
||||
return str1[0] - str2[0]
|
||||
str1 += 1
|
||||
str2 += 1
|
||||
return str1[0] - str2[0]
|
||||
|
||||
def samestr(str1: str, str2: str) -> bool:
|
||||
return str1 == str2
|
||||
|
||||
|
||||
# 有限长度字符串比较函数
|
||||
def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt:
|
||||
i: t.CSizeT = 0
|
||||
while str1[0] != '\0' and str2[0] != '\0' and i < n:
|
||||
if str1[0] != str2[0]:
|
||||
return str1[0] - str2[0]
|
||||
str1 += 1
|
||||
str2 += 1
|
||||
i += 1
|
||||
if i < n:
|
||||
return str1[0] - str2[0]
|
||||
return 0
|
||||
|
||||
|
||||
# 内存比较函数
|
||||
def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt:
|
||||
p1: BYTEPTR = BYTEPTR(ptr1)
|
||||
p2: BYTEPTR = BYTEPTR(ptr2)
|
||||
i: t.CSizeT = 0
|
||||
while i < n:
|
||||
if p1[i] != p2[i]:
|
||||
return t.CInt(p1[i]) - t.CInt(p2[i])
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
# 字符串查找函数
|
||||
def strchr(s: str, cr: t.CInt) -> str:
|
||||
while s[0] != '\0':
|
||||
if s[0] == t.CChar(cr):
|
||||
return str(s)
|
||||
s += 1
|
||||
if cr == '\0':
|
||||
return str(s)
|
||||
return None
|
||||
|
||||
# 字符串反向查找函数(找最后一次出现的字符)
|
||||
def strrchr(s: str, cr: t.CInt) -> str:
|
||||
last: str = None
|
||||
while s[0] != '\0':
|
||||
if s[0] == t.CChar(cr):
|
||||
last = s
|
||||
s += 1
|
||||
if cr == '\0': return s
|
||||
return last
|
||||
|
||||
|
||||
# 子串查找函数(在 s 中查找 needle 第一次出现的位置,返回指向该位置的指针,未找到返回 None)
|
||||
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
|
||||
|
||||
# 跳过字符
|
||||
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
|
||||
|
||||
# 内存设置函数
|
||||
def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
|
||||
# 原始实现:
|
||||
# p: BYTEPTR = BYTEPTR(ptr)
|
||||
# i: t.CSizeT
|
||||
# for i in range(num):
|
||||
# p[i] = t.CUnsignedChar(value)
|
||||
if num == 0: return ptr
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
|
||||
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
rep stosb""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
|
||||
return ptr
|
||||
|
||||
|
||||
def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
# 原始实现:
|
||||
# p: UINT32PTR = UINT32PTR(ptr)
|
||||
# i: t.CSizeT
|
||||
# for i in range(count):
|
||||
# p[i] = value
|
||||
if count == 0: return ptr
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}
|
||||
mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov rcx, {c.AsmInp(count, t.ASM_DESCR.REG_ANY)}
|
||||
rep stosd""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI])
|
||||
return ptr
|
||||
|
||||
|
||||
# 内存复制函数
|
||||
def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
|
||||
# 原始实现:
|
||||
# d: BYTEPTR = BYTEPTR(dest)
|
||||
# s: BYTEPTR = BYTEPTR(src)
|
||||
# i: t.CSizeT
|
||||
# for i in range(num):
|
||||
# d[i] = s[i]
|
||||
if num == 0: return dest
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
|
||||
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
rep movsb""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
|
||||
return dest
|
||||
|
||||
|
||||
# 内存移动函数
|
||||
def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
# 原始实现:
|
||||
# d: BYTEPTR = BYTEPTR(dest)
|
||||
# s: BYTEPTR = BYTEPTR(src)
|
||||
# i: t.CSizeT
|
||||
# if d < s:
|
||||
# for i in range(num):
|
||||
# d[i] = s[i]
|
||||
# elif d > s:
|
||||
# for i in range(num, 0, -1):
|
||||
# d[i - 1] = s[i - 1]
|
||||
if num == 0: return dest
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)}
|
||||
mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
cmp rdi, rsi
|
||||
jb 2f
|
||||
std
|
||||
add rdi, rcx
|
||||
dec rdi
|
||||
add rsi, rcx
|
||||
dec rsi
|
||||
rep movsb
|
||||
cld
|
||||
jmp 3f
|
||||
2:
|
||||
rep movsb
|
||||
3:""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI])
|
||||
return dest
|
||||
|
||||
|
||||
def atoi(src: str) -> t.CInt:
|
||||
num: t.CInt = 0
|
||||
sign: t.CInt = 1
|
||||
s: str = src
|
||||
if s == None: return 0
|
||||
# 跳过空白
|
||||
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
|
||||
s += 1
|
||||
# 符号
|
||||
if s[0] == '-':
|
||||
sign = -1
|
||||
s += 1
|
||||
elif s[0] == '+':
|
||||
s += 1
|
||||
for ch in s:
|
||||
if ch < '0' or ch > '9': break
|
||||
digit: t.CInt = ch - '0'
|
||||
num = num * 10 + digit
|
||||
return num * sign
|
||||
|
||||
|
||||
def atoll(src: str) -> t.CInt64T:
|
||||
num: t.CInt64T = 0
|
||||
sign: t.CInt64T = 1
|
||||
s: str = src
|
||||
if s == None: return 0
|
||||
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
|
||||
s += 1
|
||||
if s[0] == '-':
|
||||
sign = -1
|
||||
s += 1
|
||||
elif s[0] == '+':
|
||||
s += 1
|
||||
for ch in s:
|
||||
if ch < '0' or ch > '9': break
|
||||
d: t.CInt = ch - '0'
|
||||
digit: t.CInt64T = t.CInt64T(d)
|
||||
num = num * 10 + digit
|
||||
return num * sign
|
||||
|
||||
|
||||
def atof(src: str) -> t.CDouble:
|
||||
s: str = src
|
||||
if s == None: return 0.0
|
||||
# 跳过空白
|
||||
while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r':
|
||||
s += 1
|
||||
# 符号
|
||||
sign: t.CDouble = 1.0
|
||||
if s[0] == '-':
|
||||
sign = -1.0
|
||||
s += 1
|
||||
elif s[0] == '+':
|
||||
s += 1
|
||||
# 整数部分
|
||||
int_part: t.CDouble = 0.0
|
||||
for ch in s:
|
||||
if ch < '0' or ch > '9': break
|
||||
d1: t.CInt = ch - '0'
|
||||
int_part = int_part * 10.0 + t.CDouble(d1)
|
||||
s += 1
|
||||
# 小数部分
|
||||
frac_part: t.CDouble = 0.0
|
||||
frac_div: t.CDouble = 1.0
|
||||
if s[0] == '.':
|
||||
s += 1
|
||||
for ch in s:
|
||||
if ch < '0' or ch > '9': break
|
||||
d2: t.CInt = ch - '0'
|
||||
frac_div = frac_div * 10.0
|
||||
frac_part = frac_part * 10.0 + t.CDouble(d2)
|
||||
s += 1
|
||||
# 指数部分
|
||||
exp: t.CInt = 0
|
||||
exp_sign: t.CInt = 1
|
||||
if s[0] == 'e' or s[0] == 'E':
|
||||
s += 1
|
||||
if s[0] == '-':
|
||||
exp_sign = -1
|
||||
s += 1
|
||||
elif s[0] == '+':
|
||||
s += 1
|
||||
for ch in s:
|
||||
if ch < '0' or ch > '9': break
|
||||
d3: t.CInt = ch - '0'
|
||||
exp = exp * 10 + d3
|
||||
s += 1
|
||||
exp = exp * exp_sign
|
||||
result: t.CDouble = sign * (int_part + frac_part / frac_div)
|
||||
# 应用指数
|
||||
if exp > 0:
|
||||
while exp > 0:
|
||||
result = result * 10.0
|
||||
exp -= 1
|
||||
elif exp < 0:
|
||||
while exp < 0:
|
||||
result = result / 10.0
|
||||
exp += 1
|
||||
return result
|
||||
|
||||
def split(s: str, delim: str, result: 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
|
||||
@@ -0,0 +1,196 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import platmacro
|
||||
import memhub
|
||||
import string
|
||||
|
||||
# Windows 后端依赖
|
||||
import w32.win32base
|
||||
import w32.win32file
|
||||
import w32.win32process
|
||||
import w32.win32sync
|
||||
|
||||
# POSIX 后端依赖
|
||||
import posix
|
||||
|
||||
|
||||
# 子进程输出缓冲区大小
|
||||
OUTPUT_BUF_SIZE: t.CDefine = 65536
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# CompletedProcess 结果类
|
||||
# =============================================================================
|
||||
|
||||
class CompletedProcess:
|
||||
"""subprocess.run 的返回结果"""
|
||||
args: str # 原始命令行
|
||||
returncode: int # 进程退出码(0 表示成功)
|
||||
stdout: str # 标准输出(capture_output=True 时)
|
||||
stderr: str # 标准错误(capture_output=True 时)
|
||||
|
||||
def __new__(self, args: str, returncode: int, stdout: str, stderr: str) -> t.CPtr:
|
||||
# 堆分配(避免返回栈地址导致 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
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 入口函数
|
||||
# =============================================================================
|
||||
|
||||
def run(args: str, capture_output: bool = True, text: bool = True) -> CompletedProcess | t.CPtr:
|
||||
"""同步执行子进程并等待完成。
|
||||
args 为完整命令行字符串。
|
||||
capture_output=True 时捕获 stdout/stderr。
|
||||
text=True 时输出为字符串(当前实现总是返回字符串)。
|
||||
返回 CompletedProcess 对象。"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _run_win32(args, capture_output, text)
|
||||
return _run_posix(args, capture_output, text)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Windows 后端实现
|
||||
# =============================================================================
|
||||
|
||||
def _run_win32(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr:
|
||||
"""Windows 平台子进程执行(CreateProcessA + 管道)"""
|
||||
# 复制命令行(CreateProcessA 需要可修改的 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
|
||||
|
||||
# 安全属性(允许句柄继承)
|
||||
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
|
||||
|
||||
# 创建 stdout 管道
|
||||
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)
|
||||
# 防止读端被子进程继承
|
||||
w32.win32file.SetHandleInformation(stdout_read, w32.win32file.HANDLE_FLAG_INHERIT, 0)
|
||||
|
||||
# 设置启动信息
|
||||
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 合并到 stdout
|
||||
|
||||
pi: w32.win32process.PROCESS_INFORMATION = w32.win32process.PROCESS_INFORMATION()
|
||||
|
||||
# 创建进程
|
||||
# capture_output=True 时用 CREATE_NO_WINDOW(输出到管道,不需要控制台)
|
||||
# capture_output=False 时用 0(继承父进程控制台,让 stdout 直接显示)
|
||||
create_flags: ULONG = w32.win32process.CREATE_NO_WINDOW if capture_output else 0
|
||||
create_result: BOOL = w32.win32process.CreateProcessA(
|
||||
t.CPtr(0), # lpApplicationName (NULL,从命令行解析)
|
||||
cmd_line, # lpCommandLine (可修改)
|
||||
t.CPtr(0), # lpProcessAttributes
|
||||
t.CPtr(0), # lpThreadAttributes
|
||||
1, # bInheritHandles = TRUE
|
||||
create_flags, # dwCreationFlags
|
||||
t.CPtr(0), # lpEnvironment (继承父进程)
|
||||
t.CPtr(0), # lpCurrentDirectory (继承父进程)
|
||||
t.CPtr(c.Addr(si)),
|
||||
t.CPtr(c.Addr(pi))
|
||||
)
|
||||
|
||||
if create_result == 0:
|
||||
# 创建失败
|
||||
if capture_output:
|
||||
w32.win32base.CloseHandle(stdout_read)
|
||||
w32.win32base.CloseHandle(stdout_write)
|
||||
return CompletedProcess(args, -1, None, None)
|
||||
|
||||
# 关闭父进程的写端(子进程已有写端的继承副本)
|
||||
if capture_output:
|
||||
w32.win32base.CloseHandle(stdout_write)
|
||||
|
||||
# 读取 stdout + 等待进程结束
|
||||
# 注意:必须边读边等,否则子进程输出超过管道缓冲区时会死锁
|
||||
# (子进程阻塞在写 stdout,父进程阻塞在 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
|
||||
# 缓冲区将满,扩容(翻倍)
|
||||
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:
|
||||
# 扩容失败,停止读取
|
||||
break
|
||||
buf[total] = 0
|
||||
stdout_str = str(buf)
|
||||
|
||||
# 等待进程结束(如果还没退出的话)
|
||||
w32.win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE)
|
||||
|
||||
# 获取退出码
|
||||
exit_code: ULONG = 0
|
||||
w32.win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(c.Addr(exit_code)))
|
||||
|
||||
# 关闭句柄
|
||||
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 后端实现
|
||||
# =============================================================================
|
||||
|
||||
def _run_posix(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr:
|
||||
"""POSIX 平台子进程执行(fork + execvp + pipe + waitpid)
|
||||
注意:当前为桩函数。POSIX 实现需要 pipe/fork/waitpid,
|
||||
这些函数在 Windows MinGW 上不可用,待 POSIX 平台测试时再完善。"""
|
||||
return CompletedProcess(args, -1, None, None)
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import platmacro
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
|
||||
# Windows 后端依赖
|
||||
import w32.win32base
|
||||
import w32.win32process
|
||||
|
||||
# POSIX 后端依赖
|
||||
import posix
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# C 标准库 IO 声明
|
||||
# =============================================================================
|
||||
|
||||
def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass
|
||||
|
||||
def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass
|
||||
|
||||
# C 标准库 exit(刷新缓冲区后终止进程,跨平台)
|
||||
def exit(status: INT) -> VOID | t.CExtern | t.CExport: pass
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 平台信息
|
||||
# =============================================================================
|
||||
|
||||
# 最大整数值(64 位平台 ssize_t 上限)
|
||||
maxsize: t.CDefine = 9223372036854775807
|
||||
|
||||
|
||||
def platform() -> str:
|
||||
"""返回平台标识字符串('win32' 或 'linux')"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return "win32"
|
||||
return "linux"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 进程信息
|
||||
# =============================================================================
|
||||
|
||||
def get_pid() -> int:
|
||||
"""返回当前进程 ID"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return w32.win32process.GetCurrentProcessId()
|
||||
return posix.getpid()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 命令行参数(argv)
|
||||
# =============================================================================
|
||||
|
||||
# 全局 argv 状态(首次访问时初始化)
|
||||
_argc: INT = 0
|
||||
# _argv 是指针数组(char**),必须用 str | t.CPtr 使索引按 sizeof(char*) 步长
|
||||
# str 本身是 char*,| t.CPtr 再加一层指针 = char**
|
||||
# bytes | t.CPtr 也是 char**,可以同样用
|
||||
_argv: str | t.CPtr
|
||||
|
||||
|
||||
def _init_argv():
|
||||
"""初始化全局 argv(首次访问时调用一次)"""
|
||||
global _argc, _argv
|
||||
if _argc != 0:
|
||||
return
|
||||
if platmacro.IS_WINDOWS:
|
||||
_init_argv_win32()
|
||||
else:
|
||||
_init_argv_posix()
|
||||
|
||||
|
||||
def _init_argv_win32():
|
||||
"""Windows:GetCommandLineA + 手动解析(处理空格/双引号/反斜杠)"""
|
||||
global _argc, _argv
|
||||
cmdline: CHARPTR = w32.win32base.GetCommandLineA()
|
||||
if cmdline == None:
|
||||
return
|
||||
cmdlen: t.CSizeT = string.strlen(cmdline)
|
||||
if cmdlen == 0:
|
||||
return
|
||||
|
||||
# 分配参数字符串缓冲区(最坏情况:整个命令行 + argc 个 \0)
|
||||
buf: bytes = _mbuddy.alloc(cmdlen + 1)
|
||||
if buf == None:
|
||||
return
|
||||
|
||||
# 分配指针数组(最坏情况:每个字符都是一个参数)
|
||||
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: # 双引号
|
||||
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:
|
||||
# 空格或 Tab(引号外):参数分隔符
|
||||
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:读取 /proc/self/cmdline(参数以 \\0 分隔,末尾双 \\0)"""
|
||||
global _argc, _argv
|
||||
fd: INT = posix.open("/proc/self/cmdline", posix.O_RDONLY, 0)
|
||||
if fd < 0:
|
||||
return
|
||||
|
||||
# 读取 cmdline(4KB 足够大多数情况)
|
||||
buf: bytes = _mbuddy.alloc(4096)
|
||||
if buf == None:
|
||||
posix.close(fd)
|
||||
return
|
||||
|
||||
total: ssize_t = posix.read(fd, buf, 4096)
|
||||
posix.close(fd)
|
||||
if total <= 0:
|
||||
return
|
||||
|
||||
# 计算参数个数(\0 分隔)
|
||||
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
|
||||
|
||||
# 分配指针数组
|
||||
argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(argc * platmacro.SIZEOF_POINTER))
|
||||
if argv_arr == None:
|
||||
return
|
||||
|
||||
# 填充指针(每个参数的起始地址)
|
||||
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:
|
||||
"""返回命令行参数个数。首次调用时自动初始化。"""
|
||||
if _argc == 0:
|
||||
_init_argv()
|
||||
return _argc
|
||||
|
||||
|
||||
def argv(index: int) -> str:
|
||||
"""返回第 index 个命令行参数(index 从 0 开始)。
|
||||
首次调用时自动初始化。索引越界返回 None。"""
|
||||
if _argc == 0:
|
||||
_init_argv()
|
||||
if index < 0 or index >= _argc:
|
||||
return None
|
||||
return _argv[index]
|
||||
@@ -0,0 +1,71 @@
|
||||
# testcheck - 回归测试格式化输出库
|
||||
# 提供 PASS/FAIL 计数、分节标题、汇总报告
|
||||
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):
|
||||
"""开始测试套件,打印头部并重置当前套件计数器(累计计数不变)"""
|
||||
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):
|
||||
"""打印分节标题"""
|
||||
stdio.printf("--- %s ---\n", name)
|
||||
|
||||
|
||||
def ok(msg: str):
|
||||
"""打印 PASS 并计数"""
|
||||
global _pass_count
|
||||
_pass_count += 1
|
||||
stdio.printf("PASS: %s\n", msg)
|
||||
|
||||
|
||||
def fail(msg: str):
|
||||
"""打印 FAIL 并计数"""
|
||||
global _fail_count
|
||||
_fail_count += 1
|
||||
stdio.printf("FAIL: %s\n", msg)
|
||||
|
||||
|
||||
def check(cond: t.CInt, ok_msg: str, fail_msg: str):
|
||||
"""条件检查,自动选择 PASS/FAIL"""
|
||||
if cond:
|
||||
ok(ok_msg)
|
||||
else:
|
||||
fail(fail_msg)
|
||||
|
||||
|
||||
def info(msg: str):
|
||||
"""打印信息消息(不计入 PASS/FAIL)"""
|
||||
stdio.printf("%s\n", msg)
|
||||
|
||||
|
||||
def end() -> t.CInt:
|
||||
"""打印当前套件汇总,累加到总计,返回当前套件失败数"""
|
||||
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:
|
||||
"""打印所有套件的总计汇总,返回总失败数"""
|
||||
stdio.printf("\n=== Total Summary ===\n")
|
||||
stdio.printf("Total PASS: %d, Total FAIL: %d\n", _total_pass, _total_fail)
|
||||
return _total_fail
|
||||
@@ -0,0 +1,39 @@
|
||||
import stdio, t, c
|
||||
|
||||
|
||||
def this():
|
||||
s: str = """Ivcre Cevapvcyrf, ol GrezvArkhf
|
||||
|
||||
Ornhgl orngf htyvarff.
|
||||
Rkcyvpvg orngf vzcyvpvg.
|
||||
Fvzcyr orngf pbzcyrk.
|
||||
Pbapvfr orngf ireobfr.
|
||||
Syng orngf qrrc arfgvat.
|
||||
Fcnpvbhf orngf pyhggrerq.
|
||||
Ernqnovyvgl vf pehpvny.
|
||||
Fcrpvny pnfrf qba’g whfgvsl oernxvat gur ehyrf.
|
||||
Ohg cenpgvpnyvgl orngf cher vqrnyf.
|
||||
Reebef fubhyq arire or fvyragyl vtaberq.
|
||||
Hayrff rkcyvpvgyl fgngrq gb or vtaberq.
|
||||
Jura snprq jvgu nzovthbhf frznagvpf, erfvfg znxvat nffhzcgvbaf.
|
||||
Hayrff pyrneyl nyybjrq.
|
||||
Gurer fubhyq or bar — cersrenoyl bayl bar — boivbhf jnl gb qb vg.
|
||||
Rira vs vg’f uneq gb tenfc ng svefg, hayrff lbh qrrcyl haqrefgnaq gur haqreylvat flfgrz.
|
||||
Fgnegvat vzzrqvngryl orngf vaqrsvavgr qrynl.
|
||||
Ohg unfgl npgvba vf bsgra jbefr guna pnershy jnvgvat.
|
||||
Vs na vzcyrzragngvba vf bofpher naq uneq gb qrfpevor, vg’f n onq fbyhgvba.
|
||||
Vs na vzcyrzragngvba vf pyrne naq rnfl gb haqrefgnaq, punaprf ner vg’f n tbbq fbyhgvba.
|
||||
Anzrfcnprf ner vaperqvoyl inyhnoyr — hfr gurz trarebhfyl!"""
|
||||
|
||||
# ASCII
|
||||
m: t.CArray[t.CChar, 256] = [0]
|
||||
l: t.CArray[int, 2] = [65, 97]
|
||||
|
||||
for k in l:
|
||||
for i in range(26):
|
||||
m[k + i] = (k + ((i + 13) % 26)) # 隐式类型转换
|
||||
|
||||
for ch in s:
|
||||
_: t.CUInt8T = ch
|
||||
stdio.printf("%c", m[_] if m[_] else ch)
|
||||
stdio.printf("\n")
|
||||
@@ -0,0 +1,66 @@
|
||||
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
|
||||
old_size: t.CSizeT = self.capacity * self.elem_size
|
||||
new_size: t.CSizeT = new_capacity * self.elem_size
|
||||
new_data: t.CVoid | t.CPtr = self.pool.realloc(self.data, old_size, new_size)
|
||||
if new_data == None: return
|
||||
self.data = new_data
|
||||
self.capacity = new_capacity
|
||||
|
||||
def get(self, index: t.CSizeT) -> T:
|
||||
if self.data == None: return T(0)
|
||||
offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size
|
||||
typed_ptr = T(offset, t.CPtr)
|
||||
return c.Deref(typed_ptr)
|
||||
|
||||
def set(self, index: t.CSizeT, value: T):
|
||||
if index >= self.length: return
|
||||
if self.data == None: return
|
||||
offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size
|
||||
dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr)
|
||||
c.DerefAs(dst, value)
|
||||
|
||||
def len(self) -> t.CSizeT:
|
||||
return self.length
|
||||
|
||||
def clear(self):
|
||||
self.length = 0
|
||||
|
||||
def free(self):
|
||||
if self.data != None:
|
||||
if self.pool != None:
|
||||
self.pool.free(self.data)
|
||||
self.data = None
|
||||
self.length = 0
|
||||
self.capacity = 0
|
||||
@@ -0,0 +1,57 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
|
||||
class Buf:
|
||||
data: t.CChar | t.CPtr
|
||||
length: t.CSizeT
|
||||
capacity: t.CSizeT
|
||||
owned: bool
|
||||
|
||||
def __init__(self, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT = 0, owned: bool = False):
|
||||
self.data = data
|
||||
self.capacity = capacity
|
||||
self.length = length
|
||||
self.owned = owned
|
||||
|
||||
def clear(self):
|
||||
self.length = 0
|
||||
if self.data != None and self.capacity > 0:
|
||||
self.data[0] = 0
|
||||
|
||||
def write(self, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT:
|
||||
if self.data == None: return 0
|
||||
if src == None: return 0
|
||||
if count == 0: return 0
|
||||
avail: t.CSizeT = self.capacity - self.length
|
||||
if avail <= 0: return 0
|
||||
n: t.CSizeT = count if count < avail else avail
|
||||
i: t.CSizeT = 0
|
||||
while i < n:
|
||||
self.data[self.length + i] = src[i]
|
||||
i += 1
|
||||
self.length += n
|
||||
self.data[self.length] = 0
|
||||
return n
|
||||
|
||||
def cstr(self) -> t.CChar | t.CPtr:
|
||||
return self.data
|
||||
|
||||
def reset(self):
|
||||
self.length = 0
|
||||
if self.data != None and self.capacity > 0:
|
||||
self.data[0] = 0
|
||||
|
||||
def __enter__(self) -> 'Buf' | t.CPtr:
|
||||
return self
|
||||
|
||||
def __exit__(self):
|
||||
self.reset()
|
||||
|
||||
def free(self):
|
||||
if self.owned and self.data != None:
|
||||
self.data[0] = 0
|
||||
self.owned = False
|
||||
self.data = None
|
||||
self.length = 0
|
||||
self.capacity = 0
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,542 @@
|
||||
import t, c
|
||||
|
||||
|
||||
U_M_PI: t.CDefine = 3.14159265358979323846
|
||||
U_M_E: t.CDefine = 2.71828182845904523536
|
||||
U_M_PI_2: t.CDefine = 1.57079632679489661923
|
||||
U_M_PI_4: t.CDefine = 0.78539816339744830962
|
||||
U_M_1_PI: t.CDefine = 0.31830988618379067154
|
||||
U_M_2_PI: t.CDefine = 0.63661977236758134308
|
||||
|
||||
U_M_LN2: t.CDefine = 0.69314718055994530942
|
||||
U_M_LN10: t.CDefine = 2.30258509299404568402
|
||||
|
||||
U_M_2_SQRT_PI: t.CDefine = 1.77245385090551602730
|
||||
|
||||
def radians(degrees: t.CDouble) -> t.CDouble:
|
||||
return degrees * (U_M_PI / t.CDouble(180.0))
|
||||
|
||||
def degrees(radians: t.CDouble) -> t.CDouble:
|
||||
return radians * (t.CDouble(180.0) / U_M_PI)
|
||||
|
||||
def sin(x: t.CDouble) -> t.CDouble:
|
||||
while x > U_M_PI:
|
||||
x -= t.CDouble(2.0) * U_M_PI
|
||||
while x < -U_M_PI:
|
||||
x += t.CDouble(2.0) * U_M_PI
|
||||
x2: t.CDouble = x * x
|
||||
result: t.CDouble = x
|
||||
term: t.CDouble = x
|
||||
term = term * x2 / t.CDouble(6.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(20.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(42.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(72.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(110.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(156.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(210.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(272.0)
|
||||
result = result + term
|
||||
return result
|
||||
|
||||
|
||||
def cos(x: t.CDouble) -> t.CDouble:
|
||||
while x > U_M_PI:
|
||||
x -= t.CDouble(2.0) * U_M_PI
|
||||
while x < -U_M_PI:
|
||||
x += t.CDouble(2.0) * U_M_PI
|
||||
x2: t.CDouble = x * x
|
||||
result: t.CDouble = t.CDouble(1.0)
|
||||
term: t.CDouble = t.CDouble(1.0)
|
||||
term = term * x2 / t.CDouble(2.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(12.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(30.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(56.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(90.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(132.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(182.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(240.0)
|
||||
result = result + term
|
||||
return result
|
||||
|
||||
|
||||
def tan(x: t.CDouble) -> t.CDouble:
|
||||
return sin(x) / cos(x)
|
||||
|
||||
|
||||
def asin(x: t.CDouble) -> t.CDouble:
|
||||
if x > t.CDouble(1.0):
|
||||
x = t.CDouble(1.0)
|
||||
if x < t.CDouble(-1.0):
|
||||
x = t.CDouble(-1.0)
|
||||
x2: t.CDouble = x * x
|
||||
result: t.CDouble = x
|
||||
result += x * x2 / t.CDouble(6.0)
|
||||
result += t.CDouble(3.0) * x * x2 * x2 / t.CDouble(40.0)
|
||||
result += t.CDouble(5.0) * x * x2 * x2 * x2 / t.CDouble(112.0)
|
||||
result += t.CDouble(35.0) * x * x2 * x2 * x2 * x2 / t.CDouble(1152.0)
|
||||
result += t.CDouble(63.0) * x * x2 * x2 * x2 * x2 * x2 / t.CDouble(2816.0)
|
||||
return result
|
||||
|
||||
|
||||
def acos(x: t.CDouble) -> t.CDouble:
|
||||
return U_M_PI / t.CDouble(2.0) - asin(x)
|
||||
|
||||
|
||||
def _atan_core(x: t.CDouble) -> t.CDouble:
|
||||
x2: t.CDouble = x * x
|
||||
result: t.CDouble = x
|
||||
term: t.CDouble = x
|
||||
term = term * x2 / t.CDouble(3.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(5.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(7.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(9.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(11.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(13.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(15.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(17.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CDouble(19.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CDouble(21.0)
|
||||
result = result + term
|
||||
return result
|
||||
|
||||
|
||||
def atan(x: t.CDouble) -> t.CDouble:
|
||||
ax: t.CDouble = x
|
||||
if ax < t.CDouble(0.0):
|
||||
ax = -ax
|
||||
if ax > t.CDouble(1.0):
|
||||
return t.CDouble(0.0) - _atan_core(t.CDouble(1.0) / ax) + U_M_PI_2 if x > t.CDouble(0.0) else _atan_core(t.CDouble(1.0) / ax) - U_M_PI_2
|
||||
return _atan_core(x) if x >= t.CDouble(0.0) else t.CDouble(0.0) - _atan_core(ax)
|
||||
|
||||
|
||||
def atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble:
|
||||
if x > t.CDouble(0.0):
|
||||
return atan(y / x)
|
||||
elif x < t.CDouble(0.0):
|
||||
if y >= t.CDouble(0.0):
|
||||
return atan(y / x) + U_M_PI
|
||||
else:
|
||||
return atan(y / x) - U_M_PI
|
||||
else:
|
||||
if y > t.CDouble(0.0):
|
||||
return U_M_PI_2
|
||||
elif y < t.CDouble(0.0):
|
||||
return t.CDouble(0.0) - U_M_PI_2
|
||||
else:
|
||||
return t.CDouble(0.0)
|
||||
|
||||
|
||||
def sinh(x: t.CDouble) -> t.CDouble:
|
||||
ex: t.CDouble = exp(x)
|
||||
e_negx: t.CDouble = exp(-x)
|
||||
return (ex - e_negx) / t.CDouble(2.0)
|
||||
|
||||
|
||||
def cosh(x: t.CDouble) -> t.CDouble:
|
||||
ex: t.CDouble = exp(x)
|
||||
e_negx: t.CDouble = exp(-x)
|
||||
return (ex + e_negx) / t.CDouble(2.0)
|
||||
|
||||
|
||||
def tanh(x: t.CDouble) -> t.CDouble:
|
||||
ex: t.CDouble = exp(x)
|
||||
e_negx: t.CDouble = exp(-x)
|
||||
return (ex - e_negx) / (ex + e_negx)
|
||||
|
||||
|
||||
def exp(x: t.CDouble) -> t.CDouble:
|
||||
if x > t.CDouble(709.0):
|
||||
return t.CDouble(1.7976931348623157e308)
|
||||
if x < t.CDouble(-709.0):
|
||||
return t.CDouble(0.0)
|
||||
result: t.CDouble = t.CDouble(1.0)
|
||||
term: t.CDouble = t.CDouble(1.0)
|
||||
term = term * x / t.CDouble(1.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(2.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(3.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(4.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(5.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(6.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(7.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(8.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(9.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(10.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(11.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(12.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(13.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(14.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(15.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(16.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(17.0)
|
||||
result = result + term
|
||||
term = term * x / t.CDouble(18.0)
|
||||
result = result + term
|
||||
return result
|
||||
|
||||
|
||||
def log(x: t.CDouble) -> t.CDouble:
|
||||
if x <= t.CDouble(0.0):
|
||||
return t.CDouble(-1e308)
|
||||
exponent: t.CInt = 0
|
||||
while x >= t.CDouble(2.0):
|
||||
x /= t.CDouble(2.0)
|
||||
exponent += 1
|
||||
while x < t.CDouble(1.0):
|
||||
x *= t.CDouble(2.0)
|
||||
exponent -= 1
|
||||
y: t.CDouble = (x - t.CDouble(1.0)) / (x + t.CDouble(1.0))
|
||||
y2: t.CDouble = y * y
|
||||
result: t.CDouble = t.CDouble(2.0) * y
|
||||
term: t.CDouble = t.CDouble(2.0) * y
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(3.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(5.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(7.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(9.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(11.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(13.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(15.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(17.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(19.0)
|
||||
term = term * y2
|
||||
result = result + term / t.CDouble(21.0)
|
||||
result += t.CDouble(exponent) * U_M_LN2
|
||||
return result
|
||||
|
||||
|
||||
def sqrt(x: t.CDouble) -> t.CDouble:
|
||||
if x < t.CDouble(0.0):
|
||||
return t.CDouble(0.0)
|
||||
if x == t.CDouble(0.0):
|
||||
return t.CDouble(0.0)
|
||||
guess: t.CDouble = x / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
guess = (guess + x / guess) / t.CDouble(2.0)
|
||||
return guess
|
||||
|
||||
|
||||
def abs(x: t.CInt) -> t.CInt:
|
||||
return x if x >= 0 else -x
|
||||
|
||||
def fabs(x: t.CDouble) -> t.CDouble:
|
||||
return x if x >= t.CDouble(0.0) else -x
|
||||
|
||||
def labs(x: t.CLong) -> t.CLong:
|
||||
return x if x >= 0 else -x
|
||||
|
||||
def factorial(n: t.CInt) -> t.CDouble:
|
||||
if n < 0: return t.CDouble(0.0)
|
||||
if n == 0 or n == 1: return t.CDouble(1.0)
|
||||
result: t.CDouble = t.CDouble(1.0)
|
||||
for i in range(2, n + 1):
|
||||
result *= i
|
||||
return result
|
||||
|
||||
|
||||
def combination(n: t.CInt, k: t.CInt) -> t.CDouble:
|
||||
if k < 0 or k > n: return t.CDouble(0.0)
|
||||
if k == 0 or k == n: return t.CDouble(1.0)
|
||||
k = k if k < n - k else n - k
|
||||
result: t.CDouble = t.CDouble(1.0)
|
||||
for i in range(1, k + 1):
|
||||
result = result * (n - k + i) / i
|
||||
return result
|
||||
|
||||
|
||||
def permutation(n: t.CInt, k: t.CInt) -> t.CDouble:
|
||||
if k < 0 or k > n: return t.CDouble(0.0)
|
||||
result: t.CDouble = t.CDouble(1.0)
|
||||
for i in range(0, k):
|
||||
result *= (n - i)
|
||||
return result
|
||||
|
||||
def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble:
|
||||
if x == t.CDouble(0.0):
|
||||
if y > t.CDouble(0.0):
|
||||
return t.CDouble(0.0)
|
||||
return t.CDouble(1.0)
|
||||
if x < t.CDouble(0.0):
|
||||
iy: t.CDouble = y * log(-x)
|
||||
return exp(iy)
|
||||
return exp(y * log(x))
|
||||
|
||||
|
||||
def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble:
|
||||
return pow(x, y)
|
||||
|
||||
|
||||
def cbrt(x: t.CDouble) -> t.CDouble:
|
||||
return pow(x, t.CDouble(1.0) / t.CDouble(3.0))
|
||||
|
||||
def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble:
|
||||
return sqrt(x * x + y * y)
|
||||
|
||||
|
||||
def floor(x: t.CDouble) -> t.CDouble:
|
||||
if x >= t.CDouble(0.0):
|
||||
return t.CDouble(t.CInt(x))
|
||||
i: t.CInt = t.CInt(x)
|
||||
if x < t.CDouble(i):
|
||||
return t.CDouble(i - 1)
|
||||
else:
|
||||
return t.CDouble(i)
|
||||
|
||||
|
||||
def ceil(x: t.CDouble) -> t.CDouble:
|
||||
if x < t.CDouble(0.0):
|
||||
return t.CDouble(t.CInt(x))
|
||||
i: t.CInt = t.CInt(x)
|
||||
if x > t.CDouble(i):
|
||||
return t.CDouble(i + 1)
|
||||
else:
|
||||
return t.CDouble(i)
|
||||
|
||||
|
||||
def round(x: t.CDouble) -> t.CDouble:
|
||||
return floor(x + t.CDouble(0.5))
|
||||
|
||||
def trunc(x: t.CDouble) -> t.CDouble:
|
||||
if x >= t.CDouble(0.0):
|
||||
return floor(x)
|
||||
else:
|
||||
return ceil(x)
|
||||
|
||||
|
||||
def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble:
|
||||
if y == t.CDouble(0.0):
|
||||
return t.CDouble(0.0)
|
||||
result: t.CDouble = x - y * floor(x / y)
|
||||
if result < t.CDouble(0.0):
|
||||
result += y
|
||||
return result
|
||||
|
||||
|
||||
def fmodf(x: float, y: float) -> float:
|
||||
if y == float(0.0):
|
||||
return float(0.0)
|
||||
result: float = x - y * floorf(x / y)
|
||||
if result < float(0.0):
|
||||
result += y
|
||||
return result
|
||||
|
||||
|
||||
def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble:
|
||||
int_part: t.CDouble = floor(x)
|
||||
c.Set(c.Deref(iptr), int_part)
|
||||
return x - int_part
|
||||
|
||||
|
||||
def log10(x: t.CDouble) -> t.CDouble:
|
||||
return log(x) / U_M_LN10
|
||||
|
||||
|
||||
def log2(x: t.CDouble) -> t.CDouble:
|
||||
return log(x) / U_M_LN2
|
||||
|
||||
|
||||
def exp2(x: t.CDouble) -> t.CDouble:
|
||||
return pow(t.CDouble(2.0), x)
|
||||
|
||||
|
||||
def expm1(x: t.CDouble) -> t.CDouble:
|
||||
return exp(x) - t.CDouble(1.0)
|
||||
|
||||
|
||||
def log1p(x: t.CDouble) -> t.CDouble:
|
||||
return log(t.CDouble(1.0) + x)
|
||||
|
||||
|
||||
def asinh(x: t.CDouble) -> t.CDouble:
|
||||
return log(x + sqrt(x * x + t.CDouble(1.0)))
|
||||
|
||||
def acosh(x: t.CDouble) -> t.CDouble:
|
||||
return log(x + sqrt(x * x - t.CDouble(1.0)))
|
||||
|
||||
def atanh(x: t.CDouble) -> t.CDouble:
|
||||
return (log(t.CDouble(1.0) + x) - log(t.CDouble(1.0) - x)) / t.CDouble(2.0)
|
||||
|
||||
|
||||
def gamma(x: t.CDouble) -> t.CDouble:
|
||||
if x <= t.CDouble(0.0): return t.CDouble(0.0)
|
||||
if x == t.CDouble(1.0) or x == t.CDouble(2.0): return t.CDouble(1.0)
|
||||
ln_gamma: t.CDouble = t.CDouble(0.5) * log(t.CDouble(2.0) * U_M_PI / x) + x * log(x / U_M_E)
|
||||
return exp(ln_gamma)
|
||||
|
||||
|
||||
def erf(x: t.CDouble) -> t.CDouble:
|
||||
sign: t.CDouble = t.CDouble(1.0) if x >= t.CDouble(0.0) else t.CDouble(-1.0)
|
||||
abs_x: t.CDouble = fabs(x)
|
||||
t0: t.CDouble = t.CDouble(4.0) * abs_x * abs_x / U_M_PI
|
||||
exp_term: t.CDouble = exp(-t0)
|
||||
return sign * sqrt(t.CDouble(1.0) - exp_term)
|
||||
|
||||
|
||||
def erfc(x: t.CDouble) -> t.CDouble:
|
||||
return t.CDouble(1.0) - erf(x)
|
||||
|
||||
def sqrtf(x: t.CFloat) -> t.CFloat:
|
||||
if x < t.CFloat(0.0):
|
||||
return t.CFloat(0.0)
|
||||
if x == t.CFloat(0.0):
|
||||
return t.CFloat(0.0)
|
||||
guess: t.CFloat = x / t.CFloat(2.0)
|
||||
for i in range(10):
|
||||
guess = (guess + x / guess) / t.CFloat(2.0)
|
||||
return guess
|
||||
|
||||
def sinf(x: t.CFloat) -> t.CFloat:
|
||||
while x > t.CFloat(3.14159265):
|
||||
x -= t.CFloat(6.28318530)
|
||||
while x < t.CFloat(-3.14159265):
|
||||
x += t.CFloat(6.28318530)
|
||||
x2: t.CFloat = x * x
|
||||
result: t.CFloat = x
|
||||
term: t.CFloat = x
|
||||
term = term * x2 / t.CFloat(6.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(20.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CFloat(42.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(72.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CFloat(110.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(156.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CFloat(210.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(272.0)
|
||||
result = result + term
|
||||
return result
|
||||
|
||||
def cosf(x: t.CFloat) -> t.CFloat:
|
||||
while x > t.CFloat(3.14159265):
|
||||
x -= t.CFloat(6.28318530)
|
||||
while x < t.CFloat(-3.14159265):
|
||||
x += t.CFloat(6.28318530)
|
||||
x2: t.CFloat = x * x
|
||||
result: t.CFloat = t.CFloat(1.0)
|
||||
term: t.CFloat = t.CFloat(1.0)
|
||||
term = term * x2 / t.CFloat(2.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(12.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CFloat(30.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(56.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CFloat(90.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(132.0)
|
||||
result = result + term
|
||||
term = term * x2 / t.CFloat(182.0)
|
||||
result = result - term
|
||||
term = term * x2 / t.CFloat(240.0)
|
||||
result = result + term
|
||||
return result
|
||||
|
||||
def tanf(x: t.CFloat) -> t.CFloat:
|
||||
c: t.CFloat = cosf(x)
|
||||
if c == t.CFloat(0.0):
|
||||
return t.CFloat(0.0)
|
||||
return sinf(x) / c
|
||||
|
||||
def fabsf(x: t.CFloat) -> t.CFloat:
|
||||
return x if x >= t.CFloat(0.0) else -x
|
||||
|
||||
def floorf(x: t.CFloat) -> t.CFloat:
|
||||
if x >= t.CFloat(0.0):
|
||||
return t.CFloat(t.CInt(x))
|
||||
i: t.CInt = t.CInt(x)
|
||||
if x < t.CFloat(i):
|
||||
return t.CFloat(i - 1)
|
||||
else:
|
||||
return t.CFloat(i)
|
||||
|
||||
def ceilf(x: t.CFloat) -> t.CFloat:
|
||||
if x < t.CFloat(0.0):
|
||||
return t.CFloat(t.CInt(x))
|
||||
i: t.CInt = t.CInt(x)
|
||||
if x > t.CFloat(i):
|
||||
return t.CFloat(i + 1)
|
||||
else:
|
||||
return t.CFloat(i)
|
||||
|
||||
|
||||
class _U(t.CUnion):
|
||||
d: t.CDouble
|
||||
u: t.CUInt64T
|
||||
|
||||
def isnan(x: t.CDouble) -> t.CStatic | t.CInt:
|
||||
u: t.CUInt64T = t.CUInt64T(x)
|
||||
exp_part: t.CUInt64T = (u >> 52) & 0x7FF
|
||||
mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF
|
||||
if exp_part == 0x7FF:
|
||||
if mantissa_part != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def isinf(x: t.CDouble) -> t.CStatic | t.CInt:
|
||||
u: t.CUInt64T = t.CUInt64T(x)
|
||||
exp_part: t.CUInt64T = (u >> 52) & 0x7FF
|
||||
mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF
|
||||
if exp_part == 0x7FF:
|
||||
if mantissa_part == 0:
|
||||
return 1
|
||||
return 0
|
||||
@@ -0,0 +1,460 @@
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AVX2 双精度向量运算 (4 x double, 256-bit YMM)
|
||||
# ============================================================
|
||||
|
||||
def simd_add4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4] + b[0:4]"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vaddpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_sub4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4] - b[0:4]"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vsubpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_mul4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4] * b[0:4]"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vmulpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_div4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4] / b[0:4]"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vdivpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_sqrt4d(a: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = sqrt(a[0:4])"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vsqrtpd ymm0, ymm0
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0'])
|
||||
|
||||
|
||||
def simd_neg4d(a: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = -a[0:4] (flip sign bit via XOR)"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vpcmpeqd ymm1, ymm1, ymm1
|
||||
vpsllq ymm1, ymm1, 63
|
||||
vxorpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_abs4d(a: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = |a[0:4]| (clear sign bit via ANDN)"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vpcmpeqd ymm1, ymm1, ymm1
|
||||
vpsllq ymm1, ymm1, 63
|
||||
vandnpd ymm0, ymm1, ymm0
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_max4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = max(a[0:4], b[0:4])"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vmaxpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_min4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = min(a[0:4], b[0:4])"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vminpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_mul_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4] * scalar (broadcast)"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vbroadcastsd ymm1, [{c.AsmInp(scalar, t.ASM_DESCR.REG_ANY)}]
|
||||
vmulpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_add_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4] + scalar (broadcast)"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vbroadcastsd ymm1, [{c.AsmInp(scalar, t.ASM_DESCR.REG_ANY)}]
|
||||
vaddpd ymm0, ymm0, ymm1
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_hsum4d(a: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0] = a[0]+a[1]+a[2]+a[3] (horizontal sum)"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vextractf128 xmm1, ymm0, 1
|
||||
vaddpd xmm0, xmm0, xmm1
|
||||
vhaddpd xmm0, xmm0, xmm0
|
||||
vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_dot4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0] = dot(a[0:4], b[0:4])"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vmulpd ymm0, ymm0, ymm1
|
||||
vextractf128 xmm1, ymm0, 1
|
||||
vaddpd xmm0, xmm0, xmm1
|
||||
vhaddpd xmm0, xmm0, xmm0
|
||||
vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1'])
|
||||
|
||||
|
||||
def simd_fma4d(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""AVX2: out[0:4] = a[0:4]*b[0:4] + c[0:4] (fused multiply-add)
|
||||
Uses vfmadd213pd: ymm0 = ymm1 * ymm0 + ymm2
|
||||
Load order: b->ymm0, a->ymm1, c->ymm2"""
|
||||
c.Asm(f"""vmovupd ymm0, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm1, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
vmovupd ymm2, [{c.AsmInp(c_val, t.ASM_DESCR.REG_ANY)}]
|
||||
vfmadd213pd ymm0, ymm1, ymm2
|
||||
vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'ymm2'])
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SSE2 单精度向量运算 (4 x float, 128-bit XMM)
|
||||
# ============================================================
|
||||
|
||||
def simd_add4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""SSE2: out[0:4] = a[0:4] + b[0:4] (float)"""
|
||||
c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
addps xmm0, xmm1
|
||||
movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1'])
|
||||
|
||||
|
||||
def simd_sub4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""SSE2: out[0:4] = a[0:4] - b[0:4] (float)"""
|
||||
c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
subps xmm0, xmm1
|
||||
movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1'])
|
||||
|
||||
|
||||
def simd_mul4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""SSE2: out[0:4] = a[0:4] * b[0:4] (float)"""
|
||||
c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
mulps xmm0, xmm1
|
||||
movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1'])
|
||||
|
||||
|
||||
def simd_div4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid:
|
||||
"""SSE2: out[0:4] = a[0:4] / b[0:4] (float)"""
|
||||
c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}]
|
||||
movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}]
|
||||
divps xmm0, xmm1
|
||||
movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1'])
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 批量数组运算 (AVX2 循环, 处理 N 个 double)
|
||||
# ============================================================
|
||||
|
||||
def simd_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid:
|
||||
"""AVX2 batch: out[i:i+4] = a[i:i+4] + b[i:i+4], i=0,4,8,..."""
|
||||
c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)}
|
||||
mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
test rcx, rcx
|
||||
jz .Ladd_end
|
||||
.Ladd_loop:
|
||||
vmovupd ymm0, [r8]
|
||||
vmovupd ymm1, [r9]
|
||||
vaddpd ymm0, ymm0, ymm1
|
||||
vmovupd [r10], ymm0
|
||||
add r8, 32
|
||||
add r9, 32
|
||||
add r10, 32
|
||||
dec rcx
|
||||
jnz .Ladd_loop
|
||||
.Ladd_end:
|
||||
vzeroupper""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10'])
|
||||
|
||||
|
||||
def simd_sub_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid:
|
||||
"""AVX2 batch: out[i:i+4] = a[i:i+4] - b[i:i+4]"""
|
||||
c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)}
|
||||
mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
test rcx, rcx
|
||||
jz .Lsub_end
|
||||
.Lsub_loop:
|
||||
vmovupd ymm0, [r8]
|
||||
vmovupd ymm1, [r9]
|
||||
vsubpd ymm0, ymm0, ymm1
|
||||
vmovupd [r10], ymm0
|
||||
add r8, 32
|
||||
add r9, 32
|
||||
add r10, 32
|
||||
dec rcx
|
||||
jnz .Lsub_loop
|
||||
.Lsub_end:
|
||||
vzeroupper""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10'])
|
||||
|
||||
|
||||
def simd_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid:
|
||||
"""AVX2 batch: out[i:i+4] = a[i:i+4] * b[i:i+4]"""
|
||||
c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)}
|
||||
mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
test rcx, rcx
|
||||
jz .Lmul_end
|
||||
.Lmul_loop:
|
||||
vmovupd ymm0, [r8]
|
||||
vmovupd ymm1, [r9]
|
||||
vmulpd ymm0, ymm0, ymm1
|
||||
vmovupd [r10], ymm0
|
||||
add r8, 32
|
||||
add r9, 32
|
||||
add r10, 32
|
||||
dec rcx
|
||||
jnz .Lmul_loop
|
||||
.Lmul_end:
|
||||
vzeroupper""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10'])
|
||||
|
||||
|
||||
def simd_div_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid:
|
||||
"""AVX2 batch: out[i:i+4] = a[i:i+4] / b[i:i+4]"""
|
||||
c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)}
|
||||
mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
test rcx, rcx
|
||||
jz .Ldiv_end
|
||||
.Ldiv_loop:
|
||||
vmovupd ymm0, [r8]
|
||||
vmovupd ymm1, [r9]
|
||||
vdivpd ymm0, ymm0, ymm1
|
||||
vmovupd [r10], ymm0
|
||||
add r8, 32
|
||||
add r9, 32
|
||||
add r10, 32
|
||||
dec rcx
|
||||
jnz .Ldiv_loop
|
||||
.Ldiv_end:
|
||||
vzeroupper""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10'])
|
||||
|
||||
|
||||
def simd_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid:
|
||||
"""AVX2 batch: out[i:i+4] = sqrt(a[i:i+4])"""
|
||||
c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
test rcx, rcx
|
||||
jz .Lsqrt_end
|
||||
.Lsqrt_loop:
|
||||
vmovupd ymm0, [r8]
|
||||
vsqrtpd ymm0, ymm0
|
||||
vmovupd [r10], ymm0
|
||||
add r8, 32
|
||||
add r10, 32
|
||||
dec rcx
|
||||
jnz .Lsqrt_loop
|
||||
.Lsqrt_end:
|
||||
vzeroupper""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'rcx', 'r8', 'r10'])
|
||||
|
||||
|
||||
def simd_abs_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid:
|
||||
"""AVX2 batch: out[i:i+4] = |a[i:i+4]|"""
|
||||
c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
vpcmpeqd ymm2, ymm2, ymm2
|
||||
vpsllq ymm2, ymm2, 63
|
||||
test rcx, rcx
|
||||
jz .Labs_end
|
||||
.Labs_loop:
|
||||
vmovupd ymm0, [r8]
|
||||
vandnpd ymm0, ymm2, ymm0
|
||||
vmovupd [r10], ymm0
|
||||
add r8, 32
|
||||
add r10, 32
|
||||
dec rcx
|
||||
jnz .Labs_loop
|
||||
.Labs_end:
|
||||
vzeroupper""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm2', 'rcx', 'r8', 'r10'])
|
||||
|
||||
|
||||
def simd_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 精确标量运算 (LLVM 内置函数)
|
||||
# ============================================================
|
||||
|
||||
def simd_sqrt(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: sqrt(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.sqrt.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_fabs(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: |x|"""
|
||||
return c.LLVMIR(f"call double @llvm.fabs.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_floor(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: floor(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.floor.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_ceil(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: ceil(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.ceil.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_round(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: round(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.round.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_trunc(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: trunc(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.trunc.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_fma(a: t.CDouble, b: t.CDouble, c_val: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: a*b + c (single rounding)"""
|
||||
return c.LLVMIR(f"call double @llvm.fma.f64(double {c.LInp(a)}, double {c.LInp(b)}, double {c.LInp(c_val)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_copysign(mag: t.CDouble, sign: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: copysign(mag, sign)"""
|
||||
return c.LLVMIR(f"call double @llvm.copysign.f64(double {c.LInp(mag)}, double {c.LInp(sign)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_neg(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: -x (via copysign, 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.
|
||||
"""
|
||||
return c.LLVMIR(f"call double @llvm.copysign.f64(double {c.LInp(x)}, double {c.LInp(t.CDouble(0.0) - x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_minnum(a: t.CDouble, b: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: min(a, b) (NaN-aware)"""
|
||||
return c.LLVMIR(f"call double @llvm.minnum.f64(double {c.LInp(a)}, double {c.LInp(b)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_maxnum(a: t.CDouble, b: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: max(a, b) (NaN-aware)"""
|
||||
return c.LLVMIR(f"call double @llvm.maxnum.f64(double {c.LInp(a)}, double {c.LInp(b)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_exp(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: e^x"""
|
||||
return c.LLVMIR(f"call double @llvm.exp.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_log(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: ln(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.log.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_sin(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: sin(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.sin.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_cos(x: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: cos(x)"""
|
||||
return c.LLVMIR(f"call double @llvm.cos.f64(double {c.LInp(x)})", t.CDouble)
|
||||
|
||||
|
||||
def simd_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble:
|
||||
"""LLVM intrinsic: x^y"""
|
||||
return c.LLVMIR(f"call double @llvm.pow.f64(double {c.LInp(x)}, double {c.LInp(y)})", t.CDouble)
|
||||
@@ -0,0 +1 @@
|
||||
from .string import *
|
||||
@@ -0,0 +1,379 @@
|
||||
# vrandom - 硬件随机数生成库
|
||||
# 基于 x86 RDRAND / RDSEED 指令,使用内嵌汇编实现
|
||||
import t, c
|
||||
import vipermath
|
||||
|
||||
|
||||
# 重试次数限制(RDRAND 通常不需要重试,RDSEED 可能需要)
|
||||
RDRAND_RETRY_LIMIT: t.CDefine = 10
|
||||
RDSEED_RETRY_LIMIT: t.CDefine = 100
|
||||
|
||||
|
||||
# ============================================================
|
||||
# RDRAND - 硬件随机数(伪随机数发生器输出)
|
||||
# ============================================================
|
||||
|
||||
def rdrand16() -> t.CUInt16T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return t.CUInt16T(val)
|
||||
|
||||
|
||||
def rdrand32() -> t.CUInt32T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
def rdrand64() -> t.CUInt64T:
|
||||
val: t.CUInt64T = 0
|
||||
c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
# ============================================================
|
||||
# RDSEED - 硬件随机种子(熵源直接输出)
|
||||
# ============================================================
|
||||
|
||||
def rdseed16() -> t.CUInt16T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return t.CUInt16T(val)
|
||||
|
||||
|
||||
def rdseed32() -> t.CUInt32T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
def rdseed64() -> t.CUInt64T:
|
||||
val: t.CUInt64T = 0
|
||||
c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Step 版本(带成功标志,匹配 GCC builtin 接口)
|
||||
# 返回 1 表示成功,0 表示失败;随机值写入 *p
|
||||
# ============================================================
|
||||
|
||||
def rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = t.CUInt16T(val)
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt64T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = t.CUInt16T(val)
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt64T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 带重试的便捷接口(自动重试直到成功或达到上限)
|
||||
# ============================================================
|
||||
|
||||
def random_u16() -> t.CUInt16T:
|
||||
r: t.CUInt16T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDRAND_RETRY_LIMIT:
|
||||
if rdrand16_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def random_u32() -> t.CUInt32T:
|
||||
r: t.CUInt32T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDRAND_RETRY_LIMIT:
|
||||
if rdrand32_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def random_u64() -> t.CUInt64T:
|
||||
r: t.CUInt64T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDRAND_RETRY_LIMIT:
|
||||
if rdrand64_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def seed_u16() -> t.CUInt16T:
|
||||
r: t.CUInt16T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDSEED_RETRY_LIMIT:
|
||||
if rdseed16_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def seed_u32() -> t.CUInt32T:
|
||||
r: t.CUInt32T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDSEED_RETRY_LIMIT:
|
||||
if rdseed32_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def seed_u64() -> t.CUInt64T:
|
||||
r: t.CUInt64T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDSEED_RETRY_LIMIT:
|
||||
if rdseed64_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Python random 标准库函数实现
|
||||
# 默认类型:t.CUInt64T (u64), t.CDouble (f64), t.CInt (i32)
|
||||
# ============================================================
|
||||
|
||||
# ---------- 一、随机整数 ----------
|
||||
|
||||
def randint(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return t.CInt(a + t.CInt(random_u64() % t.CUInt64T(b - a + 1)))
|
||||
|
||||
|
||||
def randrange(start: t.CInt, stop: t.CInt, step: t.CInt = 1) -> t.CInt:
|
||||
width: t.CInt = 0
|
||||
if step > 0:
|
||||
width = (stop - start + step - 1) // step
|
||||
else:
|
||||
width = (start - stop - step - 1) // (-step)
|
||||
return t.CInt(start + t.CInt(random_u64() % t.CUInt64T(width)) * step)
|
||||
|
||||
|
||||
def getrandbits(k: t.CInt) -> t.CUInt64T:
|
||||
r: t.CUInt64T = rdrand64()
|
||||
if k >= 64:
|
||||
return r
|
||||
mask: t.CUInt64T = (t.CUInt64T(1) << k) - t.CUInt64T(1)
|
||||
return r & mask
|
||||
|
||||
|
||||
# ---------- 二、随机浮点数 ----------
|
||||
|
||||
def random() -> t.CDouble:
|
||||
return t.CDouble(rdrand64() >> 11) * (t.CDouble(1.0) / t.CDouble(9007199254740992.0))
|
||||
|
||||
|
||||
def uniform(a: t.CDouble, b: t.CDouble) -> t.CDouble:
|
||||
return a + (b - a) * random()
|
||||
|
||||
|
||||
def triangular(low: t.CDouble, high: t.CDouble, mode: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
c: t.CDouble = (mode - low) / (high - low)
|
||||
if u > c:
|
||||
u = t.CDouble(1.0) - u
|
||||
c = t.CDouble(1.0) - c
|
||||
tmp: t.CDouble = low
|
||||
low = high
|
||||
high = tmp
|
||||
return low + (high - low) * vipermath.sqrt(u * c)
|
||||
|
||||
|
||||
def betavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble:
|
||||
y: t.CDouble = gammavariate(alpha, t.CDouble(1.0))
|
||||
if y != t.CDouble(0.0):
|
||||
return y / (y + gammavariate(beta, t.CDouble(1.0)))
|
||||
return t.CDouble(0.0)
|
||||
|
||||
|
||||
def expovariate(lambd: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return -vipermath.log(t.CDouble(1.0) - u) / lambd
|
||||
|
||||
|
||||
def gammavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = t.CDouble(0.0)
|
||||
d: t.CDouble = t.CDouble(0.0)
|
||||
c: t.CDouble = t.CDouble(0.0)
|
||||
x: t.CDouble = t.CDouble(0.0)
|
||||
v: t.CDouble = t.CDouble(0.0)
|
||||
if alpha <= t.CDouble(0.0) or beta <= t.CDouble(0.0):
|
||||
return t.CDouble(0.0)
|
||||
if alpha < t.CDouble(1.0):
|
||||
u = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return gammavariate(alpha + t.CDouble(1.0), beta) * vipermath.pow(u, t.CDouble(1.0) / alpha)
|
||||
d = alpha - t.CDouble(1.0) / t.CDouble(3.0)
|
||||
c = t.CDouble(1.0) / vipermath.sqrt(t.CDouble(9.0) * d)
|
||||
while 1:
|
||||
x = gauss(t.CDouble(0.0), t.CDouble(1.0))
|
||||
v = t.CDouble(1.0) + c * x
|
||||
if v > t.CDouble(0.0):
|
||||
v = v * v * v
|
||||
u = random()
|
||||
if u < t.CDouble(1.0) - t.CDouble(0.0331) * x * x * x * x:
|
||||
return d * v * beta
|
||||
if vipermath.log(u) < t.CDouble(0.5) * x * x + d * (t.CDouble(1.0) - v + vipermath.log(v)):
|
||||
return d * v * beta
|
||||
|
||||
|
||||
def gauss(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble:
|
||||
u1: t.CDouble = random()
|
||||
u2: t.CDouble = random()
|
||||
if u1 < t.CDouble(1e-300):
|
||||
u1 = t.CDouble(1e-300)
|
||||
z0: t.CDouble = vipermath.sqrt(t.CDouble(-2.0) * vipermath.log(u1)) * vipermath.cos(t.CDouble(2.0) * vipermath.U_M_PI * u2)
|
||||
return mu + sigma * z0
|
||||
|
||||
|
||||
def normalvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble:
|
||||
NV_MAGICCONST: t.CDouble = t.CDouble(1.7155277699214135)
|
||||
u1: t.CDouble = t.CDouble(0.0)
|
||||
u2: t.CDouble = t.CDouble(0.0)
|
||||
z: t.CDouble = t.CDouble(0.0)
|
||||
zz: t.CDouble = t.CDouble(0.0)
|
||||
while 1:
|
||||
u1 = random()
|
||||
u2 = random()
|
||||
if u2 < t.CDouble(1e-300):
|
||||
continue
|
||||
z = NV_MAGICCONST * (u1 - t.CDouble(0.5)) / u2
|
||||
zz = z * z / t.CDouble(4.0)
|
||||
if zz <= t.CDouble(0.0) - vipermath.log(u2):
|
||||
break
|
||||
return mu + z * sigma
|
||||
|
||||
|
||||
def lognormvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble:
|
||||
return vipermath.exp(gauss(mu, sigma))
|
||||
|
||||
|
||||
def vonmisesvariate(mu: t.CDouble, kappa: t.CDouble) -> t.CDouble:
|
||||
if kappa <= t.CDouble(1e-6):
|
||||
return vipermath.U_M_PI * t.CDouble(2.0) * random()
|
||||
s: t.CDouble = t.CDouble(0.5) / kappa
|
||||
r: t.CDouble = s + vipermath.sqrt(t.CDouble(1.0) + s * s)
|
||||
u1: t.CDouble = t.CDouble(0.0)
|
||||
u2: t.CDouble = t.CDouble(0.0)
|
||||
u3: t.CDouble = t.CDouble(0.0)
|
||||
z: t.CDouble = t.CDouble(0.0)
|
||||
d: t.CDouble = t.CDouble(0.0)
|
||||
q: t.CDouble = t.CDouble(0.0)
|
||||
f: t.CDouble = t.CDouble(0.0)
|
||||
theta: t.CDouble = t.CDouble(0.0)
|
||||
two_pi: t.CDouble = vipermath.U_M_PI * t.CDouble(2.0)
|
||||
while 1:
|
||||
u1 = random()
|
||||
z = vipermath.cos(vipermath.U_M_PI * u1)
|
||||
d = t.CDouble(1.0) / (r + z)
|
||||
u2 = random()
|
||||
if u2 < t.CDouble(1.0) - d * d:
|
||||
break
|
||||
if u2 < (t.CDouble(1.0) - z) * vipermath.exp(kappa * (z - t.CDouble(1.0)) - d * kappa * r):
|
||||
break
|
||||
q = t.CDouble(1.0) / r
|
||||
f = (q + z) / (t.CDouble(1.0) + q * z)
|
||||
u3 = random()
|
||||
if u3 > t.CDouble(0.5):
|
||||
theta = mu + vipermath.acos(f)
|
||||
else:
|
||||
theta = mu - vipermath.acos(f)
|
||||
while theta < t.CDouble(0.0):
|
||||
theta += two_pi
|
||||
while theta >= two_pi:
|
||||
theta -= two_pi
|
||||
return theta
|
||||
|
||||
|
||||
def paretovariate(alpha: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return t.CDouble(1.0) / vipermath.pow(t.CDouble(1.0) - u, t.CDouble(1.0) / alpha)
|
||||
|
||||
|
||||
def weibullvariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return alpha * vipermath.pow(t.CDouble(-1.0) * vipermath.log(t.CDouble(1.0) - u), t.CDouble(1.0) / beta)
|
||||
@@ -0,0 +1,104 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32process import CreateThread, GetExitCodeThread, GetCurrentThreadId, TlsAlloc, TlsFree, TlsGetValue, TlsSetValue
|
||||
from w32.win32sync import WaitForSingleObject
|
||||
|
||||
# 全部导入锁类,用户也可按需导入
|
||||
from lock import Lock
|
||||
from event import Event
|
||||
from condition import Condition
|
||||
from rwlock import RWLock
|
||||
|
||||
|
||||
@t.Object
|
||||
class Thread:
|
||||
"""线程类,封装 Windows CreateThread。
|
||||
|
||||
线程回调签名: def thread_func(arg: t.CPtr) -> t.CPtr
|
||||
注意: Windows API 限制返回值为 DWORD(32位),64位指针会被截断。
|
||||
如需返回 64 位结果,请通过 arg 参数结构体传递。
|
||||
|
||||
用法:
|
||||
def worker(arg: t.CPtr) -> t.CPtr:
|
||||
# 线程逻辑
|
||||
return NULL
|
||||
|
||||
t: Thread = Thread(worker, arg_ptr)
|
||||
t.start()
|
||||
t.join()
|
||||
"""
|
||||
handle: HANDLE
|
||||
thread_id: ULONG
|
||||
target: VOIDPTR
|
||||
arg: VOIDPTR
|
||||
started: BOOL
|
||||
|
||||
def __init__(self, target: VOIDPTR, arg: VOIDPTR = NULL):
|
||||
self.handle = NULL
|
||||
self.thread_id = 0
|
||||
self.target = target
|
||||
self.arg = arg
|
||||
self.started = FALSE
|
||||
|
||||
def start(self):
|
||||
if self.started:
|
||||
return
|
||||
self.handle = CreateThread(NULL, 0, self.target, self.arg, 0, c.Addr(self.thread_id))
|
||||
self.started = TRUE
|
||||
|
||||
def join(self, timeout_ms: ULONG = INFINITE) -> BOOL:
|
||||
if not self.started:
|
||||
return FALSE
|
||||
result: ULONG = WaitForSingleObject(self.handle, timeout_ms)
|
||||
return result == WAIT_OBJECT_0
|
||||
|
||||
def is_alive(self) -> BOOL:
|
||||
if not self.started:
|
||||
return FALSE
|
||||
result: ULONG = WaitForSingleObject(self.handle, 0)
|
||||
return result == WAIT_TIMEOUT
|
||||
|
||||
def get_exit_code(self) -> ULONG:
|
||||
code: ULONG = 0
|
||||
GetExitCodeThread(self.handle, c.Addr(code))
|
||||
return code
|
||||
|
||||
def close(self):
|
||||
if self.handle != NULL:
|
||||
CloseHandle(self.handle)
|
||||
self.handle = NULL
|
||||
|
||||
|
||||
@t.Object
|
||||
class local:
|
||||
"""TLS (Thread Local Storage) 封装。
|
||||
|
||||
用法:
|
||||
tls: local = local()
|
||||
tls.set(value_ptr)
|
||||
val: t.CPtr = tls.get()
|
||||
"""
|
||||
index: ULONG
|
||||
|
||||
def __init__(self):
|
||||
self.index = TlsAlloc()
|
||||
|
||||
def get(self) -> VOIDPTR:
|
||||
return TlsGetValue(self.index)
|
||||
|
||||
def set(self, value: VOIDPTR) -> BOOL:
|
||||
return TlsSetValue(self.index, value)
|
||||
|
||||
def free(self) -> BOOL:
|
||||
return TlsFree(self.index)
|
||||
|
||||
|
||||
def get_current_thread_id() -> ULONG:
|
||||
"""获取当前线程 ID"""
|
||||
return GetCurrentThreadId()
|
||||
|
||||
|
||||
def sleep_ms(ms: ULONG):
|
||||
"""让当前线程休眠指定毫秒数"""
|
||||
Sleep(ms)
|
||||
@@ -0,0 +1,394 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import w32.win32base
|
||||
import w32.win32file
|
||||
|
||||
|
||||
class MODE(t.CEnum):
|
||||
R = 0
|
||||
W = 1
|
||||
A = 2
|
||||
RP = 3
|
||||
WP = 4
|
||||
AP = 5
|
||||
X = 6
|
||||
XP = 7
|
||||
|
||||
|
||||
class FRESULT(t.CEnum):
|
||||
OK = 0
|
||||
ERR = -1
|
||||
ERR_CLOSED = -2
|
||||
ERR_PERM = -3
|
||||
ERR_IO = -4
|
||||
ERR_NOTFOUND = -5
|
||||
|
||||
|
||||
SEEK_SET: t.CDefine = 0
|
||||
SEEK_CUR: t.CDefine = 1
|
||||
SEEK_END: t.CDefine = 2
|
||||
|
||||
INVALID_SET_FILE_POINTER: t.CDefine = -1
|
||||
|
||||
SHARE_READ: t.CDefine = 0x00000001
|
||||
SHARE_WRITE: t.CDefine = 0x00000002
|
||||
SHARE_DELETE: t.CDefine = 0x00000004
|
||||
|
||||
|
||||
class File:
|
||||
handle: w32.win32base.HANDLE
|
||||
closed: bool
|
||||
can_read: bool
|
||||
can_write: bool
|
||||
is_append: bool
|
||||
_share_mode: ULONG
|
||||
|
||||
def __init__(self, filename: str, mode: ULONG, share: ULONG = SHARE_READ):
|
||||
self.closed = True
|
||||
self.can_read = False
|
||||
self.can_write = False
|
||||
self.is_append = False
|
||||
self._share_mode = share
|
||||
|
||||
access: ULONG = 0
|
||||
disposition: ULONG = w32.win32file.OPEN_EXISTING
|
||||
|
||||
if mode == MODE.R:
|
||||
access = w32.win32file.GENERIC_READ
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
elif mode == MODE.W:
|
||||
access = w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_ALWAYS
|
||||
self.can_write = True
|
||||
elif mode == MODE.A:
|
||||
access = w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.OPEN_ALWAYS
|
||||
self.can_write = True
|
||||
self.is_append = True
|
||||
elif mode == MODE.RP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
elif mode == MODE.WP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_ALWAYS
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
elif mode == MODE.AP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.OPEN_ALWAYS
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
self.is_append = True
|
||||
elif mode == MODE.X:
|
||||
access = w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_NEW
|
||||
self.can_write = True
|
||||
elif mode == MODE.XP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_NEW
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
else:
|
||||
access = w32.win32file.GENERIC_READ
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
|
||||
self.handle = w32.win32file.CreateFileA(
|
||||
filename, access, self._share_mode,
|
||||
None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None
|
||||
)
|
||||
|
||||
if self.handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
self.closed = True
|
||||
return
|
||||
|
||||
self.closed = False
|
||||
|
||||
if self.is_append:
|
||||
self.seek(0, SEEK_END)
|
||||
|
||||
def __enter__(self) -> 'File' | t.CPtr:
|
||||
return self
|
||||
|
||||
def __exit__(self):
|
||||
self.close()
|
||||
|
||||
def read(self, buf: bytes, count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_read: return FRESULT.ERR_PERM
|
||||
bytes_read: ULONG = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), None)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
return LONG(bytes_read)
|
||||
|
||||
def write(self, buf: bytes, count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_write: return FRESULT.ERR_PERM
|
||||
bytes_written: ULONG = 0
|
||||
result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), None)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
return LONG(bytes_written)
|
||||
|
||||
def write_str(self, s: str) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_write: return FRESULT.ERR_PERM
|
||||
length: ULONG = 0
|
||||
p: bytes = s
|
||||
while c.Deref(p) != 0:
|
||||
length += 1
|
||||
p += 1
|
||||
return self.write(s, length)
|
||||
|
||||
def seek(self, offset: LONG, origin: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
result: LONG = w32.win32file.SetFilePointer(self.handle, offset, None, origin)
|
||||
if result == -1: return FRESULT.ERR_IO
|
||||
return result
|
||||
|
||||
def tell(self) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
return self.seek(0, SEEK_CUR)
|
||||
|
||||
def close(self) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
w32.win32base.CloseHandle(self.handle)
|
||||
self.closed = True
|
||||
return FRESULT.OK
|
||||
|
||||
def flush(self) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
w32.win32file.FlushFileBuffers(self.handle)
|
||||
return FRESULT.OK
|
||||
|
||||
def size(self) -> LONGLONG:
|
||||
if self.closed: return -1
|
||||
li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
|
||||
result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li)))
|
||||
if result == 0: return -1
|
||||
return li.QuadPart
|
||||
|
||||
def readline(self, buf: bytes, max_count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_read: return FRESULT.ERR_PERM
|
||||
if max_count < 2: return FRESULT.ERR
|
||||
total: ULONG = 0
|
||||
bytes_read: ULONG = 0
|
||||
ch: t.CInt = 0
|
||||
while total < max_count - 1:
|
||||
bytes_read = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), None)
|
||||
if result == 0 or bytes_read == 0: break
|
||||
ch = c.Deref(buf + total)
|
||||
total += 1
|
||||
if ch == 10: break
|
||||
if total < max_count:
|
||||
buf[total] = 0
|
||||
return LONG(total)
|
||||
|
||||
def read_all(self, buf: bytes, max_count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_read: return FRESULT.ERR_PERM
|
||||
if max_count < 2: return FRESULT.ERR
|
||||
# stdio.printf("[DBG read_all] before size()\n")
|
||||
file_size: LONGLONG = self.size()
|
||||
# stdio.printf("[DBG read_all] after size(), file_size=%lld\n", file_size)
|
||||
if file_size < 0: return FRESULT.ERR_IO
|
||||
to_read: ULONG = 0
|
||||
if file_size < max_count - 1:
|
||||
to_read = ULONG(file_size)
|
||||
else:
|
||||
to_read = max_count - 1
|
||||
# stdio.printf("[DBG read_all] to_read=%u, before seek\n", to_read)
|
||||
self.seek(0, SEEK_SET)
|
||||
# stdio.printf("[DBG read_all] after seek, before ReadFile\n")
|
||||
bytes_read: ULONG = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None)
|
||||
# stdio.printf("[DBG read_all] after ReadFile, result=%d, bytes_read=%u\n", result, bytes_read)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
if bytes_read < max_count:
|
||||
buf[bytes_read] = 0
|
||||
return LONG(bytes_read)
|
||||
|
||||
|
||||
class FileW:
|
||||
handle: w32.win32base.HANDLE
|
||||
closed: bool
|
||||
can_read: bool
|
||||
can_write: bool
|
||||
is_append: bool
|
||||
_share_mode: ULONG
|
||||
|
||||
def __init__(self, filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ):
|
||||
self.closed = True
|
||||
self.can_read = False
|
||||
self.can_write = False
|
||||
self.is_append = False
|
||||
self._share_mode = share
|
||||
|
||||
access: ULONG = 0
|
||||
disposition: ULONG = w32.win32file.OPEN_EXISTING
|
||||
|
||||
if mode == MODE.R:
|
||||
access = w32.win32file.GENERIC_READ
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
elif mode == MODE.W:
|
||||
access = w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_ALWAYS
|
||||
self.can_write = True
|
||||
elif mode == MODE.A:
|
||||
access = w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.OPEN_ALWAYS
|
||||
self.can_write = True
|
||||
self.is_append = True
|
||||
elif mode == MODE.RP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
elif mode == MODE.WP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_ALWAYS
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
elif mode == MODE.AP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.OPEN_ALWAYS
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
self.is_append = True
|
||||
elif mode == MODE.X:
|
||||
access = w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_NEW
|
||||
self.can_write = True
|
||||
elif mode == MODE.XP:
|
||||
access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE
|
||||
disposition = w32.win32file.CREATE_NEW
|
||||
self.can_read = True
|
||||
self.can_write = True
|
||||
else:
|
||||
access = w32.win32file.GENERIC_READ
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
|
||||
self.handle = w32.win32file.CreateFileW(
|
||||
filename, access, self._share_mode,
|
||||
None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None
|
||||
)
|
||||
|
||||
if self.handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
self.closed = True
|
||||
return
|
||||
|
||||
self.closed = False
|
||||
|
||||
if self.is_append:
|
||||
self.seek(0, SEEK_END)
|
||||
|
||||
def __enter__(self) -> 'FileW' | t.CPtr:
|
||||
return self
|
||||
|
||||
def __exit__(self):
|
||||
self.close()
|
||||
|
||||
def read(self, buf: bytes, count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_read: return FRESULT.ERR_PERM
|
||||
bytes_read: ULONG = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), None)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
return LONG(bytes_read)
|
||||
|
||||
def write(self, buf: bytes, count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_write: return FRESULT.ERR_PERM
|
||||
bytes_written: ULONG = 0
|
||||
result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), None)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
return LONG(bytes_written)
|
||||
|
||||
def write_str(self, s: str) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_write: return FRESULT.ERR_PERM
|
||||
length: ULONG = 0
|
||||
p: bytes = s
|
||||
while c.Deref(p) != 0:
|
||||
length += 1
|
||||
p += 1
|
||||
return self.write(s, length)
|
||||
|
||||
def seek(self, offset: LONG, origin: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
result: LONG = w32.win32file.SetFilePointer(self.handle, offset, None, origin)
|
||||
if result == -1: return FRESULT.ERR_IO
|
||||
return result
|
||||
|
||||
def tell(self) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
return self.seek(0, SEEK_CUR)
|
||||
|
||||
def close(self) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
w32.win32base.CloseHandle(self.handle)
|
||||
self.closed = True
|
||||
return FRESULT.OK
|
||||
|
||||
def flush(self) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
w32.win32file.FlushFileBuffers(self.handle)
|
||||
return FRESULT.OK
|
||||
|
||||
def size(self) -> LONGLONG:
|
||||
if self.closed: return -1
|
||||
li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
|
||||
result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li)))
|
||||
if result == 0: return -1
|
||||
return li.QuadPart
|
||||
|
||||
def readline(self, buf: bytes, max_count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_read: return FRESULT.ERR_PERM
|
||||
if max_count < 2: return FRESULT.ERR
|
||||
total: ULONG = 0
|
||||
bytes_read: ULONG = 0
|
||||
ch: t.CInt = 0
|
||||
while total < max_count - 1:
|
||||
bytes_read = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), None)
|
||||
if result == 0 or bytes_read == 0: break
|
||||
ch = c.Deref(buf + total)
|
||||
total += 1
|
||||
if ch == 10: break
|
||||
if total < max_count:
|
||||
buf[total] = 0
|
||||
return LONG(total)
|
||||
|
||||
def read_all(self, buf: bytes, max_count: ULONG) -> LONG:
|
||||
if self.closed: return FRESULT.ERR_CLOSED
|
||||
if not self.can_read: return FRESULT.ERR_PERM
|
||||
if max_count < 2: return FRESULT.ERR
|
||||
file_size: LONGLONG = self.size()
|
||||
if file_size < 0: return FRESULT.ERR_IO
|
||||
to_read: ULONG = 0
|
||||
if file_size < max_count - 1:
|
||||
to_read = ULONG(file_size)
|
||||
else:
|
||||
to_read = max_count - 1
|
||||
self.seek(0, SEEK_SET)
|
||||
bytes_read: ULONG = 0
|
||||
result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None)
|
||||
if result == 0: return FRESULT.ERR_IO
|
||||
if bytes_read < max_count:
|
||||
buf[bytes_read] = 0
|
||||
return LONG(bytes_read)
|
||||
|
||||
|
||||
def open(filename: str, mode: ULONG, share: ULONG = SHARE_READ) -> File | t.CPtr:
|
||||
return File(filename, mode, share)
|
||||
|
||||
def openw(filename: LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
|
||||
return FileW(filename, mode, share)
|
||||
@@ -0,0 +1,80 @@
|
||||
import t
|
||||
from stdint import *
|
||||
|
||||
HANDLE: t.CTypedef = VOIDPTR
|
||||
LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr
|
||||
LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr
|
||||
|
||||
INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1)
|
||||
NULL: t.CDefine = 0
|
||||
TRUE: t.CDefine = 1
|
||||
FALSE: t.CDefine = 0
|
||||
INFINITE: t.CDefine = 0xFFFFFFFF
|
||||
WAIT_FAILED: t.CDefine = 0xFFFFFFFF
|
||||
WAIT_OBJECT_0: t.CDefine = 0
|
||||
WAIT_TIMEOUT: t.CDefine = 258
|
||||
WAIT_ABANDONED: t.CDefine = 0x80
|
||||
MAX_PATH: t.CDefine = 260
|
||||
ERROR_SUCCESS: t.CDefine = 0
|
||||
ERROR_FILE_NOT_FOUND: t.CDefine = 2
|
||||
ERROR_ACCESS_DENIED: t.CDefine = 5
|
||||
ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122
|
||||
|
||||
class SECURITY_ATTRIBUTES():
|
||||
nLength: ULONG
|
||||
lpSecurityDescriptor: VOIDPTR
|
||||
bInheritHandle: BOOL
|
||||
|
||||
class OVERLAPPED():
|
||||
Internal: ULONGLONG
|
||||
InternalHigh: ULONGLONG
|
||||
Offset: ULONG
|
||||
OffsetHigh: ULONG
|
||||
hEvent: HANDLE
|
||||
|
||||
class FILETIME():
|
||||
dwLowDateTime: DWORD
|
||||
dwHighDateTime: DWORD
|
||||
|
||||
class SYSTEMTIME():
|
||||
wYear: WORD
|
||||
wMonth: WORD
|
||||
wDayOfWeek: WORD
|
||||
wDay: WORD
|
||||
wHour: WORD
|
||||
wMinute: WORD
|
||||
wSecond: WORD
|
||||
wMilliseconds: WORD
|
||||
|
||||
class GUID():
|
||||
Data1: DWORD
|
||||
Data2: WORD
|
||||
Data3: WORD
|
||||
Data4: BYTEPTR
|
||||
|
||||
class LARGE_INTEGER():
|
||||
QuadPart: LONGLONG
|
||||
|
||||
class ULARGE_INTEGER():
|
||||
QuadPart: ULONGLONG
|
||||
|
||||
def GetLastError() -> ULONG | t.State: pass
|
||||
def SetLastError(dwErrCode: ULONG) -> t.State: pass
|
||||
def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass
|
||||
def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass
|
||||
def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass
|
||||
def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass
|
||||
def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass
|
||||
def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass
|
||||
def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass
|
||||
def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass
|
||||
def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass
|
||||
def Sleep(dwMilliseconds: ULONG) -> t.State: pass
|
||||
def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass
|
||||
def GetTickCount() -> ULONG | t.State: pass
|
||||
def GetTickCount64() -> ULONGLONG | t.State: pass
|
||||
def GetCommandLineA() -> CHARPTR | t.State: pass
|
||||
@@ -0,0 +1,111 @@
|
||||
import t
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
|
||||
ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001
|
||||
ENABLE_LINE_INPUT: t.CDefine = 0x0002
|
||||
ENABLE_ECHO_INPUT: t.CDefine = 0x0004
|
||||
ENABLE_WINDOW_INPUT: t.CDefine = 0x0008
|
||||
ENABLE_MOUSE_INPUT: t.CDefine = 0x0010
|
||||
ENABLE_INSERT_MODE: t.CDefine = 0x0020
|
||||
ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040
|
||||
ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080
|
||||
|
||||
ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004
|
||||
DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008
|
||||
ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010
|
||||
|
||||
FOREGROUND_BLUE: t.CDefine = 0x0001
|
||||
FOREGROUND_GREEN: t.CDefine = 0x0002
|
||||
FOREGROUND_RED: t.CDefine = 0x0004
|
||||
FOREGROUND_INTENSITY: t.CDefine = 0x0008
|
||||
BACKGROUND_BLUE: t.CDefine = 0x0010
|
||||
BACKGROUND_GREEN: t.CDefine = 0x0020
|
||||
BACKGROUND_RED: t.CDefine = 0x0040
|
||||
BACKGROUND_INTENSITY: t.CDefine = 0x0080
|
||||
|
||||
KEY_EVENT: t.CDefine = 0x0001
|
||||
MOUSE_EVENT: t.CDefine = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004
|
||||
MENU_EVENT: t.CDefine = 0x0008
|
||||
FOCUS_EVENT: t.CDefine = 0x0010
|
||||
|
||||
class COORD():
|
||||
X: SHORT
|
||||
Y: SHORT
|
||||
|
||||
class SMALL_RECT():
|
||||
Left: SHORT
|
||||
Top: SHORT
|
||||
Right: SHORT
|
||||
Bottom: SHORT
|
||||
|
||||
class CONSOLE_SCREEN_BUFFER_INFO():
|
||||
dwSize: COORD
|
||||
dwCursorPosition: COORD
|
||||
wAttributes: WORD
|
||||
srWindow: SMALL_RECT
|
||||
dwMaximumWindowSize: COORD
|
||||
|
||||
class CONSOLE_CURSOR_INFO():
|
||||
dwSize: ULONG
|
||||
bVisible: BOOL
|
||||
|
||||
class CHAR_INFO():
|
||||
UnicodeChar: WCHAR
|
||||
Attributes: WORD
|
||||
|
||||
class KEY_EVENT_RECORD():
|
||||
bKeyDown: BOOL
|
||||
wRepeatCount: WORD
|
||||
wVirtualKeyCode: WORD
|
||||
wVirtualScanCode: WORD
|
||||
uChar: WCHAR
|
||||
dwControlKeyState: ULONG
|
||||
|
||||
class MOUSE_EVENT_RECORD():
|
||||
dwMousePosition: COORD
|
||||
dwButtonState: ULONG
|
||||
dwControlKeyState: ULONG
|
||||
dwEventFlags: ULONG
|
||||
|
||||
class WINDOW_BUFFER_SIZE_RECORD():
|
||||
dwSize: COORD
|
||||
|
||||
class INPUT_RECORD():
|
||||
EventType: WORD
|
||||
Event: KEY_EVENT_RECORD
|
||||
|
||||
def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass
|
||||
def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass
|
||||
def GetConsoleCP() -> UINT | t.State: pass
|
||||
def GetConsoleOutputCP() -> UINT | t.State: pass
|
||||
def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass
|
||||
def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass
|
||||
def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass
|
||||
def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass
|
||||
def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass
|
||||
def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass
|
||||
def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass
|
||||
def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass
|
||||
def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass
|
||||
def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass
|
||||
def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass
|
||||
def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass
|
||||
def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass
|
||||
def AllocConsole() -> BOOL | t.State: pass
|
||||
def FreeConsole() -> BOOL | t.State: pass
|
||||
def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass
|
||||
def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass
|
||||
@@ -0,0 +1,143 @@
|
||||
import t
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
|
||||
GENERIC_READ: t.CDefine = 0x80000000
|
||||
GENERIC_WRITE: t.CDefine = 0x40000000
|
||||
GENERIC_EXECUTE: t.CDefine = 0x20000000
|
||||
GENERIC_ALL: t.CDefine = 0x10000000
|
||||
|
||||
FILE_SHARE_READ: t.CDefine = 0x00000001
|
||||
FILE_SHARE_WRITE: t.CDefine = 0x00000002
|
||||
FILE_SHARE_DELETE: t.CDefine = 0x00000004
|
||||
|
||||
CREATE_NEW: t.CDefine = 1
|
||||
CREATE_ALWAYS: t.CDefine = 2
|
||||
OPEN_EXISTING: t.CDefine = 3
|
||||
OPEN_ALWAYS: t.CDefine = 4
|
||||
TRUNCATE_EXISTING: t.CDefine = 5
|
||||
|
||||
FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001
|
||||
FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002
|
||||
FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004
|
||||
FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010
|
||||
FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020
|
||||
FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080
|
||||
FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100
|
||||
FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800
|
||||
FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000
|
||||
FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000
|
||||
|
||||
FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000
|
||||
FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000
|
||||
FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000
|
||||
FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000
|
||||
FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000
|
||||
FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000
|
||||
FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000
|
||||
FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000
|
||||
|
||||
FILE_BEGIN: t.CDefine = 0
|
||||
FILE_CURRENT: t.CDefine = 1
|
||||
FILE_END: t.CDefine = 2
|
||||
|
||||
STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10)
|
||||
STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11)
|
||||
STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12)
|
||||
|
||||
MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001
|
||||
MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002
|
||||
MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008
|
||||
|
||||
class BY_HANDLE_FILE_INFORMATION():
|
||||
dwFileAttributes: ULONG
|
||||
ftCreationTime: FILETIME
|
||||
ftLastAccessTime: FILETIME
|
||||
ftLastWriteTime: FILETIME
|
||||
dwVolumeSerialNumber: ULONG
|
||||
nFileSizeHigh: ULONG
|
||||
nFileSizeLow: ULONG
|
||||
nNumberOfLinks: ULONG
|
||||
nFileIndexHigh: ULONG
|
||||
nFileIndexLow: ULONG
|
||||
|
||||
class WIN32_FIND_DATAA():
|
||||
dwFileAttributes: ULONG
|
||||
ftCreationTime: FILETIME
|
||||
ftLastAccessTime: FILETIME
|
||||
ftLastWriteTime: FILETIME
|
||||
nFileSizeHigh: ULONG
|
||||
nFileSizeLow: ULONG
|
||||
dwReserved0: ULONG
|
||||
dwReserved1: ULONG
|
||||
cFileName: t.CArray[t.CChar, 260]
|
||||
cAlternateFileName: t.CArray[t.CChar, 14]
|
||||
|
||||
class WIN32_FIND_DATAW():
|
||||
dwFileAttributes: ULONG
|
||||
ftCreationTime: FILETIME
|
||||
ftLastAccessTime: FILETIME
|
||||
ftLastWriteTime: FILETIME
|
||||
nFileSizeHigh: ULONG
|
||||
nFileSizeLow: ULONG
|
||||
dwReserved0: ULONG
|
||||
dwReserved1: ULONG
|
||||
cFileName: t.CArray[t.CUInt16T, 260]
|
||||
cAlternateFileName: t.CArray[t.CUInt16T, 14]
|
||||
|
||||
def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass
|
||||
def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass
|
||||
def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass
|
||||
def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass
|
||||
def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass
|
||||
def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass
|
||||
def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass
|
||||
def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass
|
||||
def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass
|
||||
def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass
|
||||
def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass
|
||||
def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass
|
||||
def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass
|
||||
def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass
|
||||
def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass
|
||||
def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass
|
||||
def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass
|
||||
def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass
|
||||
def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass
|
||||
def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass
|
||||
def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass
|
||||
def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass
|
||||
def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass
|
||||
def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass
|
||||
def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass
|
||||
def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass
|
||||
def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass
|
||||
def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass
|
||||
def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass
|
||||
def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass
|
||||
def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass
|
||||
def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass
|
||||
def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass
|
||||
def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass
|
||||
def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass
|
||||
def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass
|
||||
def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass
|
||||
def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass
|
||||
def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass
|
||||
def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass
|
||||
def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass
|
||||
def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass
|
||||
def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass
|
||||
def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass
|
||||
def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass
|
||||
|
||||
HANDLE_FLAG_INHERIT: t.CDefine = 0x00000001
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE: t.CDefine = 0x00000002
|
||||
|
||||
def CreatePipe(hReadPipe: HANDLE | t.CPtr, hWritePipe: HANDLE | t.CPtr, lpPipeAttributes: SECURITY_ATTRIBUTES | t.CPtr, nSize: ULONG) -> BOOL | t.State: pass
|
||||
def SetHandleInformation(hObject: HANDLE, dwMask: ULONG, dwFlags: ULONG) -> BOOL | t.State: pass
|
||||
def DuplicateHandle(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, hTargetProcessHandle: HANDLE, lpTargetHandle: HANDLE | t.CPtr, dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwOptions: ULONG) -> BOOL | t.State: pass
|
||||
|
||||
DUPLICATE_SAME_ACCESS: t.CDefine = 0x00000002
|
||||
@@ -0,0 +1,64 @@
|
||||
import t
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
|
||||
MEM_COMMIT: t.CDefine = 0x00001000
|
||||
MEM_RESERVE: t.CDefine = 0x00002000
|
||||
MEM_DECOMMIT: t.CDefine = 0x00004000
|
||||
MEM_RELEASE: t.CDefine = 0x00008000
|
||||
MEM_FREE: t.CDefine = 0x00010000
|
||||
MEM_RESET: t.CDefine = 0x00080000
|
||||
MEM_TOP_DOWN: t.CDefine = 0x00100000
|
||||
MEM_WRITE_WATCH: t.CDefine = 0x00200000
|
||||
MEM_PHYSICAL: t.CDefine = 0x00400000
|
||||
MEM_LARGE_PAGES: t.CDefine = 0x20000000
|
||||
|
||||
PAGE_NOACCESS: t.CDefine = 0x01
|
||||
PAGE_READONLY: t.CDefine = 0x02
|
||||
PAGE_READWRITE: t.CDefine = 0x04
|
||||
PAGE_WRITECOPY: t.CDefine = 0x08
|
||||
PAGE_EXECUTE: t.CDefine = 0x10
|
||||
PAGE_EXECUTE_READ: t.CDefine = 0x20
|
||||
PAGE_EXECUTE_READWRITE: t.CDefine = 0x40
|
||||
PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80
|
||||
PAGE_GUARD: t.CDefine = 0x100
|
||||
PAGE_NOCACHE: t.CDefine = 0x200
|
||||
PAGE_WRITECOMBINE: t.CDefine = 0x400
|
||||
|
||||
HEAP_NO_SERIALIZE: t.CDefine = 0x00000001
|
||||
HEAP_GROWABLE: t.CDefine = 0x00000002
|
||||
HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004
|
||||
HEAP_ZERO_MEMORY: t.CDefine = 0x00000008
|
||||
HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010
|
||||
|
||||
class MEMORY_BASIC_INFORMATION():
|
||||
BaseAddress: VOIDPTR
|
||||
AllocationBase: VOIDPTR
|
||||
AllocationProtect: ULONG
|
||||
RegionSize: t.CSizeT
|
||||
State: ULONG
|
||||
Protect: ULONG
|
||||
Type: ULONG
|
||||
|
||||
def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass
|
||||
def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass
|
||||
def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass
|
||||
def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass
|
||||
def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass
|
||||
def GetProcessHeap() -> HANDLE | t.State: pass
|
||||
def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass
|
||||
def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass
|
||||
def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass
|
||||
def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass
|
||||
def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass
|
||||
def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass
|
||||
def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass
|
||||
def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass
|
||||
def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass
|
||||
def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass
|
||||
def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass
|
||||
def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass
|
||||
def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass
|
||||
def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass
|
||||
def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass
|
||||
@@ -0,0 +1,112 @@
|
||||
import t
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
|
||||
PROCESS_TERMINATE: t.CDefine = 0x0001
|
||||
PROCESS_CREATE_THREAD: t.CDefine = 0x0002
|
||||
PROCESS_VM_OPERATION: t.CDefine = 0x0008
|
||||
PROCESS_VM_READ: t.CDefine = 0x0010
|
||||
PROCESS_VM_WRITE: t.CDefine = 0x0020
|
||||
PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400
|
||||
PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF
|
||||
|
||||
THREAD_TERMINATE: t.CDefine = 0x0001
|
||||
THREAD_SUSPEND_RESUME: t.CDefine = 0x0002
|
||||
THREAD_GET_CONTEXT: t.CDefine = 0x0008
|
||||
THREAD_SET_CONTEXT: t.CDefine = 0x0010
|
||||
THREAD_QUERY_INFORMATION: t.CDefine = 0x0040
|
||||
THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF
|
||||
|
||||
CREATE_SUSPENDED: t.CDefine = 0x00000004
|
||||
CREATE_NEW_CONSOLE: t.CDefine = 0x00000010
|
||||
CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200
|
||||
CREATE_NO_WINDOW: t.CDefine = 0x08000000
|
||||
DETACHED_PROCESS: t.CDefine = 0x00000008
|
||||
|
||||
STARTF_USESHOWWINDOW: t.CDefine = 0x00000001
|
||||
STARTF_USESTDHANDLES: t.CDefine = 0x00000100
|
||||
|
||||
SW_HIDE: t.CDefine = 0
|
||||
SW_SHOW: t.CDefine = 5
|
||||
SW_MINIMIZE: t.CDefine = 6
|
||||
|
||||
NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020
|
||||
IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040
|
||||
HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080
|
||||
REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100
|
||||
BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000
|
||||
ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000
|
||||
|
||||
STILL_ACTIVE: t.CDefine = 259
|
||||
|
||||
class STARTUPINFOA():
|
||||
cb: ULONG
|
||||
lpReserved: CHARPTR
|
||||
lpDesktop: CHARPTR
|
||||
lpTitle: CHARPTR
|
||||
dwX: ULONG
|
||||
dwY: ULONG
|
||||
dwXSize: ULONG
|
||||
dwYSize: ULONG
|
||||
dwXCountChars: ULONG
|
||||
dwYCountChars: ULONG
|
||||
dwFillAttribute: ULONG
|
||||
dwFlags: ULONG
|
||||
wShowWindow: WORD
|
||||
cbReserved2: WORD
|
||||
lpReserved2: VOIDPTR
|
||||
hStdInput: HANDLE
|
||||
hStdOutput: HANDLE
|
||||
hStdError: HANDLE
|
||||
|
||||
class STARTUPINFOW():
|
||||
cb: ULONG
|
||||
lpReserved: WCHARPTR
|
||||
lpDesktop: WCHARPTR
|
||||
lpTitle: WCHARPTR
|
||||
dwX: ULONG
|
||||
dwY: ULONG
|
||||
dwXSize: ULONG
|
||||
dwYSize: ULONG
|
||||
dwXCountChars: ULONG
|
||||
dwYCountChars: ULONG
|
||||
dwFillAttribute: ULONG
|
||||
dwFlags: ULONG
|
||||
wShowWindow: WORD
|
||||
cbReserved2: WORD
|
||||
lpReserved2: VOIDPTR
|
||||
hStdInput: HANDLE
|
||||
hStdOutput: HANDLE
|
||||
hStdError: HANDLE
|
||||
|
||||
class PROCESS_INFORMATION():
|
||||
hProcess: HANDLE
|
||||
hThread: HANDLE
|
||||
dwProcessId: ULONG
|
||||
dwThreadId: ULONG
|
||||
|
||||
def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass
|
||||
def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass
|
||||
def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass
|
||||
def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass
|
||||
def GetCurrentProcess() -> HANDLE | t.State: pass
|
||||
def GetCurrentProcessId() -> ULONG | t.State: pass
|
||||
def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass
|
||||
def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass
|
||||
def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass
|
||||
def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass
|
||||
def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass
|
||||
def GetCurrentThread() -> HANDLE | t.State: pass
|
||||
def GetCurrentThreadId() -> ULONG | t.State: pass
|
||||
def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass
|
||||
def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass
|
||||
def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass
|
||||
def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass
|
||||
def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass
|
||||
def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass
|
||||
def TlsAlloc() -> ULONG | t.State: pass
|
||||
def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass
|
||||
def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass
|
||||
def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass
|
||||
@@ -0,0 +1,65 @@
|
||||
import t
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
|
||||
class CRITICAL_SECTION():
|
||||
DebugInfo: VOIDPTR
|
||||
LockCount: LONG
|
||||
RecursionCount: LONG
|
||||
OwningThread: HANDLE
|
||||
LockSemaphore: HANDLE
|
||||
SpinCount: QWORD
|
||||
|
||||
def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass
|
||||
def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass
|
||||
def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass
|
||||
def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass
|
||||
def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass
|
||||
def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass
|
||||
def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass
|
||||
def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass
|
||||
def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass
|
||||
def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass
|
||||
def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass
|
||||
def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass
|
||||
def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass
|
||||
def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass
|
||||
def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass
|
||||
def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass
|
||||
def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass
|
||||
def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass
|
||||
def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass
|
||||
def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass
|
||||
def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass
|
||||
def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass
|
||||
def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass
|
||||
|
||||
# 条件变量 (Condition Variables) - Vista+
|
||||
CONDITION_VARIABLE_LOCKMODE_SHARED: t.CDefine = 0x1
|
||||
|
||||
def InitializeConditionVariable(ConditionVariable: VOIDPTR) -> VOID | t.State: pass
|
||||
def SleepConditionVariableCS(ConditionVariable: VOIDPTR, CriticalSection: CRITICAL_SECTION | t.CPtr, dwMilliseconds: ULONG) -> BOOL | t.State: pass
|
||||
def SleepConditionVariableSRW(ConditionVariable: VOIDPTR, SRWLock: VOIDPTR, dwMilliseconds: ULONG, Flags: ULONG) -> BOOL | t.State: pass
|
||||
def WakeConditionVariable(ConditionVariable: VOIDPTR) -> VOID | t.State: pass
|
||||
def WakeAllConditionVariable(ConditionVariable: VOIDPTR) -> VOID | t.State: pass
|
||||
|
||||
# 一次性初始化 (One-Time Initialization) - Vista+
|
||||
INIT_ONCE_STATIC_INIT: t.CDefine = 0x00000001
|
||||
INIT_ONCE_CHECK_ONLY: t.CDefine = 0x00000002
|
||||
INIT_ONCE_ASYNC: t.CDefine = 0x00000004
|
||||
INIT_ONCE_INIT_FAILED: t.CDefine = 0x00000008
|
||||
|
||||
class INIT_ONCE:
|
||||
Ptr: t.CPtr
|
||||
|
||||
def InitOnceExecuteOnce(InitOnce: INIT_ONCE | t.CPtr, InitFn: VOIDPTR, Parameter: VOIDPTR, Context: VOIDPTR | t.CPtr) -> BOOL | t.State: pass
|
||||
@@ -0,0 +1,104 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
|
||||
|
||||
# ============================================================
|
||||
# w32/winsock2.py — WinSock2 API 声明 (ws2_32.dll)
|
||||
# ============================================================
|
||||
|
||||
# 版本常量
|
||||
WINSOCK_VERSION: t.CDefine = 0x0202 # 2.2
|
||||
|
||||
# 地址族
|
||||
AF_INET: t.CDefine = 2
|
||||
AF_INET6: t.CDefine = 23
|
||||
|
||||
# 套接字类型
|
||||
SOCK_STREAM: t.CDefine = 1 # TCP
|
||||
SOCK_DGRAM: t.CDefine = 2 # UDP
|
||||
SOCK_RAW: t.CDefine = 3 # 原始套接字
|
||||
|
||||
# 协议
|
||||
IPPROTO_TCP: t.CDefine = 6
|
||||
IPPROTO_UDP: t.CDefine = 17
|
||||
|
||||
# 选项级别
|
||||
SOL_SOCKET: t.CDefine = 0xFFFF # WinSock2 值
|
||||
SO_RCVTIMEO: t.CDefine = 0x1006 # WinSock2 值
|
||||
SO_SNDTIMEO: t.CDefine = 0x1005 # WinSock2 值
|
||||
SO_REUSEADDR: t.CDefine = 0x0004 # WinSock2 值
|
||||
|
||||
# 特殊值
|
||||
INADDR_ANY: t.CDefine = 0
|
||||
SOCKET_ERROR: t.CDefine = -1
|
||||
INVALID_SOCKET: t.CDefine = 0xFFFFFFFF # WinSock2: ~0
|
||||
|
||||
# 发送/接收标志
|
||||
MSG_NOSIGNAL: t.CDefine = 0 # Windows 不支持,设为 0
|
||||
|
||||
# 关闭方式
|
||||
SD_SEND: t.CDefine = 1
|
||||
SD_RECV: t.CDefine = 0
|
||||
SD_BOTH: t.CDefine = 2
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 结构体
|
||||
# ============================================================
|
||||
# struct sockaddr_in — 16 字节
|
||||
class WSASocketAddr:
|
||||
family: u16 # sin_family
|
||||
port: u16 # sin_port
|
||||
addr: u32 # sin_addr.s_addr
|
||||
zero: u64 # sin_zero
|
||||
|
||||
|
||||
# struct WSADATA — 400 字节
|
||||
class WSAData:
|
||||
wVersion: WORD # @ 0
|
||||
wHighVersion: WORD # @ 2
|
||||
szDescription: BYTE # @ 4 (257 bytes + padding)
|
||||
szSystemStatus: BYTE # @ 261 (129 bytes + padding)
|
||||
iMaxSockets: u16 # @ 390
|
||||
iMaxUdpDg: u16 # @ 392
|
||||
lpVendorInfo: CHARPTR # @ 394 (实际上指针是 8 字节对齐)
|
||||
|
||||
|
||||
# struct hostent — 自然对齐: h_name(8) + h_aliases(8) + h_addrtype(2) + h_length(2) + auto-pad(4) + h_addr_list(8) = 32
|
||||
class WSAHostEnt:
|
||||
h_name: CHARPTR
|
||||
h_aliases: CHARPTR
|
||||
h_addrtype: SHORT
|
||||
h_length: SHORT
|
||||
h_addr_list: CHARPTR
|
||||
|
||||
|
||||
# struct timeval
|
||||
class WinTimeVal:
|
||||
tv_sec: LONG # 秒
|
||||
tv_usec: LONG # 微秒
|
||||
|
||||
|
||||
# ============================================================
|
||||
# WinSock2 API 函数
|
||||
# ============================================================
|
||||
|
||||
def WSAStartup(wVersionRequested: WORD, lpWSAData: WSAData | t.CPtr) -> INT | t.State: pass
|
||||
def WSACleanup() -> INT | t.State: pass
|
||||
def WSAGetLastError() -> INT | t.State: pass
|
||||
|
||||
def socket(family: INT, type: INT, protocol: INT) -> u64 | t.State: pass
|
||||
def closesocket(s: u64) -> INT | t.State: pass
|
||||
def connect(s: u64, name: WSASocketAddr | t.CPtr, namelen: INT) -> INT | t.State: pass
|
||||
def send(s: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.State: pass
|
||||
def recv(s: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.State: pass
|
||||
def bind(s: u64, name: WSASocketAddr | t.CPtr, namelen: INT) -> INT | t.State: pass
|
||||
def listen(s: u64, backlog: INT) -> INT | t.State: pass
|
||||
def accept(s: u64, addr: WSASocketAddr | t.CPtr, addrlen: INT | t.CPtr) -> u64 | t.State: pass
|
||||
def setsockopt(s: u64, level: INT, optname: INT, optval: t.CVoid | t.CPtr, optlen: INT) -> INT | t.State: pass
|
||||
def shutdown(s: u64, how: INT) -> INT | t.State: pass
|
||||
def gethostbyname(name: t.CChar | t.CConst | t.CPtr) -> WSAHostEnt | t.CPtr | t.State: pass
|
||||
def ntohs(netshort: u16) -> u16 | t.State: pass
|
||||
def htons(hostshort: u16) -> u16 | t.State: pass
|
||||
def inet_addr(cp: t.CChar | t.CConst | t.CPtr) -> u32 | t.State: pass
|
||||
@@ -0,0 +1 @@
|
||||
from .pyzlib import *
|
||||
@@ -0,0 +1,695 @@
|
||||
from stdint import *
|
||||
import zlib.zdeflate as zdeflate
|
||||
import zlib.zinflate as zinflate
|
||||
import zlib.zchecksum as zchecksum
|
||||
import zlib.zdef as zdef
|
||||
import zlib.zhuff as zhuff
|
||||
import stdlib
|
||||
import string
|
||||
import memhub
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Constants - matching Python zlib module names and values
|
||||
# ============================================================
|
||||
|
||||
# Compression levels
|
||||
Z_NO_COMPRESSION: t.CDefine = 0
|
||||
Z_BEST_SPEED: t.CDefine = 1
|
||||
Z_BEST_COMPRESSION: t.CDefine = 9
|
||||
Z_DEFAULT_COMPRESSION: t.CDefine = (-1)
|
||||
|
||||
# Compression methods
|
||||
DEFLATED: t.CDefine = 8
|
||||
|
||||
# Flush modes
|
||||
Z_NO_FLUSH: t.CDefine = 0
|
||||
Z_PARTIAL_FLUSH: t.CDefine = 1
|
||||
Z_SYNC_FLUSH: t.CDefine = 2
|
||||
Z_FULL_FLUSH: t.CDefine = 3
|
||||
Z_FINISH: t.CDefine = 4
|
||||
Z_BLOCK: t.CDefine = 5
|
||||
Z_TREES: t.CDefine = 6
|
||||
|
||||
# Strategies
|
||||
Z_DEFAULT_STRATEGY: t.CDefine = 0
|
||||
Z_FILTERED: t.CDefine = 1
|
||||
Z_HUFFMAN_ONLY: t.CDefine = 2
|
||||
Z_RLE: t.CDefine = 3
|
||||
Z_FIXED: t.CDefine = 4
|
||||
|
||||
# Return codes
|
||||
Z_OK: t.CDefine = 0
|
||||
Z_STREAM_END: t.CDefine = 1
|
||||
Z_NEED_DICT: t.CDefine = 2
|
||||
Z_ERRNO: t.CDefine = (-1)
|
||||
Z_STREAM_ERROR: t.CDefine = (-2)
|
||||
Z_DATA_ERROR: t.CDefine = (-3)
|
||||
Z_MEM_ERROR: t.CDefine = (-4)
|
||||
Z_BUF_ERROR: t.CDefine = (-5)
|
||||
Z_VERSION_ERROR: t.CDefine = (-6)
|
||||
|
||||
# Window / Buffer constants
|
||||
MAX_WBITS: t.CDefine = 15
|
||||
DEF_BUF_SIZE: t.CDefine = 16384
|
||||
DEF_MEM_LEVEL: t.CDefine = 8
|
||||
|
||||
# Version
|
||||
ZLIB_VERSION: t.CDefine = "1.3.2"
|
||||
|
||||
pyzlib_error_msg: t.CArray[t.CChar, 512] = ""
|
||||
pyzlib_error_code_val: t.CInt = 0
|
||||
|
||||
# ============================================================
|
||||
# Structures
|
||||
# ============================================================
|
||||
@t.Object
|
||||
class Compress:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
stream: VOIDPTR
|
||||
is_initialized: t.CInt
|
||||
is_finished: t.CInt
|
||||
level: t.CInt
|
||||
method: t.CInt
|
||||
wbits: t.CInt
|
||||
memLevel: t.CInt
|
||||
strategy: t.CInt
|
||||
zdict: BYTEPTR
|
||||
zdict_len: t.CSizeT
|
||||
last_pos: t.CSizeT
|
||||
input_buf: BYTEPTR
|
||||
input_buf_len: t.CSizeT
|
||||
input_buf_cap: t.CSizeT
|
||||
header_written: t.CInt
|
||||
|
||||
def compress(self,
|
||||
data: BYTEPTR, data_len: t.CSizeT,
|
||||
out_len: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
if not self.is_initialized:
|
||||
set_error(Z_STREAM_ERROR, "compress object not initialized")
|
||||
return None
|
||||
if self.is_finished:
|
||||
set_error(Z_STREAM_ERROR, "compress object already finished")
|
||||
return None
|
||||
if not out_len:
|
||||
set_error(Z_STREAM_ERROR, "out_len is None")
|
||||
return None
|
||||
if data_len == 0:
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p, 0, 1)
|
||||
return p
|
||||
while self.input_buf_len + data_len > self.input_buf_cap:
|
||||
self.input_buf_cap *= 2
|
||||
if self.pool == None:
|
||||
new_buf: BYTEPTR = BYTEPTR(realloc(self.input_buf, self.input_buf_cap))
|
||||
else:
|
||||
new_buf: BYTEPTR = BYTEPTR(self.pool.alloc(self.input_buf_cap))
|
||||
if new_buf:
|
||||
memcpy(new_buf, self.input_buf, self.input_buf_len)
|
||||
self.pool.free(self.input_buf)
|
||||
if not new_buf:
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p2: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p2, 0, 1)
|
||||
return p2
|
||||
self.input_buf = new_buf
|
||||
memcpy(self.input_buf + self.input_buf_len, data, data_len)
|
||||
self.input_buf_len += data_len
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p3: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p3, 0, 1)
|
||||
return p3
|
||||
|
||||
def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
if not self.is_initialized:
|
||||
set_error(Z_STREAM_ERROR, "compress object not initialized")
|
||||
return None
|
||||
if not out_len:
|
||||
set_error(Z_STREAM_ERROR, "out_len is None")
|
||||
return None
|
||||
s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换
|
||||
if mode == Z_FINISH:
|
||||
if not self.header_written:
|
||||
self.header_written = 1
|
||||
input_data: BYTEPTR = self.input_buf
|
||||
input_len: t.CSizeT = self.input_buf_len
|
||||
if input_len == 0:
|
||||
s.writer.write_bits(1, 1)
|
||||
s.writer.write_bits(1, 2)
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
lit_tree.build_fixed_lit_tree()
|
||||
lit_tree.encode_symbol(256, c.Addr(s.writer))
|
||||
else:
|
||||
s.adler = zchecksum.zchecksum_adler32(input_data, input_len, 1)
|
||||
s.compress_block(input_data, input_len, 1)
|
||||
s.is_finished = 1
|
||||
if s.wbits >= 0:
|
||||
s.writer.align()
|
||||
adler: t.CUInt32T = s.adler
|
||||
s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF
|
||||
s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF
|
||||
s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF
|
||||
s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF
|
||||
s.writer.byte_pos += 4
|
||||
self.is_finished = 1
|
||||
total: t.CSizeT = s.writer.total()
|
||||
if self.pool == None:
|
||||
result: BYTEPTR = BYTEPTR(malloc(total))
|
||||
else:
|
||||
result: BYTEPTR = BYTEPTR(self.pool.alloc(total))
|
||||
if result: memcpy(result, s.writer.buf, total)
|
||||
c.Set(c.Deref(out_len), total)
|
||||
if self.pool == None:
|
||||
free(self.input_buf)
|
||||
else:
|
||||
self.pool.free(self.input_buf)
|
||||
self.input_buf = None
|
||||
self.input_buf_len = 0
|
||||
self.input_buf_cap = 0
|
||||
return result
|
||||
elif mode == Z_SYNC_FLUSH or mode == Z_FULL_FLUSH:
|
||||
input_data: BYTEPTR = self.input_buf
|
||||
input_len: t.CSizeT = self.input_buf_len
|
||||
if input_len > 0:
|
||||
s.adler = zchecksum.zchecksum_adler32(input_data, input_len, s.adler)
|
||||
s.compress_block(input_data, input_len, 0)
|
||||
self.input_buf_len = 0
|
||||
s.writer.write_bits(0, 1)
|
||||
s.writer.write_bits(0, 2)
|
||||
s.writer.align()
|
||||
prev_pos: t.CSizeT = self.last_pos
|
||||
total: t.CSizeT = s.writer.total()
|
||||
delta: t.CSizeT = total - prev_pos
|
||||
self.last_pos = s.writer.byte_pos
|
||||
if delta == 0:
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p4: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p4, 0, 1)
|
||||
return p4
|
||||
|
||||
if self.pool == None:
|
||||
result: BYTEPTR = BYTEPTR(malloc(delta))
|
||||
else:
|
||||
result: BYTEPTR = BYTEPTR(self.pool.alloc(delta))
|
||||
if result: memcpy(result, s.writer.buf + prev_pos, delta)
|
||||
c.Set(c.Deref(out_len), delta)
|
||||
return result
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p5: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p5, 0, 1)
|
||||
return p5
|
||||
|
||||
def copy(self) -> Compress | t.CPtr:
|
||||
if not self.is_initialized:
|
||||
set_error(Z_STREAM_ERROR, "compress object not initialized")
|
||||
return None
|
||||
if self.pool == None:
|
||||
copy_obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__())
|
||||
else:
|
||||
copy_obj: Compress | t.CPtr = self.pool.alloc(Compress.__sizeof__())
|
||||
memset(copy_obj, 0, Compress.__sizeof__())
|
||||
if not copy_obj:
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
copy_obj.pool = self.pool
|
||||
s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换
|
||||
copy_obj.stream = s.copy()
|
||||
if not copy_obj.stream:
|
||||
if self.pool == None:
|
||||
free(copy_obj)
|
||||
else:
|
||||
self.pool.free(copy_obj)
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
copy_obj.is_initialized = 1
|
||||
copy_obj.is_finished = self.is_finished
|
||||
copy_obj.level = self.level
|
||||
copy_obj.method = self.method
|
||||
copy_obj.wbits = self.wbits
|
||||
copy_obj.memLevel = self.memLevel
|
||||
copy_obj.strategy = self.strategy
|
||||
copy_obj.last_pos = self.last_pos
|
||||
copy_obj.header_written = self.header_written
|
||||
if self.input_buf and self.input_buf_len > 0:
|
||||
if self.pool == None:
|
||||
copy_obj.input_buf = BYTEPTR(calloc(1, self.input_buf_cap))
|
||||
else:
|
||||
copy_obj.input_buf = BYTEPTR(self.pool.alloc(self.input_buf_cap))
|
||||
memset(copy_obj.input_buf, 0, self.input_buf_cap)
|
||||
if copy_obj.input_buf:
|
||||
memcpy(copy_obj.input_buf, self.input_buf, self.input_buf_len)
|
||||
copy_obj.input_buf_cap = self.input_buf_cap
|
||||
copy_obj.input_buf_len = self.input_buf_len
|
||||
else:
|
||||
if self.pool == None:
|
||||
copy_obj.input_buf = BYTEPTR(calloc(1, 256))
|
||||
else:
|
||||
copy_obj.input_buf = BYTEPTR(self.pool.alloc(256))
|
||||
memset(copy_obj.input_buf, 0, 256)
|
||||
copy_obj.input_buf_cap = 256
|
||||
copy_obj.input_buf_len = 0
|
||||
if self.zdict and self.zdict_len > 0:
|
||||
copy_obj.zdict = clone_bytes(self.pool, self.zdict, self.zdict_len)
|
||||
copy_obj.zdict_len = self.zdict_len
|
||||
return copy_obj
|
||||
|
||||
def delete(self):
|
||||
if self.is_initialized and self.stream:
|
||||
s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换
|
||||
s.destroy()
|
||||
if self.pool == None:
|
||||
free(self.zdict)
|
||||
free(self.input_buf)
|
||||
free(self)
|
||||
else:
|
||||
self.pool.free(self.zdict)
|
||||
self.pool.free(self.input_buf)
|
||||
self.pool.free(self)
|
||||
|
||||
def __del__(self):
|
||||
self.delete()
|
||||
|
||||
|
||||
@t.Object
|
||||
class Decompress:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
stream: VOIDPTR
|
||||
is_initialized: t.CInt
|
||||
eof: t.CInt
|
||||
wbits: t.CInt
|
||||
zdict: BYTEPTR
|
||||
zdict_len: t.CSizeT
|
||||
_unused_data: BYTEPTR
|
||||
_unused_data_len: t.CSizeT
|
||||
_unused_data_cap: t.CSizeT
|
||||
_unconsumed_tail: BYTEPTR
|
||||
_unconsumed_tail_len: t.CSizeT
|
||||
_unconsumed_tail_cap: t.CSizeT
|
||||
input_buf: BYTEPTR
|
||||
input_buf_len: t.CSizeT
|
||||
input_buf_cap: t.CSizeT
|
||||
|
||||
def decompress(self, data: BYTEPTR, data_len: t.CSizeT,
|
||||
max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
if not self.is_initialized:
|
||||
set_error(Z_STREAM_ERROR, "decompress object not initialized")
|
||||
return None
|
||||
if not out_len:
|
||||
set_error(Z_STREAM_ERROR, "out_len is None")
|
||||
return None
|
||||
if self.eof:
|
||||
if data and data_len > 0:
|
||||
append_bytes(self.pool, c.Addr(self._unused_data), c.Addr(self._unused_data_len),
|
||||
c.Addr(self._unused_data_cap), data, data_len)
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p6: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p6, 0, 1)
|
||||
return p6
|
||||
self._unconsumed_tail_len = 0
|
||||
if data and data_len > 0:
|
||||
append_bytes(self.pool, c.Addr(self.input_buf), c.Addr(self.input_buf_len),
|
||||
c.Addr(self.input_buf_cap), data, data_len)
|
||||
if self.input_buf_len == 0:
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p7: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p7, 0, 1)
|
||||
return p7
|
||||
s: zinflate.zinflate_stream | t.CPtr = zinflate.zinflate_create(self.pool, self.wbits)
|
||||
if not s:
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
if self.zdict and self.zdict_len > 0:
|
||||
s.set_dictionary(self.zdict, self.zdict_len)
|
||||
out: t.CUInt8T | t.CPtr = None
|
||||
err: t.CInt = s.decompress(self.input_buf, self.input_buf_len,
|
||||
max_length, c.Addr(out), out_len)
|
||||
if err != 0:
|
||||
s.destroy()
|
||||
set_error(Z_DATA_ERROR, "decompression failed")
|
||||
return None
|
||||
if s.is_finished:
|
||||
self.eof = 1
|
||||
if s.input_pos < s.input_len:
|
||||
append_bytes(self.pool, c.Addr(self._unused_data), c.Addr(self._unused_data_len),
|
||||
c.Addr(self._unused_data_cap),
|
||||
s.input_data + s.input_pos,
|
||||
s.input_len - s.input_pos)
|
||||
self.input_buf_len = 0
|
||||
else:
|
||||
consumed: t.CSizeT = s.input_pos
|
||||
if consumed < self.input_buf_len:
|
||||
remaining: t.CSizeT = self.input_buf_len - consumed
|
||||
memmove(self.input_buf, self.input_buf + consumed, remaining)
|
||||
self.input_buf_len = remaining
|
||||
else:
|
||||
self.input_buf_len = 0
|
||||
s.destroy()
|
||||
return out
|
||||
|
||||
def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
if not self.is_initialized:
|
||||
set_error(Z_STREAM_ERROR, "decompress object not initialized")
|
||||
return None
|
||||
if not out_len:
|
||||
set_error(Z_STREAM_ERROR, "out_len is None")
|
||||
return None
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
if self.pool == None:
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
p8: BYTEPTR = BYTEPTR(self.pool.alloc(1))
|
||||
memset(p8, 0, 1)
|
||||
return p8
|
||||
|
||||
def copy(self) -> Decompress | t.CPtr:
|
||||
if not self.is_initialized:
|
||||
set_error(Z_STREAM_ERROR, "decompress object not initialized")
|
||||
return None
|
||||
if self.pool == None:
|
||||
copy_obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__())
|
||||
else:
|
||||
copy_obj: Decompress | t.CPtr = self.pool.alloc(Decompress.__sizeof__())
|
||||
memset(copy_obj, 0, Decompress.__sizeof__())
|
||||
if not copy_obj:
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
copy_obj.pool = self.pool
|
||||
copy_obj.is_initialized = 1
|
||||
copy_obj.eof = self.eof
|
||||
copy_obj.wbits = self.wbits
|
||||
if self.zdict and self.zdict_len > 0:
|
||||
copy_obj.zdict = clone_bytes(self.pool, self.zdict, self.zdict_len)
|
||||
copy_obj.zdict_len = self.zdict_len
|
||||
if self._unused_data and self._unused_data_len > 0:
|
||||
copy_obj._unused_data = clone_bytes(self.pool, self._unused_data, self._unused_data_len)
|
||||
copy_obj._unused_data_len = self._unused_data_len
|
||||
copy_obj._unused_data_cap = self._unused_data_len
|
||||
if self._unconsumed_tail and self._unconsumed_tail_len > 0:
|
||||
copy_obj._unconsumed_tail = clone_bytes(self.pool, self._unconsumed_tail, self._unconsumed_tail_len)
|
||||
copy_obj._unconsumed_tail_len = self._unconsumed_tail_len
|
||||
copy_obj._unconsumed_tail_cap = self._unconsumed_tail_len
|
||||
if self.input_buf and self.input_buf_len > 0:
|
||||
copy_obj.input_buf = clone_bytes(self.pool, self.input_buf, self.input_buf_len)
|
||||
copy_obj.input_buf_len = self.input_buf_len
|
||||
copy_obj.input_buf_cap = self.input_buf_cap
|
||||
else:
|
||||
if self.pool == None:
|
||||
copy_obj.input_buf = BYTEPTR(calloc(1, 256))
|
||||
else:
|
||||
copy_obj.input_buf = BYTEPTR(self.pool.alloc(256))
|
||||
memset(copy_obj.input_buf, 0, 256)
|
||||
copy_obj.input_buf_cap = 256
|
||||
copy_obj.input_buf_len = 0
|
||||
return copy_obj
|
||||
|
||||
def delete(self):
|
||||
if self.pool == None:
|
||||
free(self.zdict)
|
||||
free(self._unused_data)
|
||||
free(self._unconsumed_tail)
|
||||
free(self.input_buf)
|
||||
free(self)
|
||||
else:
|
||||
self.pool.free(self.zdict)
|
||||
self.pool.free(self._unused_data)
|
||||
self.pool.free(self._unconsumed_tail)
|
||||
self.pool.free(self.input_buf)
|
||||
self.pool.free(self)
|
||||
|
||||
def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
#if not self:
|
||||
# if length:
|
||||
# c.Set(c.Deref(length), 0)
|
||||
# return None
|
||||
if length:
|
||||
c.Set(c.Deref(length), self._unused_data_len)
|
||||
return self._unused_data
|
||||
|
||||
def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
#if not self:
|
||||
# if length:
|
||||
# c.Set(c.Deref(length), 0)
|
||||
# return None
|
||||
if length:
|
||||
c.Set(c.Deref(length), self._unconsumed_tail_len)
|
||||
return self._unconsumed_tail
|
||||
|
||||
# def eof(self) -> t.CInt:
|
||||
# # if not obj: return 0
|
||||
# return self.eof
|
||||
|
||||
|
||||
|
||||
def set_error(code: int, msg: str):
|
||||
global pyzlib_error_code_val, pyzlib_error_msg
|
||||
pyzlib_error_code_val = code
|
||||
if msg:
|
||||
strncpy(pyzlib_error_msg, msg, pyzlib_error_msg.__sizeof__() - 1)
|
||||
pyzlib_error_msg[pyzlib_error_msg.__sizeof__() - 1] = '\0'
|
||||
else:
|
||||
pyzlib_error_msg[0] = '\0'
|
||||
|
||||
def clone_bytes(pool: memhub.MemManager | t.CPtr, src: BYTEPTR, length: t.CSizeT) -> BYTEPTR:
|
||||
if not src or length == 0: return None
|
||||
if pool == None:
|
||||
dst: BYTEPTR = BYTEPTR(malloc(length))
|
||||
else:
|
||||
dst: BYTEPTR = BYTEPTR(pool.alloc(length))
|
||||
if dst: memcpy(dst, src, length)
|
||||
return dst
|
||||
|
||||
def append_bytes(pool: memhub.MemManager | t.CPtr, buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr,
|
||||
data: BYTEPTR, data_len: t.CSizeT) -> t.CInt:
|
||||
if not data or data_len == 0: return 0
|
||||
needed: t.CSizeT = c.Deref(length) + data_len
|
||||
if needed > c.Deref(cap):
|
||||
new_cap: t.CSizeT = c.Deref(cap) * 2
|
||||
if new_cap < needed: new_cap = needed
|
||||
if pool == None:
|
||||
new_buf: BYTEPTR = BYTEPTR(realloc(c.Deref(buf), new_cap))
|
||||
else:
|
||||
new_buf: BYTEPTR = BYTEPTR(pool.alloc(new_cap))
|
||||
if new_buf:
|
||||
memcpy(new_buf, c.Deref(buf), c.Deref(length))
|
||||
pool.free(c.Deref(buf))
|
||||
if not new_buf: return -1
|
||||
c.Set(c.Deref(buf), new_buf)
|
||||
c.Set(c.Deref(cap), new_cap)
|
||||
memcpy(c.Deref(buf) + c.Deref(length), data, data_len)
|
||||
c.Set(c.Deref(length), c.Deref(length) + data_len)
|
||||
return 0
|
||||
|
||||
|
||||
def shrink_to_fit(pool: memhub.MemManager | t.CPtr, buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR:
|
||||
if length == 0:
|
||||
if pool == None:
|
||||
free(buf)
|
||||
return BYTEPTR(calloc(1, 1))
|
||||
else:
|
||||
pool.free(buf)
|
||||
p: BYTEPTR = BYTEPTR(pool.alloc(1))
|
||||
memset(p, 0, 1)
|
||||
return p
|
||||
if pool == None:
|
||||
result: BYTEPTR = BYTEPTR(realloc(buf, length))
|
||||
return result if result else buf
|
||||
else:
|
||||
result: BYTEPTR = BYTEPTR(pool.alloc(length))
|
||||
if result:
|
||||
memcpy(result, buf, length)
|
||||
pool.free(buf)
|
||||
return result
|
||||
return buf
|
||||
|
||||
|
||||
def runtime_version() -> str:
|
||||
return ZLIB_VERSION
|
||||
|
||||
def get_error() -> str:
|
||||
return pyzlib_error_msg
|
||||
|
||||
def get_error_code() -> t.CInt:
|
||||
return pyzlib_error_code_val
|
||||
|
||||
def clear_error():
|
||||
global pyzlib_error_msg, pyzlib_error_code_val
|
||||
pyzlib_error_msg[0] = '\0'
|
||||
pyzlib_error_code_val = 0
|
||||
|
||||
def compress(pool: memhub.MemManager | t.CPtr, data: BYTEPTR, data_len: t.CSizeT,
|
||||
level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
if not data and data_len > 0:
|
||||
set_error(Z_STREAM_ERROR, "data is None but data_len > 0")
|
||||
return None
|
||||
if not out_len:
|
||||
set_error(Z_STREAM_ERROR, "out_len is None")
|
||||
return None
|
||||
actual_wbits: t.CInt = wbits
|
||||
if wbits > MAX_WBITS:
|
||||
actual_wbits = -MAX_WBITS
|
||||
raw_result: UINT8PTR = zdeflate.zdeflate_one_shot(pool, data, data_len, level, actual_wbits, out_len)
|
||||
if not raw_result:
|
||||
set_error(Z_DATA_ERROR, "compression failed")
|
||||
return None
|
||||
if wbits > MAX_WBITS:
|
||||
gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8
|
||||
if pool == None:
|
||||
gzip_buf: BYTEPTR = BYTEPTR(malloc(gzip_len))
|
||||
else:
|
||||
gzip_buf: BYTEPTR = BYTEPTR(pool.alloc(gzip_len))
|
||||
if not gzip_buf:
|
||||
if pool == None:
|
||||
free(raw_result)
|
||||
else:
|
||||
pool.free(raw_result)
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
pos: t.CSizeT = 0
|
||||
gzip_buf[pos + 0] = 0x1F
|
||||
gzip_buf[pos + 1] = 0x8B
|
||||
gzip_buf[pos + 2] = 0x08
|
||||
gzip_buf[pos + 3] = 0x00
|
||||
gzip_buf[pos + 4] = 0x00
|
||||
gzip_buf[pos + 5] = 0x00
|
||||
gzip_buf[pos + 6] = 0x00
|
||||
gzip_buf[pos + 7] = 0x00
|
||||
gzip_buf[pos + 8] = 0x00
|
||||
gzip_buf[pos + 9] = 0xFF
|
||||
pos += 10
|
||||
|
||||
memcpy(gzip_buf + pos, raw_result, c.Deref(out_len))
|
||||
pos += c.Deref(out_len)
|
||||
if pool == None:
|
||||
free(raw_result)
|
||||
else:
|
||||
pool.free(raw_result)
|
||||
|
||||
crc: t.CUInt32T = zchecksum.zchecksum_crc32(data, data_len, 0)
|
||||
gzip_buf[pos + 0] = (crc) & 0xFF
|
||||
gzip_buf[pos + 1] = (crc >> 8) & 0xFF
|
||||
gzip_buf[pos + 2] = (crc >> 16) & 0xFF
|
||||
gzip_buf[pos + 3] = (crc >> 24) & 0xFF
|
||||
gzip_buf[pos + 4] = (data_len) & 0xFF
|
||||
gzip_buf[pos + 5] = (data_len >> 8) & 0xFF
|
||||
gzip_buf[pos + 6] = (data_len >> 16) & 0xFF
|
||||
gzip_buf[pos + 7] = (data_len >> 24) & 0xFF
|
||||
pos += 8
|
||||
c.Set(c.Deref(out_len), pos)
|
||||
return shrink_to_fit(pool, gzip_buf, pos)
|
||||
return shrink_to_fit(pool, raw_result, c.Deref(out_len))
|
||||
|
||||
|
||||
def decompress(pool: memhub.MemManager | t.CPtr, data: BYTEPTR, data_len: t.CSizeT,
|
||||
wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR:
|
||||
if not data and data_len > 0:
|
||||
set_error(Z_STREAM_ERROR, "data is None but data_len > 0")
|
||||
return None
|
||||
if not out_len:
|
||||
set_error(Z_STREAM_ERROR, "out_len is None")
|
||||
return None
|
||||
result: UINT8PTR = zinflate.zinflate_one_shot(pool, data, data_len, wbits, bufsize, out_len)
|
||||
if not result:
|
||||
set_error(Z_DATA_ERROR, "decompression failed")
|
||||
return None
|
||||
return shrink_to_fit(pool, result, c.Deref(out_len))
|
||||
|
||||
def compressobj(pool: memhub.MemManager | t.CPtr, level: t.CInt, method: t.CInt, wbits: t.CInt,
|
||||
memLevel: t.CInt, strategy: t.CInt,
|
||||
zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr:
|
||||
if pool == None:
|
||||
obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__())
|
||||
else:
|
||||
obj: Compress | t.CPtr = pool.alloc(Compress.__sizeof__())
|
||||
memset(obj, 0, Compress.__sizeof__())
|
||||
if not obj:
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
obj.pool = pool
|
||||
actual_wbits: t.CInt = wbits
|
||||
if wbits > MAX_WBITS: actual_wbits = wbits - 16
|
||||
s: zdeflate.zdeflate_stream | t.CPtr = zdeflate.zdeflate_create(pool, level, actual_wbits, memLevel, strategy)
|
||||
if not s:
|
||||
if pool == None:
|
||||
free(obj)
|
||||
else:
|
||||
pool.free(obj)
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
obj.stream = s
|
||||
obj.is_initialized = 1
|
||||
obj.level = level
|
||||
obj.method = method
|
||||
obj.wbits = wbits
|
||||
obj.memLevel = memLevel
|
||||
obj.strategy = strategy
|
||||
if pool == None:
|
||||
obj.input_buf = BYTEPTR(calloc(1, 256))
|
||||
else:
|
||||
obj.input_buf = BYTEPTR(pool.alloc(256))
|
||||
memset(obj.input_buf, 0, 256)
|
||||
obj.input_buf_cap = 256
|
||||
obj.input_buf_len = 0
|
||||
obj.header_written = 0
|
||||
if zdict and zdict_len > 0:
|
||||
s.set_dictionary(zdict, zdict_len)
|
||||
obj.zdict = clone_bytes(pool, zdict, zdict_len)
|
||||
obj.zdict_len = zdict_len
|
||||
return obj
|
||||
|
||||
|
||||
def decompressobj(pool: memhub.MemManager | t.CPtr, wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr:
|
||||
if pool == None:
|
||||
obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__())
|
||||
else:
|
||||
obj: Decompress | t.CPtr = pool.alloc(Decompress.__sizeof__())
|
||||
memset(obj, 0, Decompress.__sizeof__())
|
||||
if not obj:
|
||||
set_error(Z_MEM_ERROR, "out of memory")
|
||||
return None
|
||||
obj.pool = pool
|
||||
actual_wbits: t.CInt = wbits
|
||||
if wbits > MAX_WBITS: actual_wbits = wbits - 16
|
||||
obj.stream = None
|
||||
obj.is_initialized = 1
|
||||
obj.wbits = actual_wbits
|
||||
if zdict and zdict_len > 0:
|
||||
obj.zdict = clone_bytes(pool, zdict, zdict_len)
|
||||
obj.zdict_len = zdict_len
|
||||
if pool == None:
|
||||
obj.input_buf = BYTEPTR(calloc(1, 256))
|
||||
else:
|
||||
obj.input_buf = BYTEPTR(pool.alloc(256))
|
||||
memset(obj.input_buf, 0, 256)
|
||||
obj.input_buf_cap = 256
|
||||
obj.input_buf_len = 0
|
||||
return obj
|
||||
|
||||
def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong:
|
||||
return zchecksum.zchecksum_adler32(data, length, UINT32(value))
|
||||
|
||||
def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong:
|
||||
return zchecksum.zchecksum_crc32(data, length, UINT32(value))
|
||||
@@ -0,0 +1,89 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
|
||||
|
||||
def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T:
|
||||
a: t.CUInt32T = (init >> 0) & 0xFFFF
|
||||
b: t.CUInt32T = (init >> 16) & 0xFFFF
|
||||
if not data or length == 0:
|
||||
return init
|
||||
i: t.CSizeT
|
||||
for i in range(length):
|
||||
a = (a + data[i]) % 65521
|
||||
b = (b + a) % 65521
|
||||
return (b << 16) | a
|
||||
|
||||
crc32_table: t.CArray[t.CUInt32T, 256] = [
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBBBD6, 0xACBCCB40,
|
||||
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7D49,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||
0xA9BCAE53, 0xDede9EC5, 0x47D7897F, 0x30D0B8E9,
|
||||
0xBDDA8B1C, 0xCADD8B8A, 0x53D3903A, 0x24D4C2AC,
|
||||
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
]
|
||||
|
||||
def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T:
|
||||
crc: t.CUInt32T = init ^ 0xFFFFFFFF
|
||||
if not data or length == 0: return init
|
||||
i: t.CSizeT
|
||||
for i in range(length):
|
||||
crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8)
|
||||
return crc ^ 0xFFFFFFFF
|
||||
@@ -0,0 +1,288 @@
|
||||
from stdint import *
|
||||
import stddef
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DEFLATE / zlib constants
|
||||
# ============================================================
|
||||
ZDEFLATE_WINDOW_BITS: t.CDefine = 15
|
||||
ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS)
|
||||
ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1)
|
||||
|
||||
ZDEFLATE_MIN_MATCH: t.CDefine = 3
|
||||
ZDEFLATE_MAX_MATCH: t.CDefine = 258
|
||||
|
||||
ZDEFLATE_HASH_BITS: t.CDefine = 15
|
||||
ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS)
|
||||
ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1)
|
||||
|
||||
ZDEFLATE_MAX_CODES: t.CDefine = 288
|
||||
ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32
|
||||
ZDEFLATE_MAX_BITS: t.CDefine = 15
|
||||
ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19
|
||||
|
||||
ZDEFLATE_LIT_COUNT: t.CDefine = 286
|
||||
ZDEFLATE_DIST_COUNT: t.CDefine = 30
|
||||
|
||||
ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257
|
||||
ZDEFLATE_END_OF_BLOCK: t.CDefine = 256
|
||||
|
||||
# ============================================================
|
||||
# Length / Distance extra bits tables (RFC 1951)
|
||||
# ============================================================
|
||||
zdeflate_len_extra_bits: t.CArray[t.CInt, 29] = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
2, 2, 2, 2,
|
||||
3, 3, 3, 3,
|
||||
4, 4, 4, 4,
|
||||
5, 5, 5, 5,
|
||||
0
|
||||
]
|
||||
|
||||
zdeflate_len_base: t.CArray[t.CInt, 29] = [
|
||||
3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 13, 15, 17,
|
||||
19, 23, 27, 31,
|
||||
35, 43, 51, 59,
|
||||
67, 83, 99, 115,
|
||||
131, 163, 195, 227,
|
||||
258
|
||||
]
|
||||
|
||||
zdeflate_dist_extra_bits: t.CArray[t.CInt, 30] = [
|
||||
0, 0, 0, 0,
|
||||
1, 1,
|
||||
2, 2,
|
||||
3, 3,
|
||||
4, 4,
|
||||
5, 5,
|
||||
6, 6,
|
||||
7, 7,
|
||||
8, 8,
|
||||
9, 9,
|
||||
10, 10,
|
||||
11, 11,
|
||||
12, 12,
|
||||
13, 13
|
||||
]
|
||||
|
||||
zdeflate_dist_base: t.CArray[t.CInt, 30] = [
|
||||
1, 2, 3, 4,
|
||||
5, 7,
|
||||
9, 13,
|
||||
17, 25,
|
||||
33, 49,
|
||||
65, 97,
|
||||
129, 193,
|
||||
257, 385,
|
||||
513, 769,
|
||||
1025, 1537,
|
||||
2049, 3073,
|
||||
4097, 6145,
|
||||
8193, 12289,
|
||||
16385, 24577
|
||||
]
|
||||
|
||||
zdeflate_codelen_order: t.CArray[int, 19] = [
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
]
|
||||
|
||||
# ============================================================
|
||||
# Bit writer - writes bits LSB first into a byte buffer
|
||||
# ============================================================
|
||||
@t.Object
|
||||
class zbit_writer:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
buf: BYTE | t.CPtr
|
||||
cap: t.CSizeT
|
||||
byte_pos: t.CSizeT
|
||||
bit_pos: t.CInt
|
||||
|
||||
def __init__(self, pool: memhub.MemManager | t.CPtr):
|
||||
self.pool = pool
|
||||
self.cap = 4096
|
||||
if pool == None:
|
||||
self.buf = BYTEPTR(malloc(self.cap))
|
||||
else:
|
||||
self.buf = BYTEPTR(pool.alloc(self.cap))
|
||||
memset(self.buf, 0, self.cap)
|
||||
self.byte_pos = 0
|
||||
self.bit_pos = 0
|
||||
|
||||
def ensure(self, need: t.CSizeT):
|
||||
while self.byte_pos + need + 4 >= self.cap:
|
||||
new_cap: t.CSizeT = self.cap * 2
|
||||
if self.pool == None:
|
||||
new_buf: BYTE | t.CPtr = BYTEPTR(realloc(self.buf, new_cap))
|
||||
else:
|
||||
new_buf: BYTE | t.CPtr = BYTEPTR(self.pool.alloc(new_cap))
|
||||
if new_buf:
|
||||
memcpy(new_buf, self.buf, self.byte_pos + (self.bit_pos + 7) / 8)
|
||||
self.pool.free(self.buf)
|
||||
if not new_buf: return
|
||||
memset(new_buf + self.cap, 0, new_cap - self.cap)
|
||||
self.buf = new_buf
|
||||
self.cap = new_cap
|
||||
|
||||
def write_bits(self, value: UINT, nbits: t.CInt):
|
||||
self.ensure((nbits + 7) / 8 + 1)
|
||||
for i in range(nbits):
|
||||
if value & (UINT(1) << i):
|
||||
self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos)
|
||||
self.bit_pos += 1
|
||||
if self.bit_pos == 8:
|
||||
self.bit_pos = 0
|
||||
self.byte_pos += 1
|
||||
|
||||
def write_bits_rev(self, code: UINT, nbits: t.CInt):
|
||||
self.ensure((nbits + 7) / 8 + 1)
|
||||
for i in range(nbits - 1, -1, -1):
|
||||
if code & (UINT(1) << i):
|
||||
self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos)
|
||||
self.bit_pos += 1
|
||||
if self.bit_pos == 8:
|
||||
self.bit_pos = 0
|
||||
self.byte_pos += 1
|
||||
|
||||
def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt):
|
||||
self.write_bits(1 if final else 0, 1)
|
||||
self.write_bits(0, 2)
|
||||
self.align()
|
||||
|
||||
pos: t.CSizeT = 0
|
||||
while pos < length:
|
||||
block_length: t.CSizeT = length - pos
|
||||
if block_length > 65535:
|
||||
block_length = 65535
|
||||
n: t.CUInt16T = t.CUInt16T(block_length)
|
||||
ncomp: t.CUInt16T = ~n
|
||||
self.write_bits(n, 16)
|
||||
self.write_bits(ncomp, 16)
|
||||
|
||||
self.ensure(block_length)
|
||||
i: t.CSizeT = 0
|
||||
for i in range(block_length):
|
||||
self.buf[self.byte_pos] = data[pos + i]
|
||||
self.byte_pos += 1
|
||||
pos += block_length
|
||||
if pos < length:
|
||||
self.write_bits(0, 1)
|
||||
self.write_bits(0, 2)
|
||||
self.align()
|
||||
|
||||
def write_zlib_header(self, wbits: t.CInt, level: t.CInt):
|
||||
cinfo: t.CInt = wbits - 8
|
||||
if cinfo < 1: cinfo = 1
|
||||
if cinfo > 7: cinfo = 7
|
||||
cmf: t.CUnsignedChar = t.CUnsignedChar((cinfo << 4) | 8)
|
||||
|
||||
flevel: t.CInt = 0
|
||||
if level >= 5: flevel = 3
|
||||
elif level >= 3: flevel = 1
|
||||
|
||||
flg: t.CUnsignedChar = t.CUnsignedChar(flevel << 6)
|
||||
flg |= t.CUnsignedChar(31 - (cmf * 256 + flg) % 31)
|
||||
|
||||
self.buf[self.byte_pos + 0] = cmf
|
||||
self.buf[self.byte_pos + 1] = flg
|
||||
self.byte_pos += 2
|
||||
|
||||
|
||||
def write_gzip_header(self):
|
||||
self.buf[self.byte_pos + 0] = 0x1F
|
||||
self.buf[self.byte_pos + 1] = 0x8B
|
||||
self.buf[self.byte_pos + 2] = 0x08
|
||||
self.buf[self.byte_pos + 3] = 0x00
|
||||
self.buf[self.byte_pos + 4] = 0x00
|
||||
self.buf[self.byte_pos + 5] = 0x00
|
||||
self.buf[self.byte_pos + 6] = 0x00
|
||||
self.buf[self.byte_pos + 7] = 0x00
|
||||
self.buf[self.byte_pos + 8] = 0x00
|
||||
self.buf[self.byte_pos + 9] = 0xFF
|
||||
self.byte_pos += 10
|
||||
|
||||
def align(self):
|
||||
if self.bit_pos > 0:
|
||||
self.bit_pos = 0
|
||||
self.byte_pos += 1
|
||||
|
||||
def total(self) -> t.CSizeT:
|
||||
return self.byte_pos + (1 if (self.bit_pos > 0) else 0)
|
||||
|
||||
def free(self):
|
||||
if self.pool == None:
|
||||
free(self.buf)
|
||||
else:
|
||||
self.pool.free(self.buf)
|
||||
self.buf = None
|
||||
self.cap = 0
|
||||
self.byte_pos = 0
|
||||
self.bit_pos = 0
|
||||
|
||||
def __del__(self):
|
||||
self.free()
|
||||
|
||||
# ============================================================
|
||||
# Bit reader - reads bits LSB first from a byte buffer
|
||||
# ============================================================
|
||||
@t.Object
|
||||
class zbit_reader:
|
||||
buf: BYTE | t.CPtr
|
||||
length: t.CSizeT
|
||||
byte_pos: t.CSizeT
|
||||
bit_pos: t.CInt
|
||||
|
||||
def init(self, buf: BYTE | t.CPtr, length: t.CSizeT):
|
||||
self.buf = buf
|
||||
self.length = length
|
||||
self.byte_pos = 0
|
||||
self.bit_pos = 0
|
||||
|
||||
def read_bits(self, nbits: t.CInt, out: UINTPTR) -> t.CInt:
|
||||
val: UINT = 0
|
||||
for i in range(nbits):
|
||||
if self.byte_pos >= self.length: return -1
|
||||
if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos):
|
||||
val |= (UINT(1) << i)
|
||||
self.bit_pos += 1
|
||||
if self.bit_pos == 8:
|
||||
self.bit_pos = 0
|
||||
self.byte_pos += 1
|
||||
c.Set(c.Deref(out), val)
|
||||
return 0
|
||||
|
||||
def read_bits_rev(self, nbits: t.CInt, out: UINTPTR) -> t.CInt:
|
||||
val: UINT = 0
|
||||
for i in range(nbits - 1, 0, -1):
|
||||
if self.byte_pos >= self.length: return -1
|
||||
if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos):
|
||||
val |= (UINT(1) << i)
|
||||
self.bit_pos += 1
|
||||
if self.bit_pos == 8:
|
||||
self.bit_pos = 0
|
||||
self.byte_pos += 1
|
||||
c.Set(c.Deref(out), val)
|
||||
return 0
|
||||
|
||||
def align(self):
|
||||
if self.bit_pos > 0:
|
||||
self.bit_pos = 0
|
||||
self.byte_pos += 1
|
||||
|
||||
# ============================================================
|
||||
# Memory allocation helper for bare metal
|
||||
# Can be replaced with custom allocator
|
||||
# ============================================================
|
||||
def zdef_alloc(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> VOIDPTR:
|
||||
if pool == None: return malloc(n)
|
||||
return pool.alloc(n)
|
||||
def zdef_free(pool: memhub.MemManager | t.CPtr, p: VOIDPTR):
|
||||
if pool == None:
|
||||
free(p)
|
||||
return
|
||||
pool.free(p)
|
||||
@@ -0,0 +1,434 @@
|
||||
from stdint import *
|
||||
import zlib.zchecksum as zchecksum
|
||||
import zlib.zhuff as zhuff
|
||||
import zlib.zdef as zdef
|
||||
import string
|
||||
import memhub
|
||||
import t, c
|
||||
|
||||
|
||||
@t.Object
|
||||
class zdeflate_stream:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
writer: zdef.zbit_writer
|
||||
window: BYTE | t.CPtr
|
||||
window_pos: t.CInt
|
||||
window_size: t.CInt
|
||||
hash_head: t.CInt | t.CPtr
|
||||
hash_prev: t.CInt | t.CPtr
|
||||
level: t.CInt
|
||||
strategy: t.CInt
|
||||
wbits: t.CInt
|
||||
is_finished: t.CInt
|
||||
adler: t.CUInt32T
|
||||
|
||||
def find_match(self, data: BYTE | t.CPtr, data_len: t.CSizeT,
|
||||
pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt:
|
||||
if pos + 2 >= data_len: return 0
|
||||
h: t.CUnsignedInt = zdeflate_hash(data + pos)
|
||||
chain: t.CInt = self.hash_head[h]
|
||||
best_len: t.CInt = zdef.ZDEFLATE_MIN_MATCH - 1
|
||||
c.Set(c.Deref(best_dist), 0)
|
||||
max_chain: t.CInt = 128 if (self.level >= 5) else (32 if (self.level >= 2) else 4)
|
||||
limit: t.CInt = (1 << self.wbits) if (self.wbits > 0) else zdef.ZDEFLATE_WINDOW_SIZE
|
||||
if limit > zdef.ZDEFLATE_WINDOW_SIZE:
|
||||
limit = zdef.ZDEFLATE_WINDOW_SIZE
|
||||
attempts: t.CInt = 0
|
||||
while chain >= 0 and attempts < max_chain:
|
||||
dist: t.CInt = t.CInt(pos) - chain
|
||||
if dist <= 0 or dist > limit: break
|
||||
match_len: t.CInt = 0
|
||||
max_len: t.CInt = t.CInt(data_len - pos)
|
||||
if max_len > zdef.ZDEFLATE_MAX_MATCH:
|
||||
max_len = zdef.ZDEFLATE_MAX_MATCH
|
||||
while match_len < max_len and data[pos + match_len] == data[chain + match_len]:
|
||||
match_len += 1
|
||||
if match_len > best_len:
|
||||
best_len = match_len
|
||||
c.Set(c.Deref(best_dist), dist)
|
||||
if best_len >= zdef.ZDEFLATE_MAX_MATCH: break
|
||||
chain = self.hash_prev[chain & zdef.ZDEFLATE_WINDOW_MASK]
|
||||
if chain <= t.CInt(pos) - limit: break
|
||||
attempts += 1
|
||||
return best_len if (best_len >= zdef.ZDEFLATE_MIN_MATCH) else 0
|
||||
|
||||
def update_hash(self, data: BYTE | t.CPtr, pos: t.CSizeT):
|
||||
if pos + 2 < pos: return
|
||||
h: t.CUnsignedInt = zdeflate_hash(data + pos)
|
||||
self.hash_prev[pos & zdef.ZDEFLATE_WINDOW_MASK] = self.hash_head[h]
|
||||
self.hash_head[h] = t.CInt(pos)
|
||||
|
||||
def write_fixed_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt):
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
dist_tree = zhuff.zhuff_tree()
|
||||
lit_tree.build_fixed_lit_tree()
|
||||
dist_tree.build_fixed_dist_tree()
|
||||
self.writer.write_bits(1 if final else 0, 1)
|
||||
self.writer.write_bits(1, 2)
|
||||
pos: t.CSizeT = 0
|
||||
while pos < length:
|
||||
best_dist: t.CInt = 0
|
||||
match_len: t.CInt = 0
|
||||
if self.level > 0 and pos + 2 < length:
|
||||
match_len = self.find_match(data, length, pos, c.Addr(best_dist))
|
||||
if match_len >= zdef.ZDEFLATE_MIN_MATCH:
|
||||
len_sym: t.CInt = zdeflate_len_to_symbol(match_len)
|
||||
lit_tree.encode_symbol(len_sym, c.Addr(self.writer))
|
||||
extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257]
|
||||
if extra > 0:
|
||||
self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra)
|
||||
dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist)
|
||||
dist_tree.encode_symbol(dist_sym, c.Addr(self.writer))
|
||||
extra = zdef.zdeflate_dist_extra_bits[dist_sym]
|
||||
if extra > 0:
|
||||
self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra)
|
||||
for i in range(match_len):
|
||||
self.update_hash(data, pos + i)
|
||||
pos += match_len
|
||||
else:
|
||||
lit_tree.encode_symbol(data[pos], c.Addr(self.writer))
|
||||
self.update_hash(data, pos)
|
||||
pos += 1
|
||||
lit_tree.encode_symbol(256, c.Addr(self.writer))
|
||||
|
||||
def encode_block_data(self, data: UINT8PTR, length: t.CSizeT,
|
||||
lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr):
|
||||
pos: t.CSizeT = 0
|
||||
while pos < length:
|
||||
best_dist: t.CInt = 0
|
||||
match_len: t.CInt = 0
|
||||
if self.level > 0 and pos + 2 < length:
|
||||
match_len = self.find_match(data, length, pos, c.Addr(best_dist))
|
||||
if match_len >= zdef.ZDEFLATE_MIN_MATCH:
|
||||
len_sym: t.CInt = zdeflate_len_to_symbol(match_len)
|
||||
lit_tree.encode_symbol(len_sym, c.Addr(self.writer))
|
||||
extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257]
|
||||
if extra > 0:
|
||||
self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra)
|
||||
dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist)
|
||||
dist_tree.encode_symbol(dist_sym, c.Addr(self.writer))
|
||||
extra = zdef.zdeflate_dist_extra_bits[dist_sym]
|
||||
if extra > 0:
|
||||
self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra)
|
||||
for j in range(match_len):
|
||||
self.update_hash(data, pos + j)
|
||||
pos += match_len
|
||||
else:
|
||||
lit_tree.encode_symbol(data[pos], c.Addr(self.writer))
|
||||
self.update_hash(data, pos)
|
||||
pos += 1
|
||||
lit_tree.encode_symbol(256, c.Addr(self.writer))
|
||||
|
||||
|
||||
def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt):
|
||||
lit_freqs: t.CArray[t.CInt, 288]
|
||||
dist_freqs: t.CArray[t.CInt, 32]
|
||||
zdeflate_count_freqs(lit_freqs, dist_freqs, self, data, length)
|
||||
hlit: t.CInt = 286
|
||||
while hlit > 257 and lit_freqs[hlit - 1] == 0: hlit -= 1
|
||||
hdist: t.CInt = 30
|
||||
while hdist > 1 and dist_freqs[hdist - 1] == 0: hdist -= 1
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
dist_tree = zhuff.zhuff_tree()
|
||||
lit_tree.build_codes(lit_freqs, hlit, zdef.ZDEFLATE_MAX_BITS)
|
||||
dist_tree.build_codes(dist_freqs, hdist, zdef.ZDEFLATE_MAX_BITS)
|
||||
all_lengths: t.CArray[t.CInt, 288 + 32]
|
||||
for i in range(hlit): all_lengths[i] = lit_tree.codes[i].bits
|
||||
for i in range(hdist): all_lengths[hlit + i] = dist_tree.codes[i].bits
|
||||
total_lengths: t.CInt = hlit + hdist
|
||||
cl_freqs: t.CArray[t.CInt, 19]
|
||||
zdeflate_count_cl_freqs(all_lengths, total_lengths, cl_freqs)
|
||||
cl_tree = zhuff.zhuff_tree()
|
||||
cl_tree.build_codes(cl_freqs, 19, 7)
|
||||
hclen: int = 19
|
||||
while hclen > 4 and cl_tree.codes[zdef.zdeflate_codelen_order[hclen - 1]].bits == 0: hclen -= 1
|
||||
self.writer.write_bits(1 if final else 0, 1)
|
||||
self.writer.write_bits(2, 2)
|
||||
self.writer.write_bits(hlit - 257, 5)
|
||||
self.writer.write_bits(hdist - 1, 5)
|
||||
self.writer.write_bits(hclen - 4, 4)
|
||||
for j in range(hclen):
|
||||
self.writer.write_bits(cl_tree.codes[zdef.zdeflate_codelen_order[j]].bits, 3)
|
||||
zdeflate_write_cl_encoded(all_lengths, total_lengths, c.Addr(self.writer), c.Addr(cl_tree))
|
||||
self.encode_block_data(data, length, c.Addr(lit_tree), c.Addr(dist_tree))
|
||||
|
||||
def compress_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt):
|
||||
if self.level == 0:
|
||||
self.write_stored_block(data, length, final)
|
||||
elif self.strategy == 4 or length < 128:
|
||||
self.write_fixed_block(data, length, final)
|
||||
else:
|
||||
self.write_dynamic_block(data, length, final)
|
||||
|
||||
def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt):
|
||||
self.writer.stored_block(data, length, final)
|
||||
|
||||
def compress(self, data: UINT8PTR, length: t.CSizeT,
|
||||
out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt:
|
||||
if self.is_finished: return -2
|
||||
if not data or length == 0:
|
||||
c.Set(c.Deref(out), None)
|
||||
c.Set(c.Deref(out_len), 0)
|
||||
return 0
|
||||
self.adler = zchecksum.zchecksum_adler32(data, length, self.adler)
|
||||
memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())
|
||||
memset(self.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())
|
||||
self.compress_block(data, length, 0)
|
||||
c.Set(c.Deref(out_len), self.writer.total())
|
||||
c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, c.Deref(out_len))))
|
||||
if not c.Deref(out): return -4
|
||||
memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len))
|
||||
return 0
|
||||
|
||||
def flush(self, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt:
|
||||
if mode == 4:
|
||||
if not self.is_finished:
|
||||
if self.level == 0:
|
||||
self.writer.write_bits(1, 1)
|
||||
self.writer.write_bits(0, 2)
|
||||
self.writer.align()
|
||||
else:
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
lit_tree.build_fixed_lit_tree()
|
||||
self.writer.write_bits(1, 1)
|
||||
self.writer.write_bits(1, 2)
|
||||
lit_tree.encode_symbol(256, c.Addr(self.writer))
|
||||
self.is_finished = 1
|
||||
if self.wbits >= 0:
|
||||
self.writer.align()
|
||||
adler: t.CUInt32T = self.adler
|
||||
self.writer.buf[self.writer.byte_pos + 0] = (adler >> 24) & 0xFF
|
||||
self.writer.buf[self.writer.byte_pos + 1] = (adler >> 16) & 0xFF
|
||||
self.writer.buf[self.writer.byte_pos + 2] = (adler >> 8) & 0xFF
|
||||
self.writer.buf[self.writer.byte_pos + 3] = (adler >> 0) & 0xFF
|
||||
self.writer.byte_pos += 4
|
||||
elif mode == 2 or mode == 3:
|
||||
self.writer.write_bits(0, 1)
|
||||
self.writer.write_bits(0, 2)
|
||||
self.writer.align()
|
||||
c.Set(c.Deref(out_len), self.writer.total())
|
||||
c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, c.Deref(out_len))))
|
||||
if not c.Deref(out): return -4
|
||||
memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len))
|
||||
return 0
|
||||
|
||||
def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt:
|
||||
if not dict: return -2
|
||||
use: t.CSizeT = length
|
||||
if use > zdef.ZDEFLATE_WINDOW_SIZE:
|
||||
dict += length - zdef.ZDEFLATE_WINDOW_SIZE
|
||||
use = zdef.ZDEFLATE_WINDOW_SIZE
|
||||
memcpy(self.window, dict, use)
|
||||
self.window_size = t.CInt(use)
|
||||
self.window_pos = t.CInt(use)
|
||||
self.adler = zchecksum.zchecksum_adler32(dict, length, self.adler)
|
||||
return 0
|
||||
|
||||
def copy(self) -> zdeflate_stream | t.CPtr:
|
||||
z: zdeflate_stream | t.CPtr = zdef.zdef_alloc(self.pool, zdeflate_stream.__sizeof__())
|
||||
if not z: return None
|
||||
memcpy(z, self, zdeflate_stream.__sizeof__())
|
||||
z.writer.buf = BYTEPTR(zdef.zdef_alloc(self.pool, self.writer.cap))
|
||||
if not z.writer.buf:
|
||||
zdef.zdef_free(self.pool, z)
|
||||
return None
|
||||
memcpy(z.writer.buf, self.writer.buf, self.writer.cap)
|
||||
z.window = BYTEPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE))
|
||||
z.hash_head = INTPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()))
|
||||
z.hash_prev = INTPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()))
|
||||
if not z.window or not z.hash_head or not z.hash_prev:
|
||||
if z.writer.buf: zdef.zdef_free(self.pool, z.writer.buf)
|
||||
zdef.zdef_free(self.pool, z)
|
||||
return None
|
||||
memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE)
|
||||
memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())
|
||||
memcpy(z.hash_prev, self.hash_prev, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())
|
||||
return z
|
||||
|
||||
def destroy(self):
|
||||
if self.writer.buf: zdef.zdef_free(self.pool, self.writer.buf)
|
||||
if self.window: zdef.zdef_free(self.pool, self.window)
|
||||
if self.hash_head: zdef.zdef_free(self.pool, self.hash_head)
|
||||
if self.hash_prev: zdef.zdef_free(self.pool, self.hash_prev)
|
||||
zdef.zdef_free(self.pool, self)
|
||||
|
||||
|
||||
|
||||
|
||||
def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR,
|
||||
s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT):
|
||||
memset(lit_freqs, 0, 288 * int.__sizeof__())
|
||||
memset(dist_freqs, 0, 32 * int.__sizeof__())
|
||||
pos: t.CSizeT = 0
|
||||
while pos < length:
|
||||
best_dist: t.CInt = 0
|
||||
match_len: t.CInt = 0
|
||||
if s.level > 0 and pos + 2 < length:
|
||||
match_len = zdeflate_stream.find_match(s, data, length, pos, c.Addr(best_dist))
|
||||
if match_len >= zdef.ZDEFLATE_MIN_MATCH:
|
||||
len_sym: t.CInt = zdeflate_len_to_symbol(match_len)
|
||||
lit_freqs[len_sym] += 1
|
||||
dist_freqs[zdeflate_dist_to_symbol(best_dist)] += 1
|
||||
for i in range(match_len):
|
||||
zdeflate_stream.update_hash(s, data, pos + i)
|
||||
pos += match_len
|
||||
else:
|
||||
lit_freqs[data[pos]] += 1
|
||||
zdeflate_stream.update_hash(s, data, pos)
|
||||
pos += 1
|
||||
lit_freqs[256] = 1
|
||||
|
||||
|
||||
|
||||
def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt:
|
||||
return (t.CUnsignedInt(p[0]) ^ (t.CUnsignedInt(p[1]) << 5) ^ (t.CUnsignedInt(p[2]) << 10)) & zdef.ZDEFLATE_HASH_MASK
|
||||
|
||||
|
||||
def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt:
|
||||
for i in range(29):
|
||||
if length <= zdef.zdeflate_len_base[i] + (1 << zdef.zdeflate_len_extra_bits[i]) - 1:
|
||||
return 257 + i
|
||||
return 285
|
||||
|
||||
def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt:
|
||||
for i in range(30):
|
||||
if dist <= zdef.zdeflate_dist_base[i] + (1 << zdef.zdeflate_dist_extra_bits[i]) - 1:
|
||||
return i
|
||||
return 29
|
||||
|
||||
def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR):
|
||||
memset(cl_freqs, 0, 19 * int.__sizeof__())
|
||||
i: t.CInt = 0
|
||||
while i < total:
|
||||
if all_lengths[i] == 0:
|
||||
run: t.CInt = 0
|
||||
while i + run < total and all_lengths[i + run] == 0: run += 1
|
||||
while run > 0:
|
||||
if run >= 11:
|
||||
count: t.CInt = run
|
||||
if count > 138: count = 138
|
||||
cl_freqs[18] += 1
|
||||
run -= count
|
||||
elif run >= 3:
|
||||
count: t.CInt = run
|
||||
if count > 10: count = 10
|
||||
cl_freqs[17] += 1
|
||||
run -= count
|
||||
else:
|
||||
cl_freqs[0] += 1
|
||||
run -= 1
|
||||
while i < total and all_lengths[i] == 0: i += 1
|
||||
else:
|
||||
cl_freqs[all_lengths[i]] += 1
|
||||
val: t.CInt = all_lengths[i]
|
||||
i += 1
|
||||
run: t.CInt = 0
|
||||
while i + run < total and all_lengths[i + run] == val: run += 1
|
||||
while run >= 3:
|
||||
count: t.CInt = run
|
||||
if count > 6: count = 6
|
||||
cl_freqs[16] += 1
|
||||
run -= count
|
||||
i += run
|
||||
|
||||
def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt,
|
||||
w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr):
|
||||
i: t.CInt = 0
|
||||
while i < total:
|
||||
if all_lengths[i] == 0:
|
||||
run: t.CInt = 0
|
||||
while i + run < total and all_lengths[i + run] == 0: run += 1
|
||||
while run > 0:
|
||||
if run >= 11:
|
||||
count: t.CInt = run
|
||||
if count > 138: count = 138
|
||||
cl_tree.encode_symbol(18, w)
|
||||
w.write_bits(count - 11, 7)
|
||||
run -= count
|
||||
elif run >= 3:
|
||||
count: t.CInt = run
|
||||
if count > 10: count = 10
|
||||
cl_tree.encode_symbol(17, w)
|
||||
w.write_bits(count - 3, 3)
|
||||
run -= count
|
||||
else:
|
||||
cl_tree.encode_symbol(0, w)
|
||||
run -= 1
|
||||
while i < total and all_lengths[i] == 0: i += 1
|
||||
else:
|
||||
cl_tree.encode_symbol(all_lengths[i], w)
|
||||
val: t.CInt = all_lengths[i]
|
||||
i += 1
|
||||
run: t.CInt = 0
|
||||
while i + run < total and all_lengths[i + run] == val: run += 1
|
||||
while run >= 3:
|
||||
count: t.CInt = run
|
||||
if count > 6: count = 6
|
||||
cl_tree.encode_symbol(16, w)
|
||||
w.write_bits(count - 3, 2)
|
||||
run -= count
|
||||
i += run
|
||||
|
||||
|
||||
|
||||
def zdeflate_create(pool: memhub.MemManager | t.CPtr, level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr:
|
||||
n: t.CSizeT = zdeflate_stream.__sizeof__()
|
||||
s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(pool, n)
|
||||
if not s: return None
|
||||
memset(s, 0, zdeflate_stream.__sizeof__())
|
||||
s.pool = pool
|
||||
s.writer = zdef.zbit_writer(pool)
|
||||
s.window = BYTEPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE))
|
||||
s.hash_head = INTPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()))
|
||||
s.hash_prev = INTPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()))
|
||||
if not s.window or not s.hash_head or not s.hash_prev:
|
||||
s.destroy()
|
||||
return None
|
||||
memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())
|
||||
memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())
|
||||
s.level = level
|
||||
s.wbits = wbits
|
||||
s.strategy = strategy
|
||||
s.is_finished = 0
|
||||
s.adler = 1
|
||||
if wbits > 0:
|
||||
s.writer.write_zlib_header(wbits, level)
|
||||
elif wbits == 0:
|
||||
s.writer.write_zlib_header(15, level)
|
||||
return s
|
||||
|
||||
|
||||
def zdeflate_one_shot(pool: memhub.MemManager | t.CPtr, data: UINT8PTR, length: t.CSizeT,
|
||||
level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr:
|
||||
s: zdeflate_stream | t.CPtr = zdeflate_create(pool, level, wbits, 8, 0)
|
||||
if not s: return None
|
||||
|
||||
memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())
|
||||
memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())
|
||||
|
||||
s.adler = zchecksum.zchecksum_adler32(data, length, 1)
|
||||
|
||||
if length == 0:
|
||||
s.writer.write_bits(1, 1)
|
||||
s.writer.write_bits(1, 2)
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
lit_tree.build_fixed_lit_tree()
|
||||
lit_tree.encode_symbol(256, c.Addr(s.writer))
|
||||
else:
|
||||
s.compress_block(data, length, 1)
|
||||
|
||||
s.is_finished = 1
|
||||
|
||||
if wbits >= 0:
|
||||
s.writer.align()
|
||||
adler: t.CUInt32T = s.adler
|
||||
s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF
|
||||
s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF
|
||||
s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF
|
||||
s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF
|
||||
s.writer.byte_pos += 4
|
||||
c.Set(c.Deref(out_len), s.writer.total())
|
||||
result: UINT8PTR = UINT8PTR(zdef.zdef_alloc(pool, c.Deref(out_len)))
|
||||
if result: memcpy(result, s.writer.buf, c.Deref(out_len))
|
||||
s.destroy()
|
||||
return result
|
||||
@@ -0,0 +1,356 @@
|
||||
#include <string.h>
|
||||
from stdint import *
|
||||
import zlib.zdef as zdef
|
||||
import memhub
|
||||
import t, c
|
||||
|
||||
|
||||
ZHUFF_MAX_CODES: t.CDefine = 288
|
||||
ZHUFF_MAX_BITS: t.CDefine = 15
|
||||
|
||||
class zhuff_code:
|
||||
code: UINT
|
||||
bits: t.CInt
|
||||
|
||||
@t.Object
|
||||
class zhuff_tree:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
codes: t.CArray[zhuff_code, ZHUFF_MAX_CODES]
|
||||
count: t.CInt
|
||||
max_bits: t.CInt
|
||||
|
||||
def __init__(self):
|
||||
self.pool = None
|
||||
|
||||
def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt):
|
||||
lengths: t.CArray[t.CInt, ZHUFF_MAX_CODES]
|
||||
bl_count: t.CArray[t.CInt, ZHUFF_MAX_BITS + 1]
|
||||
next_code: t.CArray[UINT, ZHUFF_MAX_BITS + 1]
|
||||
self.count = count
|
||||
self.max_bits = max_bits
|
||||
self.build_code_lengths(lengths, freqs, count, max_bits)
|
||||
memset(bl_count, 0, bl_count.__sizeof__())
|
||||
for i in range(count):
|
||||
if lengths[i] > 0:
|
||||
bl_count[lengths[i]] += 1
|
||||
code: t.CUnsignedInt = 0
|
||||
next_code[0] = 0
|
||||
for bits in range(1, max_bits + 1):
|
||||
code = (code + bl_count[bits - 1]) << 1
|
||||
next_code[bits] = code
|
||||
for i in range(count):
|
||||
self.codes[i].bits = lengths[i]
|
||||
if lengths[i] > 0:
|
||||
self.codes[i].code = next_code[lengths[i]]
|
||||
next_code[lengths[i]] += 1
|
||||
else:
|
||||
self.codes[i].code = 0
|
||||
|
||||
def build_fixed_lit_tree(self):
|
||||
lengths: t.CArray[t.CInt, 288]
|
||||
bl_count: t.CArray[t.CInt, 16]
|
||||
next_code: t.CArray[t.CUnsignedInt, 16]
|
||||
self.get_fixed_lit_lengths(lengths)
|
||||
memset(bl_count, 0, bl_count.__sizeof__())
|
||||
for i in range(288):
|
||||
if lengths[i] > 0:
|
||||
bl_count[lengths[i]] += 1
|
||||
code: t.CUnsignedInt = 0
|
||||
next_code[0] = 0
|
||||
for bits in range(1, 9 + 1):
|
||||
code = (code + bl_count[bits - 1]) << 1
|
||||
next_code[bits] = code
|
||||
self.count = 288
|
||||
self.max_bits = 9
|
||||
for i in range(288):
|
||||
self.codes[i].bits = lengths[i]
|
||||
if lengths[i] > 0:
|
||||
self.codes[i].code = next_code[lengths[i]]
|
||||
next_code[lengths[i]] += 1
|
||||
else:
|
||||
self.codes[i].code = 0
|
||||
|
||||
def build_fixed_dist_tree(self):
|
||||
lengths: t.CArray[t.CInt, 32]
|
||||
bl_count: t.CArray[t.CInt, 16]
|
||||
next_code: t.CArray[t.CUnsignedInt, 16]
|
||||
self.get_fixed_dist_lengths(lengths)
|
||||
memset(bl_count, 0, bl_count.__sizeof__())
|
||||
for i in range(32):
|
||||
if lengths[i] > 0:
|
||||
bl_count[lengths[i]] += 1
|
||||
code: t.CUnsignedInt = 0
|
||||
next_code[0] = 0
|
||||
for bits in range(1, 5 + 1):
|
||||
code = (code + bl_count[bits - 1]) << 1
|
||||
next_code[bits] = code
|
||||
self.count = 32
|
||||
self.max_bits = 5
|
||||
for i in range(32):
|
||||
self.codes[i].bits = lengths[i]
|
||||
if lengths[i] > 0:
|
||||
self.codes[i].code = next_code[lengths[i]]
|
||||
next_code[lengths[i]] += 1
|
||||
else:
|
||||
self.codes[i].code = 0
|
||||
|
||||
def encode_symbol(self, symbol: int, writer: zdef.zbit_writer | t.CPtr):
|
||||
if symbol < 0 or symbol >= self.count:
|
||||
return
|
||||
if self.codes[symbol].bits == 0:
|
||||
return
|
||||
writer.write_bits_rev(self.codes[symbol].code, self.codes[symbol].bits)
|
||||
|
||||
|
||||
def build_code_lengths(self, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt):
|
||||
bl_count: t.CArray[t.CInt, ZHUFF_MAX_BITS + 2]
|
||||
sort_count: t.CInt = 0
|
||||
memset(bl_count, 0, bl_count.__sizeof__())
|
||||
memset(lengths, 0, int.__sizeof__() * count)
|
||||
for i in range(count):
|
||||
if freqs[i] > 0:
|
||||
sort_count += 1
|
||||
if sort_count == 0: return
|
||||
if sort_count == 1:
|
||||
for i in range(count):
|
||||
if freqs[i] > 0:
|
||||
lengths[i] = 1
|
||||
return
|
||||
items: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__()))
|
||||
item_freqs: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__()))
|
||||
idx: t.CInt = 0
|
||||
for i in range(count):
|
||||
if freqs[i] > 0:
|
||||
items[idx] = i
|
||||
item_freqs[idx] = freqs[i]
|
||||
idx += 1
|
||||
for i in range(sort_count):
|
||||
key_item: t.CInt = items[i]
|
||||
key_freq: t.CInt = item_freqs[i]
|
||||
j: t.CInt = i - 1
|
||||
while j >= 0 and item_freqs[j] > key_freq:
|
||||
items[j + 1] = items[j]
|
||||
item_freqs[j + 1] = item_freqs[j]
|
||||
j -= 1
|
||||
items[j + 1] = key_item
|
||||
item_freqs[j + 1] = key_freq
|
||||
parent: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count * 2) * int.__sizeof__()))
|
||||
for i in range(sort_count * 2):
|
||||
parent[i] = -1
|
||||
heap: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count + 1) * int.__sizeof__()))
|
||||
heap_size: t.CInt = 0
|
||||
for i in range(sort_count):
|
||||
heap[heap_size] = i
|
||||
heap_size += 1
|
||||
pos: t.CInt = heap_size - 1
|
||||
while pos > 0:
|
||||
par: t.CInt = (pos - 1) / 2
|
||||
if item_freqs[heap[par]] > item_freqs[heap[pos]]:
|
||||
tmp: t.CInt = heap[par]
|
||||
heap[par] = heap[pos]
|
||||
heap[pos] = tmp
|
||||
pos = par
|
||||
else: break
|
||||
combined_freq: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count * 2) * int.__sizeof__()))
|
||||
for i in range(sort_count):
|
||||
combined_freq[i] = item_freqs[i]
|
||||
internal: t.CInt = sort_count
|
||||
while heap_size > 1:
|
||||
a: t.CInt = heap[0]
|
||||
heap[0] = heap[heap_size - 1]
|
||||
heap_size -= 1
|
||||
pos: t.CInt = 0
|
||||
while True:
|
||||
left: t.CInt = 2 * pos + 1
|
||||
right: t.CInt = 2 * pos + 2
|
||||
smallest: t.CInt = pos
|
||||
if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]:
|
||||
smallest = left
|
||||
if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]:
|
||||
smallest = right
|
||||
if smallest != pos:
|
||||
tmp: t.CInt = heap[pos]
|
||||
heap[pos] = heap[smallest]
|
||||
heap[smallest] = tmp
|
||||
pos = smallest
|
||||
else: break
|
||||
b: t.CInt = heap[0]
|
||||
heap[0] = heap[heap_size - 1]
|
||||
heap_size -= 1
|
||||
pos = 0
|
||||
while True:
|
||||
left: t.CInt = 2 * pos + 1
|
||||
right: t.CInt = 2 * pos + 2
|
||||
smallest: t.CInt = pos
|
||||
if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]:
|
||||
smallest = left
|
||||
if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]:
|
||||
smallest = right
|
||||
if smallest != pos:
|
||||
tmp: t.CInt = heap[pos]
|
||||
heap[pos] = heap[smallest]
|
||||
heap[smallest] = tmp
|
||||
pos = smallest
|
||||
else: break
|
||||
if internal >= sort_count * 2 - 1: break
|
||||
combined_freq[internal] = combined_freq[a] + combined_freq[b]
|
||||
parent[a] = internal
|
||||
parent[b] = internal
|
||||
heap[heap_size] = internal
|
||||
heap_size += 1
|
||||
pos = heap_size - 1
|
||||
while pos > 0:
|
||||
par: t.CInt = (pos - 1) / 2
|
||||
if combined_freq[heap[par]] > combined_freq[heap[pos]]:
|
||||
tmp: t.CInt = heap[par]
|
||||
heap[par] = heap[pos]
|
||||
heap[pos] = tmp
|
||||
pos = par
|
||||
else: break
|
||||
internal += 1
|
||||
for i in range(sort_count):
|
||||
node: t.CInt = i
|
||||
length: t.CInt = 0
|
||||
while parent[node] >= 0:
|
||||
length += 1
|
||||
node = parent[node]
|
||||
lengths[items[i]] = length
|
||||
memset(bl_count, 0, bl_count.__sizeof__())
|
||||
for i in range(count):
|
||||
if lengths[i] > 0:
|
||||
bl_count[lengths[i]] += 1
|
||||
overflow: t.CInt = 0
|
||||
for i in range(count):
|
||||
if lengths[i] > max_bits:
|
||||
overflow += 1
|
||||
bl_count[lengths[i]] -= 1
|
||||
lengths[i] = max_bits
|
||||
bl_count[max_bits] += 1
|
||||
while overflow > 0:
|
||||
bits: t.CInt = max_bits - 1
|
||||
while bits > 0 and bl_count[bits] == 0:
|
||||
bits -= 1
|
||||
if bits == 0: break
|
||||
bl_count[bits] -= 1
|
||||
bl_count[bits + 1] += 2
|
||||
bl_count[max_bits] -= 1
|
||||
overflow -= 2
|
||||
sorted_items: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__()))
|
||||
si: t.CInt = 0
|
||||
for i in range(count):
|
||||
if freqs[i] > 0:
|
||||
sorted_items[si] = i
|
||||
si += 1
|
||||
for i in range(si - 1):
|
||||
for j in range(i + 1, si):
|
||||
if lengths[sorted_items[i]] < lengths[sorted_items[j]]:
|
||||
tmp: t.CInt = sorted_items[i]
|
||||
sorted_items[i] = sorted_items[j]
|
||||
sorted_items[j] = tmp
|
||||
sidx: t.CInt = 0
|
||||
for bits in range(max_bits, 1, -1):
|
||||
n: t.CInt = bl_count[bits]
|
||||
while n > 0 and sidx < si:
|
||||
lengths[sorted_items[sidx]] = bits
|
||||
sidx += 1
|
||||
n -= 1
|
||||
zdef.zdef_free(self.pool, sorted_items)
|
||||
zdef.zdef_free(self.pool, heap)
|
||||
zdef.zdef_free(self.pool, parent)
|
||||
zdef.zdef_free(self.pool, combined_freq)
|
||||
zdef.zdef_free(self.pool, item_freqs)
|
||||
zdef.zdef_free(self.pool, items)
|
||||
|
||||
def get_fixed_lit_lengths(self, lengths: INTPTR):
|
||||
for i in range( 0, 143 + 1): lengths[i] = 8
|
||||
for i in range(143 + 1, 255 + 1): lengths[i] = 9
|
||||
for i in range(255 + 1, 279 + 1): lengths[i] = 7
|
||||
for i in range(279 + 1, 287 + 1): lengths[i] = 8
|
||||
|
||||
def get_fixed_dist_lengths(self, lengths: INTPTR):
|
||||
for i in range(32):
|
||||
lengths[i] = 5
|
||||
|
||||
def build_tree_from_lengths(self, lengths: INTPTR, count: t.CInt, max_bits: t.CInt):
|
||||
bl_count: t.CArray[t.CInt, 16]
|
||||
next_code: t.CArray[t.CUnsignedInt, 16]
|
||||
|
||||
memset(bl_count, 0, bl_count.__sizeof__())
|
||||
for i in range(count):
|
||||
if lengths[i] > 0:
|
||||
bl_count[lengths[i]] += 1
|
||||
|
||||
code: UINT = 0
|
||||
next_code[0] = 0
|
||||
for bits in range(1, max_bits + 1):
|
||||
code = (code + bl_count[bits - 1]) << 1
|
||||
next_code[bits] = code
|
||||
|
||||
self.count = count
|
||||
self.max_bits = max_bits
|
||||
for i in range(count):
|
||||
self.codes[i].bits = lengths[i]
|
||||
if lengths[i] > 0:
|
||||
self.codes[i].code = next_code[lengths[i]]
|
||||
next_code[lengths[i]] += 1
|
||||
else:
|
||||
self.codes[i].code = 0
|
||||
|
||||
|
||||
class zhuff_decode_node:
|
||||
children: t.CArray[t.CInt, 2]
|
||||
symbol: t.CInt
|
||||
|
||||
|
||||
@t.Object
|
||||
class zhuff_decode_tree:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
nodes: t.CArray[zhuff_decode_node, 2 * ZHUFF_MAX_CODES]
|
||||
node_count: t.CInt
|
||||
root: t.CInt
|
||||
|
||||
def __init__(self):
|
||||
self.pool = None
|
||||
|
||||
def build_decode_tree(self, ht: zhuff_tree | t.CPtr):
|
||||
self.node_count = 1
|
||||
self.root = 0
|
||||
self.nodes[0].children[0] = -1
|
||||
self.nodes[0].children[1] = -1
|
||||
self.nodes[0].symbol = -1
|
||||
for i in range(ht.count):
|
||||
if ht.codes[i].bits == 0: continue
|
||||
node: int = 0
|
||||
for bit in range(ht.codes[i].bits - 1, -1, -1):
|
||||
dir: t.CInt = (ht.codes[i].code >> bit) & 1
|
||||
if bit > 0:
|
||||
# Internal node: traverse or create
|
||||
if self.nodes[node].children[dir] == -1:
|
||||
new_node: int = self.node_count
|
||||
self.node_count += 1
|
||||
self.nodes[new_node].children[0] = -1
|
||||
self.nodes[new_node].children[1] = -1
|
||||
self.nodes[new_node].symbol = -1
|
||||
self.nodes[node].children[dir] = new_node
|
||||
node = self.nodes[node].children[dir]
|
||||
else:
|
||||
# Leaf: bit 0 - set symbol on the child
|
||||
if self.nodes[node].children[dir] == -1:
|
||||
leaf: int = self.node_count
|
||||
self.node_count += 1
|
||||
self.nodes[leaf].children[0] = -1
|
||||
self.nodes[leaf].children[1] = -1
|
||||
self.nodes[leaf].symbol = i
|
||||
self.nodes[node].children[dir] = leaf
|
||||
else:
|
||||
self.nodes[self.nodes[node].children[dir]].symbol = i
|
||||
|
||||
def decode_symbol(self, reader: zdef.zbit_reader | t.CPtr) -> t.CInt:
|
||||
node: int = self.root
|
||||
while self.nodes[node].symbol == -1:
|
||||
bit: t.CUnsignedInt
|
||||
if reader.read_bits(1, c.Addr(bit)) != 0: return -1
|
||||
dir: t.CInt = t.CInt(bit)
|
||||
if self.nodes[node].children[dir] == -1: return -1
|
||||
node = self.nodes[node].children[dir]
|
||||
return self.nodes[node].symbol
|
||||
@@ -0,0 +1,456 @@
|
||||
from stdint import *
|
||||
import zlib.zchecksum as zchecksum
|
||||
import zlib.zdef as zdef
|
||||
import zlib.zhuff as zhuff
|
||||
import string
|
||||
import memhub
|
||||
import t, c
|
||||
|
||||
|
||||
@t.Object
|
||||
class zinflate_stream:
|
||||
pool: memhub.MemManager | t.CPtr
|
||||
reader: zdef.zbit_reader
|
||||
|
||||
window: BYTEPTR
|
||||
window_pos: t.CInt
|
||||
window_size: t.CInt
|
||||
|
||||
wbits: t.CInt
|
||||
is_finished: t.CInt
|
||||
is_initialized: t.CInt
|
||||
|
||||
header_parsed: t.CInt
|
||||
is_gzip: t.CInt
|
||||
|
||||
adler: t.CUInt32T
|
||||
crc: t.CUInt32T
|
||||
|
||||
output: BYTEPTR
|
||||
output_len: t.CSizeT
|
||||
output_cap: t.CSizeT
|
||||
|
||||
input_data: t.CConst | BYTEPTR
|
||||
input_len: t.CSizeT
|
||||
input_pos: t.CSizeT
|
||||
|
||||
max_length: t.CSizeT
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def output_byte(self, byte: BYTE):
|
||||
if self.max_length > 0 and self.output_len >= self.max_length: return
|
||||
|
||||
if self.output_len >= self.output_cap:
|
||||
new_cap: t.CSizeT = self.output_cap * 2
|
||||
if new_cap < 256: new_cap = 256
|
||||
new_buf: BYTEPTR = BYTEPTR(zdef.zdef_alloc(self.pool, new_cap))
|
||||
if not new_buf: return
|
||||
memcpy(new_buf, self.output, self.output_len)
|
||||
zdef.zdef_free(self.pool, self.output)
|
||||
self.output = new_buf
|
||||
self.output_cap = new_cap
|
||||
self.output[self.output_len] = byte
|
||||
self.output_len += 1
|
||||
self.window[self.window_pos & (zdef.ZDEFLATE_WINDOW_SIZE - 1)] = byte
|
||||
self.window_pos += 1
|
||||
|
||||
|
||||
def parse_header(self) -> t.CInt:
|
||||
if self.header_parsed: return 0
|
||||
if self.wbits < 0:
|
||||
self.header_parsed = 1
|
||||
self.is_gzip = 0
|
||||
return 0
|
||||
if self.input_pos + 2 > self.input_len: return -3
|
||||
b0: BYTE = self.input_data[self.input_pos]
|
||||
b1: BYTE = self.input_data[self.input_pos + 1]
|
||||
if b0 == 0x1F and b1 == 0x8B:
|
||||
self.is_gzip = 1
|
||||
if self.input_pos + 10 > self.input_len: return -3
|
||||
self.input_pos += 10
|
||||
flg: BYTE = self.input_data[self.input_pos - 6]
|
||||
if flg & 0x04:
|
||||
if self.input_pos + 2 > self.input_len: return -3
|
||||
xlen: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8)
|
||||
self.input_pos += 2 + xlen
|
||||
if flg & 0x08:
|
||||
while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1
|
||||
self.input_pos += 1
|
||||
if flg & 0x10:
|
||||
while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1
|
||||
self.input_pos += 1
|
||||
if flg & 0x02:
|
||||
self.input_pos += 2
|
||||
if self.input_pos > self.input_len: return -3
|
||||
else:
|
||||
self.is_gzip = 0
|
||||
if (b0 * 256 + b1) % 31 != 0: return -3
|
||||
cm: t.CInt = b0 & 0x0F
|
||||
if cm != 8: return -3
|
||||
self.input_pos += 2
|
||||
self.header_parsed = 1
|
||||
return 0
|
||||
|
||||
|
||||
def read_bits_from_input(self, nbits: t.CInt, out: UINTPTR) -> t.CInt:
|
||||
val: UINT = 0
|
||||
for i in range(nbits):
|
||||
if self.input_pos >= self.input_len: return -3
|
||||
if self.input_data[self.input_pos] & (UINT(1) << (self.reader.bit_pos)):
|
||||
val |= (UINT(1) << i)
|
||||
self.reader.bit_pos += 1
|
||||
if self.reader.bit_pos == 8:
|
||||
self.reader.bit_pos = 0
|
||||
self.input_pos += 1
|
||||
c.Set(c.Deref(out), val)
|
||||
return 0
|
||||
|
||||
|
||||
def read_huffman(self, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt:
|
||||
node: int = dt.root
|
||||
while dt.nodes[node].symbol == -1:
|
||||
bit: UINT
|
||||
if self.read_bits_from_input(1, c.Addr(bit)) != 0: return -1
|
||||
dir: int = t.CInt(bit)
|
||||
if dt.nodes[node].children[dir] == -1: return -3
|
||||
node = dt.nodes[node].children[dir]
|
||||
return dt.nodes[node].symbol
|
||||
|
||||
def inflate_block_stored(self) -> t.CInt:
|
||||
if self.reader.bit_pos != 0:
|
||||
self.reader.bit_pos = 0
|
||||
self.input_pos += 1
|
||||
if self.input_pos + 4 > self.input_len: return -3
|
||||
length: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8)
|
||||
nlen: UINT = self.input_data[self.input_pos + 2] | (self.input_data[self.input_pos + 3] << 8)
|
||||
self.input_pos += 4
|
||||
if (length ^ nlen) != 0xFFFF: return -3
|
||||
if self.input_pos + length > self.input_len: return -3
|
||||
i: t.CUnsignedInt
|
||||
for i in range(length):
|
||||
self.output_byte(self.input_data[self.input_pos])
|
||||
self.input_pos += 1
|
||||
return 0
|
||||
|
||||
|
||||
def inflate_block_fixed(self) -> t.CInt:
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
dist_tree = zhuff.zhuff_tree()
|
||||
lit_tree.build_fixed_lit_tree()
|
||||
dist_tree.build_fixed_dist_tree()
|
||||
|
||||
lit_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(self.pool, zhuff.zhuff_decode_tree.__sizeof__())
|
||||
dist_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(self.pool, zhuff.zhuff_decode_tree.__sizeof__())
|
||||
if not lit_dt or not dist_dt:
|
||||
if lit_dt: zdef.zdef_free(self.pool, lit_dt)
|
||||
if dist_dt: zdef.zdef_free(self.pool, dist_dt)
|
||||
return -4
|
||||
memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__())
|
||||
memset(dist_dt, 0, zhuff.zhuff_decode_tree.__sizeof__())
|
||||
lit_dt.build_decode_tree(c.Addr(lit_tree))
|
||||
dist_dt.build_decode_tree(c.Addr(dist_tree))
|
||||
|
||||
result: t.CInt = 0
|
||||
while True:
|
||||
if self.max_length > 0 and self.output_len >= self.max_length: break
|
||||
|
||||
sym: t.CInt = self.read_huffman(lit_dt)
|
||||
if sym < 0:
|
||||
result = -3
|
||||
break
|
||||
if sym == 256: break
|
||||
if sym < 256:
|
||||
self.output_byte(BYTE(sym))
|
||||
else:
|
||||
len_idx: t.CInt = sym - 257
|
||||
if len_idx < 0 or len_idx >= 29:
|
||||
result = -3
|
||||
break
|
||||
length: t.CInt = zdef.zdeflate_len_base[len_idx]
|
||||
extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx]
|
||||
if extra > 0:
|
||||
extra_val: UINT
|
||||
if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0:
|
||||
result = -3
|
||||
break
|
||||
length += extra_val
|
||||
|
||||
dist_sym: t.CInt = self.read_huffman(dist_dt)
|
||||
if dist_sym < 0 or dist_sym >= 30:
|
||||
result = -3
|
||||
break
|
||||
dist: t.CInt = zdef.zdeflate_dist_base[dist_sym]
|
||||
extra = zdef.zdeflate_dist_extra_bits[dist_sym]
|
||||
if extra > 0:
|
||||
extra_val: UINT
|
||||
if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0:
|
||||
result = -3
|
||||
break
|
||||
dist += extra_val
|
||||
|
||||
for i in range(length):
|
||||
if self.max_length > 0 and self.output_len >= self.max_length: break
|
||||
src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1)
|
||||
byte: BYTE = self.window[src_pos]
|
||||
self.output_byte(byte)
|
||||
|
||||
zdef.zdef_free(self.pool, lit_dt)
|
||||
zdef.zdef_free(self.pool, dist_dt)
|
||||
return result
|
||||
|
||||
|
||||
def inflate_block_dynamic(self) -> t.CInt:
|
||||
hlit_val: UINT
|
||||
hdist_val: UINT
|
||||
hclen_val: UINT
|
||||
if self.read_bits_from_input(5, c.Addr(hlit_val)) != 0: return -3
|
||||
if self.read_bits_from_input(5, c.Addr(hdist_val)) != 0: return -3
|
||||
if self.read_bits_from_input(4, c.Addr(hclen_val)) != 0: return -3
|
||||
|
||||
hlit: t.CInt = t.CInt(hlit_val) + 257
|
||||
hdist: t.CInt = t.CInt(hdist_val) + 1
|
||||
hclen: t.CInt = t.CInt(hclen_val) + 4
|
||||
|
||||
cl_lengths: t.CArray[t.CInt, 19]
|
||||
memset(cl_lengths, 0, cl_lengths.__sizeof__())
|
||||
for i in range(hclen):
|
||||
len_val: UINT
|
||||
if self.read_bits_from_input(3, c.Addr(len_val)) != 0: return -3
|
||||
cl_lengths[zdef.zdeflate_codelen_order[i]] = t.CInt(len_val)
|
||||
|
||||
cl_tree = zhuff.zhuff_tree()
|
||||
cl_tree.build_tree_from_lengths(cl_lengths, 19, 7)
|
||||
|
||||
cl_dt = zhuff.zhuff_decode_tree()
|
||||
cl_dt.build_decode_tree(c.Addr(cl_tree))
|
||||
|
||||
total: t.CInt = hlit + hdist
|
||||
all_lengths: t.CInt | t.CPtr = zdef.zdef_alloc(self.pool, total * int.__sizeof__())
|
||||
if not all_lengths: return -4
|
||||
|
||||
idx: t.CInt = 0
|
||||
while idx < total:
|
||||
sym: t.CInt = self.read_huffman(c.Addr(cl_dt))
|
||||
if sym < 0 or sym > 18:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
if sym < 16:
|
||||
all_lengths[idx] = sym
|
||||
idx += 1
|
||||
elif sym == 16:
|
||||
rep: UINT
|
||||
if self.read_bits_from_input(2, c.Addr(rep)) != 0:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
rep += 3
|
||||
if idx == 0 or idx + rep > total:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
prev: t.CInt = all_lengths[idx - 1]
|
||||
i: t.CUnsignedInt
|
||||
for i in range(rep):
|
||||
all_lengths[idx] = prev
|
||||
idx += 1
|
||||
elif sym == 17:
|
||||
rep: t.CUnsignedInt
|
||||
if self.read_bits_from_input(3, c.Addr(rep)) != 0:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
rep += 3
|
||||
if idx + rep > total:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
i: t.CUnsignedInt
|
||||
for i in range(rep):
|
||||
all_lengths[idx] = 0
|
||||
idx += 1
|
||||
else:
|
||||
rep: t.CUnsignedInt
|
||||
if self.read_bits_from_input(7, c.Addr(rep)) != 0:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
rep += 11
|
||||
if idx + rep > total:
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
return -3
|
||||
i: t.CUnsignedInt
|
||||
for i in range(rep):
|
||||
all_lengths[idx] = 0
|
||||
idx += 1
|
||||
|
||||
lit_tree = zhuff.zhuff_tree()
|
||||
dist_tree = zhuff.zhuff_tree()
|
||||
|
||||
lit_lengths: t.CArray[t.CInt, 288]
|
||||
memset(lit_lengths, 0, lit_lengths.__sizeof__())
|
||||
for i in range(hlit):
|
||||
lit_lengths[i] = all_lengths[i]
|
||||
lit_tree.build_tree_from_lengths(lit_lengths, hlit, zdef.ZDEFLATE_MAX_BITS)
|
||||
|
||||
dist_lengths: t.CArray[t.CInt, 32]
|
||||
memset(dist_lengths, 0, dist_lengths.__sizeof__())
|
||||
for i in range(hdist):
|
||||
dist_lengths[i] = all_lengths[hlit + i]
|
||||
dist_tree.build_tree_from_lengths(dist_lengths, hdist, zdef.ZDEFLATE_MAX_BITS)
|
||||
|
||||
zdef.zdef_free(self.pool, all_lengths)
|
||||
|
||||
lit_dt = zhuff.zhuff_decode_tree()
|
||||
dist_dt = zhuff.zhuff_decode_tree()
|
||||
lit_dt.build_decode_tree(c.Addr(lit_tree))
|
||||
dist_dt.build_decode_tree(c.Addr(dist_tree))
|
||||
|
||||
while True:
|
||||
if self.max_length > 0 and self.output_len >= self.max_length: return 0
|
||||
sym: t.CInt = self.read_huffman(c.Addr(lit_dt))
|
||||
if sym < 0: return -3
|
||||
if sym == 256: return 0
|
||||
if sym < 256:
|
||||
self.output_byte(BYTE(sym))
|
||||
else:
|
||||
len_idx: t.CInt = sym - 257
|
||||
if len_idx < 0 or len_idx >= 29: return -3
|
||||
length: t.CInt = zdef.zdeflate_len_base[len_idx]
|
||||
extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx]
|
||||
if extra > 0:
|
||||
extra_val: UINT
|
||||
if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3
|
||||
length += extra_val
|
||||
dist_sym: t.CInt = self.read_huffman(c.Addr(dist_dt))
|
||||
if dist_sym < 0 or dist_sym >= 30: return -3
|
||||
dist: t.CInt = zdef.zdeflate_dist_base[dist_sym]
|
||||
extra = zdef.zdeflate_dist_extra_bits[dist_sym]
|
||||
if extra > 0:
|
||||
extra_val: UINT
|
||||
if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3
|
||||
dist += extra_val
|
||||
for i in range(length):
|
||||
if self.max_length > 0 and self.output_len >= self.max_length: return 0
|
||||
src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1)
|
||||
byte: BYTE = self.window[src_pos]
|
||||
self.output_byte(byte)
|
||||
|
||||
def inflate_stream(self) -> t.CInt:
|
||||
err: t.CInt = self.parse_header()
|
||||
if err != 0: return err
|
||||
while not self.is_finished:
|
||||
bfinal_val: UINT
|
||||
btype_val: UINT
|
||||
if self.read_bits_from_input(1, c.Addr(bfinal_val)) != 0: return -3
|
||||
if self.read_bits_from_input(2, c.Addr(btype_val)) != 0: return -3
|
||||
bfinal: t.CInt = t.CInt(bfinal_val)
|
||||
btype: t.CInt = t.CInt(btype_val)
|
||||
if btype == 0:
|
||||
err = self.inflate_block_stored()
|
||||
elif btype == 1:
|
||||
err = self.inflate_block_fixed()
|
||||
elif btype == 2:
|
||||
err = self.inflate_block_dynamic()
|
||||
else:
|
||||
return -3
|
||||
if err != 0: return err
|
||||
if bfinal: self.is_finished = 1
|
||||
if self.max_length > 0 and self.output_len >= self.max_length: return 0
|
||||
if self.is_gzip:
|
||||
if self.reader.bit_pos != 0:
|
||||
self.reader.bit_pos = 0
|
||||
self.input_pos += 1
|
||||
if self.input_pos + 8 <= self.input_len:
|
||||
self.crc = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 0) |
|
||||
(t.CUInt32T(self.input_data[self.input_pos + 1]) << 8) |
|
||||
(t.CUInt32T(self.input_data[self.input_pos + 2]) << 16) |
|
||||
(t.CUInt32T(self.input_data[self.input_pos + 3]) << 24))
|
||||
self.input_pos += 8
|
||||
elif self.wbits >= 0:
|
||||
if self.reader.bit_pos != 0:
|
||||
self.reader.bit_pos = 0
|
||||
self.input_pos += 1
|
||||
if self.input_pos + 4 <= self.input_len:
|
||||
self.adler = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 24) |
|
||||
(t.CUInt32T(self.input_data[self.input_pos + 1]) << 16) |
|
||||
(t.CUInt32T(self.input_data[self.input_pos + 2]) << 8) |
|
||||
(t.CUInt32T(self.input_data[self.input_pos + 3]) << 0))
|
||||
self.input_pos += 4
|
||||
return 0
|
||||
|
||||
def decompress(self, data: UINT8PTR, length: t.CSizeT,
|
||||
max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt:
|
||||
if not self.is_initialized: return -2
|
||||
self.input_data = data
|
||||
self.input_len = length
|
||||
self.input_pos = 0
|
||||
self.reader.bit_pos = 0
|
||||
self.output_len = 0
|
||||
self.max_length = max_length
|
||||
err: t.CInt = self.inflate_stream()
|
||||
if err != 0: return err
|
||||
c.Set(c.Deref(out_len), self.output_len)
|
||||
if self.output_len == 0:
|
||||
c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, 1)))
|
||||
else:
|
||||
dst: UINT8PTR = UINT8PTR(zdef.zdef_alloc(self.pool, self.output_len))
|
||||
c.Set(c.Deref(out), dst)
|
||||
if dst:
|
||||
memcpy(dst, self.output, self.output_len)
|
||||
return 0
|
||||
|
||||
def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt:
|
||||
if not dict: return -2
|
||||
use: t.CSizeT = length
|
||||
if use > zdef.ZDEFLATE_WINDOW_SIZE:
|
||||
dict += length - zdef.ZDEFLATE_WINDOW_SIZE
|
||||
use = zdef.ZDEFLATE_WINDOW_SIZE
|
||||
memcpy(self.window, dict, use)
|
||||
self.window_pos = t.CInt(use)
|
||||
return 0
|
||||
|
||||
def copy(self) -> zinflate_stream | t.CPtr:
|
||||
z: zinflate_stream | t.CPtr = zdef.zdef_alloc(self.pool, zinflate_stream.__sizeof__())
|
||||
if not z: return None
|
||||
memcpy(z, self, zinflate_stream.__sizeof__())
|
||||
z.window = BYTEPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE))
|
||||
z.output = BYTEPTR(zdef.zdef_alloc(self.pool, self.output_cap))
|
||||
if not z.window or not z.output:
|
||||
zinflate_stream.destroy(z)
|
||||
return None
|
||||
memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE)
|
||||
memcpy(z.output, self.output, self.output_cap)
|
||||
return z
|
||||
|
||||
def destroy(self):
|
||||
if not self: return
|
||||
if self.window: zdef.zdef_free(self.pool, self.window)
|
||||
if self.output: zdef.zdef_free(self.pool, self.output)
|
||||
zdef.zdef_free(self.pool, self)
|
||||
|
||||
|
||||
def zinflate_one_shot(pool: memhub.MemManager | t.CPtr, data: UINT8PTR, length: t.CSizeT,
|
||||
wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr:
|
||||
s: zinflate_stream | t.CPtr = zinflate_create(pool, wbits)
|
||||
if not s: return None
|
||||
out: t.CUInt8T | t.CPtr = None
|
||||
err: t.CInt = s.decompress(data, length, 0, c.Addr(out), out_len)
|
||||
s.destroy()
|
||||
if err != 0: return None
|
||||
return out
|
||||
|
||||
|
||||
def zinflate_create(pool: memhub.MemManager | t.CPtr, wbits: t.CInt) -> zinflate_stream | t.CPtr:
|
||||
s: zinflate_stream | t.CPtr = zdef.zdef_alloc(pool, zinflate_stream.__sizeof__())
|
||||
if not s: return None
|
||||
memset(s, 0, zinflate_stream.__sizeof__())
|
||||
s.pool = pool
|
||||
s.wbits = wbits
|
||||
s.is_initialized = 1
|
||||
s.adler = 1
|
||||
s.window = BYTEPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE))
|
||||
s.output = BYTEPTR(zdef.zdef_alloc(pool, 256))
|
||||
s.output_cap = 256
|
||||
s.output_len = 0
|
||||
s.max_length = 0
|
||||
if not s.window or not s.output:
|
||||
s.destroy()
|
||||
return None
|
||||
return s
|
||||
Reference in new issue
Block a user