diff --git a/_dict.vp b/_dict.vp index 98c4bcf..1b51756 100644 --- a/_dict.vp +++ b/_dict.vp @@ -1,4 +1,3 @@ -import t, c import memhub import string import json @@ -28,7 +27,7 @@ class dict: mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size) d: dict = dict(mb) d.set_int("x", 42) - p: t.CPtr = d["x"] + p: rawptr = d["x"] v: int = c.Deref((int*)(p)) # int value stored as i32; read it back with an int* view # Nested dict @@ -82,7 +81,7 @@ class dict: Use typed methods such as set_int / set_str for persistent storage.""" self._set_variant_raw(key, VARIANT_PTR, val) - def _set_variant_raw(self, key: str, vtype: int, ptr: t.CPtr): + def _set_variant_raw(self, key: str, vtype: int, ptr: rawptr): """Internal method: store Variant entry (vtype + ptr). No automatic address resolution.""" idx: sizet = self._find(key) if idx < self.__count__: @@ -143,7 +142,7 @@ class dict: """Store nested dictionary pointer (VARIANT_DICT).""" self._set_variant_raw(key, VARIANT_DICT, val) - def set_list(self, key: str, val: t.CPtr): + def set_list(self, key: str, val: rawptr): """Store nested list pointer (VARIANT_LIST).""" self._set_variant_raw(key, VARIANT_LIST, val) @@ -166,7 +165,7 @@ class dict: vtype_ptr: int* = int*(self.__values__ + idx * _VARIANT_SIZE) return vtype_ptr[0] - def get(self, key: str, default: t.CPtr) -> t.CPtr: + def get(self, key: str, default: rawptr) -> rawptr: """Return value pointer; return default pointer if key does not exist.""" idx: sizet = self._find(key) if idx >= self.__count__: diff --git a/_variant.vp b/_variant.vp index c1b1a4d..5c8df63 100644 --- a/_variant.vp +++ b/_variant.vp @@ -1,6 +1,3 @@ -import t - - # Variant type tags (fixed enumeration + custom pointer type) define VARIANT_NONE = 0 # Untyped / null value define VARIANT_INT = 1 # int (i64) diff --git a/argparse.vp b/argparse.vp index 37b9ed8..88c8658 100644 --- a/argparse.vp +++ b/argparse.vp @@ -1,4 +1,4 @@ -import t, c +import t import string import memhub import stdio @@ -90,14 +90,14 @@ class ParsedArgs: if self._ht.__contains__(name) == 0: return 0 ptr: t.CPtr = self._ht[name] - return c.Deref(int(uint64(ptr), t.CPtr)) + return *(int*(ptr)) def get_bool(self, name: str) -> bool: """Fetch boolean value. Returns false if key not found.""" if self._ht.__contains__(name) == 0: return False - ptr: t.CPtr = self._ht[name] - return c.Deref(int(uint64(ptr), t.CPtr)) != 0 + ptr: rawptr = self._ht[name] + return *(int*(ptr)) != 0 def has(self, name: str) -> bool: """Check whether specified key exists.""" @@ -128,11 +128,11 @@ class ArgumentParser: __mbuddy__: memhub.MemBuddy* def __new__(self, prog: str = "", description: str = "", - pool: memhub.MemBuddy* = None) -> t.CPtr: + pool: memhub.MemBuddy* = None) -> rawptr: mb: memhub.MemBuddy* = pool if mb is None: mb = _mbuddy - ret: t.CPtr = mb.alloc(40) + ret: rawptr = mb.alloc(40) return ret def __init__(self, prog: str = "", description: str = "", diff --git a/ast/__init__.vp b/ast/__init__.vp index 01e3e97..5b2309f 100644 --- a/ast/__init__.vp +++ b/ast/__init__.vp @@ -1,7 +1,6 @@ -import t, c from stdint import * import memhub -import string + # Import submodule from .tokens import ( @@ -37,6 +36,10 @@ from .exprs import ( Constant, NamedExpr, Attribute, Subscript, Starred, Name, List, Tuple, Slice, Call, Compare, OpNode, + # M2.4 `new` 描述符分配节点与描述符常量 + New, + NEW_SRC_DEFAULT, NEW_SRC_STACK, NEW_SRC_HEAP, NEW_SRC_MEMGR, + NEW_LIFE_DEFAULT, NEW_LIFE_SLIFE, NEW_LIFE_HLIFE, name_get_id, constant_get_str_val, binop_get_left, binop_get_right, diff --git a/ast/astaux.vp b/ast/astaux.vp index 9b7dc16..b691876 100644 --- a/ast/astaux.vp +++ b/ast/astaux.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/ast/base.vp b/ast/base.vp index 5639543..cafb4bf 100644 --- a/ast/base.vp +++ b/ast/base.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string @@ -44,6 +43,8 @@ enum ASTKind: MatchClass, MatchStar, MatchAs, MatchOr # Soft keyword statement (appended last to keep existing enum values unchanged) FallThrough + # `new` 描述符分配表达式(M2.4;同样只在枚举尾部追加,既有取值不变) + New # ============================================================ diff --git a/ast/exprs.vp b/ast/exprs.vp index 3dac91d..bc72ab0 100644 --- a/ast/exprs.vp +++ b/ast/exprs.vp @@ -1,8 +1,6 @@ -import t, c from stdint import * import memhub import string -import stdio from .base import ( AST, ExprNode, ASTKind, ASTCtx, OpKind, _init_ast, _copy_str, _set_parent_list, @@ -326,6 +324,75 @@ class Call(ExprNode): return pos +# ============================================================ +# New Node(M2.4:`new` 描述符分配) +# ============================================================ +# 两条正交轴,各取其一;顺序无关;重复/冲突在解析期即报错。 +# 来源 SourceKind:缺省 = heap(D3) +define NEW_SRC_DEFAULT = 0 +define NEW_SRC_STACK = 1 +define NEW_SRC_HEAP = 2 +define NEW_SRC_MEMGR = 3 +# 生命期 LifeKind:缺省由来源决定(stack→slife,heap/memgr→hlife) +define NEW_LIFE_DEFAULT = 0 +define NEW_LIFE_SLIFE = 1 +define NEW_LIFE_HLIFE = 2 + + +class New(ExprNode): + """New(Source: CInt, Life: CInt, memgr: AST | CPtr, func: AST, args: list[AST | CPtr])""" + Source: int # SourceKind(NEW_SRC_*) + Life: int # LifeKind(NEW_LIFE_*) + memgr: AST* # `memgr(x)` 的 x;无 memgr 描述符时为 None + func: AST* # 被构造的类型/可调用(`new ... T(args)` 里的 T) + args: list[AST*]* + + def __new__(self, pool: memhub.MemManager*, + Source: int, + Life: int, + memgr: AST*, + func: AST*, + args: list[AST*]*): + ptr: New* = pool.alloc(New.__sizeof__()) + if ptr: string.memset(ptr, 0, New.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager*, + Source: int, + Life: int, + memgr: AST*, + func: AST*, + args: list[AST*]*): + _init_ast(self, pool, 0, 0) + self.Source = Source + self.Life = Life + self.memgr = memgr + self.func = func + self.args = args + _set_parent_list(args, self) + + def kind(self) -> int: + return ASTKind.New + + def type_name(self) -> str: + return "New" + + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: + pos = _emit(buf, size, pos, "New(") + if self.memgr is not None: + pos = _emit(buf, size, pos, ", memgr=") + pos = self.memgr.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", func=") + if self.func is not None: + pos = self.func.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", args=") + pos = _dump_list(self.args, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + # ============================================================ # BoolOp Node # ============================================================ diff --git a/ast/lexer.vp b/ast/lexer.vp index 3fe26d9..40cd688 100644 --- a/ast/lexer.vp +++ b/ast/lexer.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/ast/match.vp b/ast/match.vp index 88f6f76..b683c7f 100644 --- a/ast/match.vp +++ b/ast/match.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/ast/parser.vp b/ast/parser.vp index 32d8058..72f4cbc 100644 --- a/ast/parser.vp +++ b/ast/parser.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string @@ -17,7 +16,9 @@ from .exprs import ( ListComp, SetComp, DictComp, GeneratorExp, Await, Yield, YieldFrom, FormattedValue, JoinedStr, Constant, NamedExpr, Attribute, Subscript, Starred, Name, - List, Tuple, Slice, Call, Compare, OpNode, + List, Tuple, Slice, Call, Compare, OpNode, New, + NEW_SRC_DEFAULT, NEW_SRC_STACK, NEW_SRC_HEAP, NEW_SRC_MEMGR, + NEW_LIFE_DEFAULT, NEW_LIFE_SLIFE, NEW_LIFE_HLIFE, ) from .stmts import ( Module, Expression, Interactive, FunctionType, @@ -1780,6 +1781,90 @@ def _parse_slice(ps: Parser*) -> AST*: return lower +def _is_new_expr(ps: Parser*) -> int: + """是否 `new` 描述符表达式(软关键字判定)。 + + `new` 是软关键字:只有紧跟一个**普通名**(描述符 hlife/slife/stack/heap/memgr 或类型名 + `T(args)`)时才当关键字。`new = 1`、`new.x`、`new(1)`、`for new in ...` 都仍是标识符。 + """ + if _is_named_soft(ps, "new") == 0: return 0 + nxt: Token* = ps.cur.next + if nxt is None: return 0 + if nxt.type != TokenType.Name: return 0 + if nxt.kw_subtype != Keyword.NotKeyword: return 0 + return 1 + + +def _parse_new_expr(ps: Parser*) -> AST*: + """`new [Descriptor...] T(args)`:描述符顺序无关、各轴最多一次(冲突即报错)。 + + 结果恒为 `T*`;来源缺省 = heap(D3),生命期缺省由来源决定(语义侧落地)。 + """ + lineno: int = _cur_lineno(ps) + col: int = _cur_col(ps) + _advance(ps) # 吃掉 `new` + src: int = NEW_SRC_DEFAULT + life: int = NEW_LIFE_DEFAULT + memgr_arg: AST* = None + while True: + if _is_named_soft(ps, "hlife") != 0: + if life != NEW_LIFE_DEFAULT: + _record_parse_err(ps) + ps.error_count += 1 + return None + life = NEW_LIFE_HLIFE + _advance(ps) + continue + if _is_named_soft(ps, "slife") != 0: + if life != NEW_LIFE_DEFAULT: + _record_parse_err(ps) + ps.error_count += 1 + return None + life = NEW_LIFE_SLIFE + _advance(ps) + continue + if _is_named_soft(ps, "stack") != 0: + if src != NEW_SRC_DEFAULT: + _record_parse_err(ps) + ps.error_count += 1 + return None + src = NEW_SRC_STACK + _advance(ps) + continue + if _is_named_soft(ps, "heap") != 0: + if src != NEW_SRC_DEFAULT: + _record_parse_err(ps) + ps.error_count += 1 + return None + src = NEW_SRC_HEAP + _advance(ps) + continue + if _is_named_soft(ps, "memgr") != 0: + if src != NEW_SRC_DEFAULT: + _record_parse_err(ps) + ps.error_count += 1 + return None + _advance(ps) # memgr + if _expect_op(ps, TokOp.LPar) == 0: return None + _skip_nl(ps) + memgr_arg = _parse_test(ps) + if memgr_arg is None: return None + if _expect_op(ps, TokOp.RPar) == 0: return None + src = NEW_SRC_MEMGR + continue + break + # 类型/可调用 + 实参:复用普通表达式解析,要求结果恰好是一个 Call(`T(args)`) + callee: AST* = _parse_atom_expr(ps) + if callee is None or callee.kind() != ASTKind.Call: + _record_parse_err(ps) + ps.error_count += 1 + return None + cl: Call* = Call*(callee) + node: New* = New(ps.pool, src, life, memgr_arg, cl.func, cl.args) + _set_pos(node, lineno, col, 0, 0) + return node + + def _parse_atom(ps: Parser*) -> AST*: """atom: the smallest unit of expression""" ttype: int = _cur_type(ps) @@ -1787,6 +1872,8 @@ def _parse_atom(ps: Parser*) -> AST*: col: int = _cur_col(ps) if ttype == TokenType.Name: + # M2.4 `new` 描述符分配(软关键字):仅当后面确实跟着描述符/类型调用时才当关键字 + if _is_new_expr(ps) != 0: return _parse_new_expr(ps) kw: int = _cur_kw(ps) if kw == Keyword.True_: _advance(ps) @@ -2449,31 +2536,31 @@ def _parse_array_prefix_declarator(ps: Parser*) -> AST*: return carray -def _IsCTypedefAnnotation(ann: AST*) -> int: - """1 if the annotation is a typedef marker (bare CTypedef / t.CTypedef / a union containing it). - - Used to parse a typedef's right-hand side as a **type**: `X: t.CTypedef = const uint16*` - synthesizes descriptors and the `*` suffix through _parse_type_ann (the annotation rule), - so both sides agree. TPC's vast Parser._IsCTypedefAnnotation uses the same name-based test. - """ - if ann is None: return 0 - kd: int = ann.kind() - if kd == ASTKind.Attribute: - at: Attribute* = Attribute*(ann) - if at.attr is not None and string.strcmp(at.attr, "CTypedef") == 0: return 1 - return 0 - if kd == ASTKind.Name: - nm: Name* = Name*(ann) - if nm.id is not None and string.strcmp(nm.id, "CTypedef") == 0: return 1 - return 0 - if kd == ASTKind.BinOp: - bo: BinOp* = BinOp*(ann) - if bo.left is not None and _IsCTypedefAnnotation(bo.left) != 0: return 1 - if bo.right is not None and _IsCTypedefAnnotation(bo.right) != 0: return 1 - return 0 - return 0 - - +def _IsCTypedefAnnotation(ann: AST*) -> int: + """1 if the annotation is a typedef marker (bare CTypedef / t.CTypedef / a union containing it). + + Used to parse a typedef's right-hand side as a **type**: `X: t.CTypedef = const uint16*` + synthesizes descriptors and the `*` suffix through _parse_type_ann (the annotation rule), + so both sides agree. TPC's vast Parser._IsCTypedefAnnotation uses the same name-based test. + """ + if ann is None: return 0 + kd: int = ann.kind() + if kd == ASTKind.Attribute: + at: Attribute* = Attribute*(ann) + if at.attr is not None and string.strcmp(at.attr, "CTypedef") == 0: return 1 + return 0 + if kd == ASTKind.Name: + nm: Name* = Name*(ann) + if nm.id is not None and string.strcmp(nm.id, "CTypedef") == 0: return 1 + return 0 + if kd == ASTKind.BinOp: + bo: BinOp* = BinOp*(ann) + if bo.left is not None and _IsCTypedefAnnotation(bo.left) != 0: return 1 + if bo.right is not None and _IsCTypedefAnnotation(bo.right) != 0: return 1 + return 0 + return 0 + + def _parse_type_ann(ps: Parser*) -> AST*: """Parse a type annotation: descriptor prefixes (const / volatile / __attribute__) and C-style pointer suffixes (* / **), field-identical to TPC's expansion. `static` is invalid here; missing type / non-type diff --git a/ast/stmts.vp b/ast/stmts.vp index 005896e..8cbdaf3 100644 --- a/ast/stmts.vp +++ b/ast/stmts.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/ast/tokens.vp b/ast/tokens.vp index 9559a94..79c8730 100644 --- a/ast/tokens.vp +++ b/ast/tokens.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/atom.vp b/atom.vp index 3ace8ad..f6c971a 100644 --- a/atom.vp +++ b/atom.vp @@ -1,6 +1,3 @@ -import t, c - - define ATOMIC_RELAXED = 0 define ATOMIC_CONSUME = 1 define ATOMIC_ACQUIRE = 2 @@ -11,8 +8,8 @@ define ATOMIC_SEQ_CST = 5 def __atomic_test_and_set(ptr: uint64*, order: int) -> bool: result: uint8 = 1 - c.Asm(f"""mov al, 1 - xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al + __asm__(f"""mov al, 1 + xchg byte ptr [{asminp(ptr, ASM_DESCR.REG_ANY)}], al mov $0, al""", out = [asmout(result, ASM_DESCR.OUTPUT_REG)], op = [ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX]) @@ -20,7 +17,7 @@ def __atomic_test_and_set(ptr: uint64*, order: int) -> bool: def __atomic_clear(ptr: uint64*, order: int): - __asm__(f"""mov byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], 0""", + __asm__(f"""mov byte ptr [{asminp(ptr, ASM_DESCR.REG_ANY)}], 0""", inp = [asminp(ptr, ASM_DESCR.REG_ANY)], op = [ASM_DESCR.CLOBBER_MEMORY]) diff --git a/base64.vp b/base64.vp index 9a86327..34a9052 100644 --- a/base64.vp +++ b/base64.vp @@ -1,6 +1,3 @@ -import t, c - - # ============================================== # Base64 Encoder & Decoder, pure bare-metal implementation # ============================================== diff --git a/binascii.vp b/binascii.vp index 065a9c6..1bf9d6d 100644 --- a/binascii.vp +++ b/binascii.vp @@ -1,4 +1,4 @@ -import t, c +import t import stdlib diff --git a/builtins.vp b/builtins.vp index 702bb5a..5cbd073 100644 --- a/builtins.vp +++ b/builtins.vp @@ -1,4 +1,3 @@ -import stdint as __stdint import t diff --git a/condition.vp b/condition.vp index 8f061f5..1f12857 100644 --- a/condition.vp +++ b/condition.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from w32.win32base import * from w32.win32sync import ( @@ -42,7 +41,7 @@ class Condition: def release(self): LeaveCriticalSection(&self.cs) - def __enter__(self) -> 'Condition' | t.CPtr: + def __enter__(self) -> Condition*: self.acquire() return self diff --git a/coro.vp b/coro.vp index 20278a1..53562a4 100644 --- a/coro.vp +++ b/coro.vp @@ -1,8 +1,3 @@ -import t, c -from stdint import * -import stdlib - - novirtual class Coroutine: """Coroutine frame handle (M1: __ptr__ holds the frame pointer returned by create_()). Pure handle semantics: never instantiated or polymorphically dispatched, the compiler intercepts all coro.* calls; user code uses t.CPtr as the handle.""" @@ -43,7 +38,7 @@ def coro_gather(a: Coroutine) -> int: # M4 placeholder: the compiler inlines coro.coro_gather(frames...) into a concurrent-advance loop. return 0 -def coro_exception_msg(c: Coroutine) -> t.CPtr: +def coro_exception_msg(c: Coroutine) -> rawptr: # M7 placeholder: the compiler inlines coro.coro_exception_msg(frame) into a frame msg-slot read. # Note: TPV (Viper) does not support bare null; use t.CPtr(0) to build a null pointer (compatible with both compilers). return None diff --git a/ctraits.vpi b/ctraits.vpi deleted file mode 100644 index f8656e2..0000000 --- a/ctraits.vpi +++ /dev/null @@ -1,20 +0,0 @@ -"""ctraits — Compile-time type trait library - -Provides compile-time type predicates with no runtime code generated. -All functions are evaluated exclusively at compile time and can be combined with the conditional -compilation statements cif / celif / celse. -""" -import t - -def isptr(x: t.CType) -> bool: - """Compile-time predicate to determine whether the type of x is a pointer. - - Returns True if x is a pointer type (ptr_count > 0); otherwise returns False. - Can be used alongside cif to implement conditional compilation. - - Example: - cif ctraits.isptr(my_var): - # This branch compiles only when my_var is a pointer type - ... - """ - pass \ No newline at end of file diff --git a/event.vp b/event.vp index 85fe1be..e7a7bf1 100644 --- a/event.vp +++ b/event.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from w32.win32base import * from w32.win32sync import CreateEventA, SetEvent, ResetEvent, WaitForSingleObject diff --git a/gzip.vp b/gzip.vp index 36986f1..c20982f 100644 --- a/gzip.vp +++ b/gzip.vp @@ -14,7 +14,6 @@ # # Covers the three deflate block types (stored/fixed/dynamic); does not decode CRC. # ============================================================ -import t, c import stdlib import string import w32.fileio as fileio @@ -132,11 +131,11 @@ class GzipFile: _g_bits: uint64 = 0 _g_bitcnt: int = 0 _g_pos: sizet = 0 -_g_src: t.CPtr = None +_g_src: rawptr = None _g_src_len: sizet = 0 -def gzip_isize(src: t.CPtr, src_len: sizet) -> uint32: +def gzip_isize(src: rawptr, src_len: sizet) -> uint32: """gzip trailing ISIZE (little-endian u32): original length hint.""" if src is None or src_len < 4: return 0 @@ -150,7 +149,7 @@ def gzip_isize(src: t.CPtr, src_len: sizet) -> uint32: return uint32(v64) -def _reset(src: t.CPtr, src_len: sizet): +def _reset(src: rawptr, src_len: sizet): global _g_bits, _g_bitcnt, _g_pos, _g_src, _g_src_len _g_bits = 0 _g_bitcnt = 0 @@ -315,8 +314,8 @@ def _cl_order_set(arr: int*, idx: int, val: int): # ============================================================ # Core decompression (module-private) # ============================================================ -def _gzip_decode(src: t.CPtr, src_len: sizet, - dst: t.CPtr, dst_cap: sizet) -> LONG: +def _gzip_decode(src: rawptr, src_len: sizet, + dst: rawptr, dst_cap: sizet) -> LONG: if src is None or dst is None or src_len < 18 or dst_cap == 0: return -1 ub: uchar* = src diff --git a/hashlib/__md5.vp b/hashlib/__md5.vp index 8e7bba9..b378547 100644 --- a/hashlib/__md5.vp +++ b/hashlib/__md5.vp @@ -1,5 +1,4 @@ import string -import t, c # ============================================== @@ -41,8 +40,8 @@ class md5: state: [4]uint32 = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 - ] # 4 32-bit state registers - count: uint64 = 0 # processed bits + ] # 4 32-bit state registers + count: uint64 = 0 # processed bits buf: [MD5_BLOCK_LEN]uint8 # Initialize MD5 context def __init__(self): diff --git a/hashlib/__sha1.vp b/hashlib/__sha1.vp index e2d0919..d25a0b6 100644 --- a/hashlib/__sha1.vp +++ b/hashlib/__sha1.vp @@ -1,6 +1,4 @@ import string -import t, c - # ============================================== diff --git a/hashlib/__sha256.vp b/hashlib/__sha256.vp index 7b1f8e2..f2b1221 100644 --- a/hashlib/__sha256.vp +++ b/hashlib/__sha256.vp @@ -1,5 +1,4 @@ import string -import t, c # ============================================== diff --git a/hashlib/__sha512.vp b/hashlib/__sha512.vp index 314d350..d3eb91c 100644 --- a/hashlib/__sha512.vp +++ b/hashlib/__sha512.vp @@ -1,4 +1,3 @@ -import t, c import string diff --git a/hashtable.vp b/hashtable.vp index 430f4b3..b48cf94 100644 --- a/hashtable.vp +++ b/hashtable.vp @@ -1,10 +1,8 @@ # hashtable - Open-addressing hash table library # Linear probing for collision resolution, supports auto-resizing and tombstone deletion # Key type fixed as str (i8*), value type is void* (generic pointer) -import t, c import string import memhub -import stdio from stdint import * # Empty slot marker (hash == 0) diff --git a/json/__init__.vp b/json/__init__.vp index 5134dcc..d4bebd7 100644 --- a/json/__init__.vp +++ b/json/__init__.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string @@ -26,9 +25,9 @@ class JsonValue: int_val: int64 float_val: double str_val: str - next: 'JsonValue' | t.CPtr + next: JsonValue* key: str - child: 'JsonValue' | t.CPtr + child: JsonValue* child_count: sizet def __new__(self, pool: memhub.MemManager*): @@ -77,7 +76,7 @@ class JsonValue: def __len__(self) -> sizet: return self.child_count - def __getitem__(self, key: str) -> 'JsonValue' | t.CPtr: + def __getitem__(self, key: str) -> JsonValue*: """Python-style get: v["key"] returns an object field.""" if self.vtype != JSON_OBJECT: return None @@ -91,7 +90,7 @@ class JsonValue: cur = cur.next return None - def __setitem__(self, key: str, val: 'JsonValue' | t.CPtr): + def __setitem__(self, key: str, val: JsonValue*): """Python-style set: v["key"] = val.""" if self.vtype != JSON_OBJECT or key == None or val == None: return @@ -116,7 +115,7 @@ class JsonValue: val.key = kbuf self._append_child(val) - def get_item(self, index: sizet) -> 'JsonValue' | t.CPtr: + def get_item(self, index: sizet) -> JsonValue*: """Get an array element by index: v.get_item(0).""" if self.vtype != JSON_ARRAY and self.vtype != JSON_OBJECT: return None @@ -133,7 +132,7 @@ class JsonValue: """Internal: allocate from current object's mpool (reserved; currently returns None).""" return None - def _append_child(self, child: 'JsonValue' | t.CPtr): + def _append_child(self, child: JsonValue*): if self.child == None: self.child = child else: diff --git a/lock.vp b/lock.vp index 4667feb..dea7e6a 100644 --- a/lock.vp +++ b/lock.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from w32.win32base import * from w32.win32sync import CRITICAL_SECTION, InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, TryEnterCriticalSection diff --git a/platmacro.vp b/platmacro.vp index 230e378..eb481ff 100644 --- a/platmacro.vp +++ b/platmacro.vp @@ -1,6 +1,3 @@ -import t, c - - define IS_WINDOWS = 1 define IS_WIN64 = 1 define IS_X86_64 = 1 diff --git a/posix.vp b/posix.vp index 8f24a5c..2ad59a2 100644 --- a/posix.vp +++ b/posix.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * @@ -6,7 +5,7 @@ from stdint import * # POSIX Type Alias # Note: ssize_t has already been defined as t.CPtrDiffT in stdint.py, so we won’t repeat it here. # ============================================================================= -DIR: t.CTypedef = t.CPtr # Opaque directory stream handle +DIR: t.CTypedef = rawptr # Opaque directory stream handle mode_t: t.CTypedef = uint32 # File mode/permission bits pid_t: t.CTypedef = int32 # Process ID off_t: t.CTypedef = int64 # File offset (Linux x86_64) diff --git a/random.vp b/random.vp index 62a6529..73ad418 100644 --- a/random.vp +++ b/random.vp @@ -1,6 +1,5 @@ # vrandom - Hardware Random Number Generation Library # Implemented using inline assembly based on x86 RDRAND / RDSEED instructions -import t, c import math @@ -14,21 +13,21 @@ define RDSEED_RETRY_LIMIT = 100 # ============================================================ def rdrand16() -> uint16: val: uint32 = 0 - __asm__(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + __asm__(f"rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}", out=[asmout(val, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC]) return uint16(val) def rdrand32() -> uint32: val: uint32 = 0 - __asm__(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + __asm__(f"rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}", out=[asmout(val, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC]) return val def rdrand64() -> uint64: val: uint64 = 0 - __asm__(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + __asm__(f"rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}", out=[asmout(val, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC]) return val @@ -39,21 +38,21 @@ def rdrand64() -> uint64: # ============================================================ def rdseed16() -> uint16: val: uint32 = 0 - __asm__(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + __asm__(f"rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}", out=[asmout(val, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC]) return uint16(val) def rdseed32() -> uint32: val: uint32 = 0 - __asm__(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + __asm__(f"rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}", out=[asmout(val, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC]) return val def rdseed64() -> uint64: val: uint64 = 0 - __asm__(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + __asm__(f"rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}", out=[asmout(val, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC]) return val @@ -66,9 +65,9 @@ def rdseed64() -> uint64: def rdrand16_step(p: uint16*) -> int: val: uint32 = 0 ok: uint32 = 0 - c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + __asm__(f"""rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)} setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""", out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL]) p[0] = uint16(val) @@ -77,9 +76,9 @@ def rdrand16_step(p: uint16*) -> int: def rdrand32_step(p: uint32*) -> int: val: uint32 = 0 ok: uint32 = 0 - c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + __asm__(f"""rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)} setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""", out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL]) p[0] = val @@ -88,9 +87,9 @@ def rdrand32_step(p: uint32*) -> int: def rdrand64_step(p: uint64*) -> int: val: uint64 = 0 ok: uint32 = 0 - c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + __asm__(f"""rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)} setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""", out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL]) p[0] = val @@ -99,9 +98,9 @@ def rdrand64_step(p: uint64*) -> int: def rdseed16_step(p: uint16*) -> int: val: uint32 = 0 ok: uint32 = 0 - c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + __asm__(f"""rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)} setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""", out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL]) p[0] = uint16(val) @@ -110,9 +109,9 @@ def rdseed16_step(p: uint16*) -> int: def rdseed32_step(p: uint32*) -> int: val: uint32 = 0 ok: uint32 = 0 - c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + __asm__(f"""rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)} setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""", out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL]) p[0] = val @@ -121,9 +120,9 @@ def rdseed32_step(p: uint32*) -> int: def rdseed64_step(p: uint64*) -> int: val: uint64 = 0 ok: uint32 = 0 - c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + __asm__(f"""rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)} setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""", out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)], op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL]) p[0] = val diff --git a/rwlock.vp b/rwlock.vp index a015afc..362b44d 100644 --- a/rwlock.vp +++ b/rwlock.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from w32.win32base import * from w32.win32sync import ( @@ -38,7 +37,7 @@ class RWLock: def release_write(self): ReleaseSRWLockExclusive(&self.lock) - def __enter__(self) -> 'RWLock' | t.CPtr: + def __enter__(self) -> RWLock*: self.acquire_write() return self diff --git a/shutil.vp b/shutil.vp index 2a4e2d0..65c4b1b 100644 --- a/shutil.vp +++ b/shutil.vp @@ -25,24 +25,19 @@ _mbuddy: memhub.MemBuddy* def copyfile(src: str, dst: str) -> int: """Copy file content. Returns 0, otherwise -1.""" - if platmacro.IS_WINDOWS: - return _copyfile_win32(src, dst) - return _copyfile_posix(src, dst) + return _copyfile_win32(src, dst) if platmacro.IS_WINDOWS else _copyfile_posix(src, dst) def _copyfile_win32(src: str, dst: str) -> int: """Windows: Use CopyFileA kernel implementation (efficient).""" result: BOOL = w32.win32file.CopyFileA(src, dst, 0) - if result == 0: - return -1 - return 0 + return -1 if result == 0 else 0 def _copyfile_posix(src: str, dst: str) -> int: """POSIX: Manual file read/write loop copy""" fd_in: INT = posix.open(src, posix.O_RDONLY, 0) - if fd_in < 0: - return -1 + 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) @@ -52,17 +47,16 @@ def _copyfile_posix(src: str, dst: str) -> int: posix.close(fd_in) posix.close(fd_out) return -1 - n: ssize_t = 0 + n: sizet = 0 result: int = 0 n = posix.read(fd_in, buf, COPY_BUF_SIZE) while n > 0: - written: ssize_t = posix.write(fd_out, buf, sizet(n)) + written: sizet = posix.write(fd_out, buf, sizet(n)) if written < 0: result = -1 break n = posix.read(fd_in, buf, COPY_BUF_SIZE) - if n < 0: - result = -1 + if n < 0: result = -1 _mbuddy.free(buf) posix.close(fd_in) posix.close(fd_out) @@ -75,9 +69,7 @@ def _copyfile_posix(src: str, dst: str) -> int: def copy(src: str, dst: str) -> int: """Copy file and preserve permissions/metadata (POSIX only). Returns 0, otherwise -1.""" - if platmacro.IS_WINDOWS: - return _copy_win32(src, dst) - return _copy_posix(src, dst) + return _copy_win32(src, dst) if platmacro.IS_WINDOWS else _copy_posix(src, dst) def _copy_win32(src: str, dst: str) -> int: @@ -88,11 +80,9 @@ def _copy_win32(src: str, dst: str) -> int: def _copy_posix(src: str, dst: str) -> int: """POSIX: Copy file and preserve permissions (stat+chmod). Returns 0, otherwise -1.""" result: int = _copyfile_posix(src, dst) - if result != 0: - return -1 + if result != 0: return -1 st: posix.Stat = posix.Stat() - if posix.stat(src, &st) == 0: - posix.chmod(dst, st.st_mode) + if posix.stat(src, &st) == 0: posix.chmod(dst, st.st_mode) return 0 @@ -102,9 +92,7 @@ def _copy_posix(src: str, dst: str) -> int: def rmtree(path: str) -> int: """Recursively delete a directory tree. Returns 0 on success and -1 on failure.""" - if platmacro.IS_WINDOWS: - return _rmtree_win32(path) - return _rmtree_posix(path) + return _rmtree_win32(path) if platmacro.IS_WINDOWS else - _rmtree_posix(path) def _rmtree_win32(path: str) -> int: diff --git a/socket.vp b/socket.vp index 9559079..c35ee0e 100644 --- a/socket.vp +++ b/socket.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import string import platmacro @@ -127,15 +126,15 @@ def _MakeAddr(host: str, port: INT) -> SocketAddr: if he_raw is not None: # he_raw.h_addr_list → he_raw->h_addr_list (char**) # c.Deref(uint64(he_raw.h_addr_list, t.CPtr)) → *(uint64_t*)(he_raw->h_addr_list) → h_addr_list[0] - ip_ptr: u64 = u64(c.Deref(uint64(he_raw.h_addr_list, t.CPtr))) + ip_ptr: u64 = u64(*(uint64*(he_raw.h_addr_list))) if ip_ptr != 0: - addr.addr = u32(c.Deref(uint32(ip_ptr, t.CPtr))) + addr.addr = u32(*(uint32*(ip_ptr))) else: he: HostEnt* = gethostbyname(host) if he is not None: - ip_ptr: u64 = u64(c.Deref(uint64(he.h_addr_list, t.CPtr))) + ip_ptr: u64 = u64(*(uint64*(he.h_addr_list))) if ip_ptr != 0: - addr.addr = u32(c.Deref(uint32(ip_ptr, t.CPtr))) + addr.addr = u32(*(uint32*(ip_ptr))) return addr @@ -175,7 +174,7 @@ def _ParseIPv4(ip_str: str, out_addr: u32*) -> bool: result = result | (u32(parts[1]) << 16) result = result | (u32(parts[2]) << 8) result = result | u32(parts[3]) - c.DerefAs(out_addr, result) + *out_addr = result return True diff --git a/traceback.vp b/traceback.vp index ffca1b0..c6a3e1c 100644 --- a/traceback.vp +++ b/traceback.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from w32.win32base import * import string @@ -525,8 +524,8 @@ class TracebackState(): ContextBuf: VOIDPTR # CONTEXT buffer (calloc, 16-byte aligned) FrameBuf: VOIDPTR # STACKFRAME64 buffer (calloc) LineBuf: bytes # output line buffer - FrameAddr: t.CArray[uint64, TRACEBACK_FRAME_BUF] # collected frames, innermost first - FrameScan: t.CArray[int32, TRACEBACK_FRAME_BUF] # 0 = authoritative, 1 = inferred (ScanStack) + FrameAddr: [TRACEBACK_FRAME_BUF]uint64 # collected frames, innermost first + FrameScan: [TRACEBACK_FRAME_BUF]int32 # 0 = authoritative, 1 = inferred (ScanStack) FrameCount: int # frames collected so far (also the printed frame count) @@ -577,7 +576,7 @@ def DiagEnabled() -> int: global _DiagFlag if _DiagFlag >= 0: return _DiagFlag - Val: t.CArray[char, 8] + Val: [8]char Val[0] = char(0) R: DWORD = GetEnvironmentVariableA("TRACEBACK_DIAG", &Val, DWORD(8)) _DiagFlag = 0 @@ -630,7 +629,7 @@ def EmitToFile(N: int): if _DumpFileFailWarned != 0: return _DumpFileFailWarned = 1 - LB: t.CArray[char, 160] + LB: [160]char M: int = stdio.snprintf(&LB, sizet(160), "[traceback] WARN: stack dump file write failed (further file-write failures not reported)\n") if M <= 0: @@ -667,15 +666,15 @@ def EmitLine(N: int): # Line-number prefix: shift the buffer right by the prefix length, then write the prefix. if DiagEnabled() != 0: _DumpLineNo = _DumpLineNo + 1 - Pfx: t.CArray[char, 32] + Pfx: [32]char Pl: int = stdio.snprintf(&Pfx, sizet(32), " [dump#%d] ", _DumpLineNo) if Pl > 0: # Keep room for the trailing '\0' after prefixing. if N + Pl > TRACEBACK_LINE_CAP - 1: N = TRACEBACK_LINE_CAP - 1 - Pl # Move the trailing '\0' too (N+1) so the buffer stays NUL-terminated. - string.memmove(t.CPtr(_State.LineBuf + int(Pl)), t.CPtr(_State.LineBuf), sizet(N + 1)) - string.memmove(t.CPtr(_State.LineBuf), &Pfx, sizet(Pl)) + string.memmove(rawptr(_State.LineBuf + int(Pl)), rawptr(_State.LineBuf), sizet(N + 1)) + string.memmove(rawptr(_State.LineBuf), &Pfx, sizet(Pl)) N = N + Pl WriteConsoleOnly(N) EmitToFile(N) @@ -718,7 +717,7 @@ def EmitEarlyCode(Text: str, Code: ULONG): N: int = stdio.snprintf(_State.LineBuf, sizet(TRACEBACK_LINE_CAP), "%s(GetLastError=%u)\n", Text, Code) EmitLine(N) return - LB: t.CArray[char, 256] + LB: [256]char N2: int = stdio.snprintf(&LB, sizet(256), "%s(GetLastError=%u)\n", Text, Code) if N2 <= 0: return @@ -890,7 +889,7 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int: Got: ULONG = 0 if wf.ReadFile(hFile, Buf, ULONG(Size), &Got, None) == 0: Err: ULONG = GetLastError() - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) if _State != None and _State.LineBuf != None: RN: int = stdio.snprintf(_State.LineBuf, sizet(TRACEBACK_LINE_CAP), "[traceback] WARN: read .stackmap failed (GetLastError=%u)," @@ -898,14 +897,14 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int: EmitLine(RN) return 0 if sizet(Got) != sizet(Size): - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailPlain(Size, "read fewer bytes than the file size") # Header: magic / version / entry_count / str_count / str_bytes if ReadU32(Buf, 0) != uint32(TRACEBACK_MAP_MAGIC): - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailHdr(Size, "magic is not \"TPCS\" (writer/reader endianness or offset mismatch)", Buf) if ReadU32(Buf, 4) != uint32(TRACEBACK_MAP_VERSION): - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailHdr(Size, "version is not 1 (stackmap written by another TPC version)", Buf) Cnt: uint32 = ReadU32(Buf, 8) StrCnt: uint32 = ReadU32(Buf, 12) @@ -915,16 +914,16 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int: + uint64(Cnt) * uint64(TRACEBACK_ENTRY_SIZE) \ + uint64(SBytes) if Need > uint64(Size): - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailHdr(Size, "20+entry_count*20+str_bytes exceeds end of file " "(header corrupt or file truncated)", Buf) if SBytes == 0: - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailHdr(Size, "str_bytes is 0 (string pool missing)", Buf) # The last pool byte must be '\0' so any later %s print stays inside the pool. PoolEnd: int = TRACEBACK_MAP_HEADER + int(Cnt) * TRACEBACK_ENTRY_SIZE + int(SBytes) - 1 if Buf[PoolEnd] != 0: - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailHdr(Size, "string pool does not end with '\\0' (pool corrupt)", Buf) # Full-table check: strictly ascending rva + string offsets inside the pool. Prev: uint64 = 0 @@ -932,17 +931,17 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int: Off: int = TRACEBACK_MAP_HEADER + int(i) * TRACEBACK_ENTRY_SIZE Cur: uint64 = ReadU64(Buf, Off) if i > 0 and Cur <= Prev: - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailEntry(Size, int(i), "record rva not strictly ascending (breaks binary search)", Cur) Prev = Cur FO: uint32 = ReadU32(Buf, Off + TRACEBACK_ENTRY_FILEOFF) FN: uint32 = ReadU32(Buf, Off + TRACEBACK_ENTRY_FUNCOFF) if uint64(FO) >= uint64(SBytes): - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailEntry(Size, int(i), "file_off outside the string pool", uint64(FO)) if FN != 0 and uint64(FN) >= uint64(SBytes): - stdlib.free(t.CPtr(Buf)) + stdlib.free(Buf) return MapFailEntry(Size, int(i), "func_off is neither 0 (no name) nor inside the string pool", uint64(FN)) @@ -989,13 +988,13 @@ def EmitSourceText(Path: str, LineNo: int): if _State == None or _State.LineBuf == None or LineNo <= 0: return h: HANDLE = wf.CreateFileA(Path, wf.GENERIC_READ, wf.FILE_SHARE_READ | wf.FILE_SHARE_WRITE, - t.CPtr(0), wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, t.CPtr(0)) + None, wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, None) if h == INVALID_HANDLE_VALUE: return - Chunk: t.CArray[char, TRACEBACK_SRC_CHUNK] - Src: t.CArray[char, TRACEBACK_LINE_CAP] + Chunk: [TRACEBACK_SRC_CHUNK]char + Src: [TRACEBACK_LINE_CAP]char Line: int = 1 - Out: int = 0 # bytes collected for the target line + Out: int = 0 # bytes collected for the target line Done: int = 0 while Done == 0: Got: ULONG = 0 @@ -1115,7 +1114,7 @@ def EmitFrame(Addr: uint64, Base: uint64, Scanned: int): # ============================================================ def ReadMemCb(hProcess: HANDLE, Addr: ULONGLONG, Buf: VOIDPTR, Size: DWORD, - pRead: t.CPtr) -> BOOL: + pRead: rawptr) -> BOOL: """This module's stand-in for the StackWalk64 memory callback (PREAD_PROCESS_MEMORY_ROUTINE64). Not kernel32!ReadProcessMemory directly: @@ -1129,7 +1128,7 @@ def ReadMemCb(hProcess: HANDLE, Addr: ULONGLONG, Buf: VOIDPTR, Size: DWORD, Passing this function by name as a t.CPtr mirrors SetConsoleCtrlHandler(CtrlHandler). """ Read: sizet = 0 - R: BOOL = wm.ReadProcessMemory(hProcess, t.CPtr(Addr), Buf, sizet(Size), &Read) + R: BOOL = wm.ReadProcessMemory(hProcess, rawptr(Addr), Buf, sizet(Size), &Read) if pRead != None: Rd: uint32* = (uint32*)(pRead) Rd[0] = uint32(Read) @@ -1299,7 +1298,7 @@ def WalkRbpChain(Rip: uint64, Rbp: uint64, Base: uint64) -> int: Cur: uint64 = Rbp i: int = 1 HProc: HANDLE = wp.GetCurrentProcess() - Two: t.CArray[uint64, 2] # [0] = [rbp] (caller rbp), [1] = [rbp+8] (return address) + Two: [2]uint64 # [0] = [rbp] (caller rbp), [1] = [rbp+8] (return address) while i < TRACEBACK_MAX_FRAMES: # Raw readings + decision for this step, produced before any early reject. Rd: sizet = 0 @@ -1319,7 +1318,7 @@ def WalkRbpChain(Rip: uint64, Rbp: uint64, Base: uint64) -> int: # Read 16 bytes via ReadProcessMemory (invalid/unreadable addresses return 0 without # faulting); dereferencing a wild rbp directly would crash, which the primary path # must never do. - OkRead: BOOL = wm.ReadProcessMemory(HProc, t.CPtr(Cur), &Two, sizet(16), &Rd) + OkRead: BOOL = wm.ReadProcessMemory(HProc, rawptr(Cur), &Two, sizet(16), &Rd) if OkRead == 0 or sizet(Rd) < sizet(16): # GetLastError must be read immediately after ReadProcessMemory. RpmErr = GetLastError() @@ -1401,8 +1400,8 @@ def ScanStack(StartIndex: int, Rsp: uint64, Base: uint64) -> int: HProc: HANDLE = wp.GetCurrentProcess() Upper: uint64 = Rsp + uint64(TRACEBACK_SCAN_MAX_BYTES) ModEnd: uint64 = Base + uint64(TRACEBACK_MODULE_MAX) - Words: t.CArray[uint64, TRACEBACK_SCAN_CHUNK_WORDS] # 4 KiB chunk buffer (local) - Found: t.CArray[uint64, TRACEBACK_SCAN_MAX_HITS] # deduplicated candidate return addresses + Words: [TRACEBACK_SCAN_CHUNK_WORDS]uint64 # 4 KiB chunk buffer (local) + Found: [TRACEBACK_SCAN_MAX_HITS]uint64 # deduplicated candidate return addresses Hits: int = 0 Prev: uint64 = 0 # [A-8]: previous word unknown at chunk start, 0 (one less confirmation) Addr: uint64 = Rsp @@ -1414,7 +1413,7 @@ def ScanStack(StartIndex: int, Rsp: uint64, Base: uint64) -> int: EmitLine(D0) while Addr < Upper: Rd: sizet = 0 - OkRead: BOOL = wm.ReadProcessMemory(HProc, t.CPtr(Addr), &Words, sizet(TRACEBACK_SCAN_CHUNK_BYTES), &Rd) + OkRead: BOOL = wm.ReadProcessMemory(HProc, rawptr(Addr), &Words, sizet(TRACEBACK_SCAN_CHUNK_BYTES), &Rd) N: int = int(sizet(Rd) / sizet(8)) # u64 words actually read in this chunk if OkRead == 0 or N <= 0: Er: ULONG = GetLastError() @@ -1630,7 +1629,7 @@ def DumpMainThread(IsBreak: int) -> int: string.memset(_State.ContextBuf, 0, wp.CONTEXT.__sizeof__()) ctx: wp.CONTEXT* = (wp.CONTEXT*)(_State.ContextBuf) ctx.ContextFlags = uint32(wp.CONTEXT_FULL) - if wp.GetThreadContext(hThread, t.CPtr(_State.ContextBuf)) == 0: + if wp.GetThreadContext(hThread, rawptr(_State.ContextBuf)) == 0: N = stdio.snprintf(_State.LineBuf, sizet(TRACEBACK_LINE_CAP), " fallback: GetThreadContext failed (GetLastError=%u), cannot dump stack\n", GetLastError()) @@ -1749,8 +1748,8 @@ def DumpMainThread(IsBreak: int) -> int: # shrink the dump whenever dbghelp fails. Locals only: the handler thread allocates # nothing (same discipline as ScanStack's chunk buffers). SavedCount: int = _State.FrameCount - SaveAddrBuf: t.CArray[uint64, TRACEBACK_FRAME_BUF] - SaveScanBuf: t.CArray[int32, TRACEBACK_FRAME_BUF] + SaveAddrBuf: [TRACEBACK_FRAME_BUF]uint64 + SaveScanBuf: [TRACEBACK_FRAME_BUF]int32 for si in range(SavedCount): SaveAddrBuf[si] = _State.FrameAddr[si] SaveScanBuf[si] = _State.FrameScan[si] @@ -1832,11 +1831,10 @@ def DumpCrashThread(Info: VOIDPTR) -> int: EmitText("=== TPC crash dump (unhandled exception; the process keeps terminating) ===\n") HProc: HANDLE = wp.GetCurrentProcess() Rd: sizet = 0 - Two: t.CArray[uint64, 2] # [0] = EXCEPTION_RECORD*, [1] = CONTEXT* (EXCEPTION_POINTERS) + Two: [2]uint64 # [0] = EXCEPTION_RECORD*, [1] = CONTEXT* (EXCEPTION_POINTERS) Two[0] = 0 Two[1] = 0 - if wm.ReadProcessMemory(HProc, t.CPtr(Info), &Two, sizet(16), &Rd) == 0 \ - or sizet(Rd) < sizet(16): + if wm.ReadProcessMemory(HProc, rawptr(Info), &Two, sizet(16), &Rd) == 0 or sizet(Rd) < sizet(16): EmitText(" fallback: EXCEPTION_POINTERS unreadable, crash dump skipped\n") AtomicLeaveDump() return 0 @@ -1853,10 +1851,10 @@ def DumpCrashThread(Info: VOIDPTR) -> int: # u32[10..11] ExceptionInformation[1] (offset 0x28 = the faulting DATA address). # The two ExceptionInformation fields are only filled for access violations (code 0xC0000005); # they are printed unconditionally because a hard crash is exactly when raw numbers beat guesses. - RecWords: t.CArray[uint32, 12] + RecWords: [12]uint32 RecWords[0] = 0 if Rec != 0: - if wm.ReadProcessMemory(HProc, t.CPtr(Rec), &RecWords, sizet(48), &Rd) != 0 \ + if wm.ReadProcessMemory(HProc, rawptr(Rec), &RecWords, sizet(48), &Rd) != 0 \ and sizet(Rd) >= sizet(48): Code = RecWords[0] ExAddr = uint64(RecWords[4]) | (uint64(RecWords[5]) << 32) @@ -1871,9 +1869,7 @@ def DumpCrashThread(Info: VOIDPTR) -> int: EmitText(" fallback: CONTEXT pointer null, crash dump skipped\n") AtomicLeaveDump() return 0 - if wm.ReadProcessMemory(HProc, t.CPtr(CtxPtr), t.CPtr(_State.ContextBuf), - wp.CONTEXT.__sizeof__(), &Rd) == 0 \ - or sizet(Rd) < sizet(wp.CONTEXT.__sizeof__()): + if wm.ReadProcessMemory(HProc, rawptr(CtxPtr), rawptr(_State.ContextBuf), wp.CONTEXT.__sizeof__(), &Rd) == 0 or sizet(Rd) < sizet(wp.CONTEXT.__sizeof__()): EmitText(" fallback: CONTEXT unreadable, crash dump skipped\n") AtomicLeaveDump() return 0 @@ -1906,7 +1902,7 @@ def DumpCrashThread(Info: VOIDPTR) -> int: # follow. The RBP chain and the stack scan stay as fallbacks, exactly as in the Ctrl+C path. Frames: int = 0 if DbgHelpUsable() != 0: - Frames = WalkViaDbgHelp(HProc, wp.GetCurrentThread(), t.CPtr(_State.ContextBuf), Base) + Frames = WalkViaDbgHelp(HProc, wp.GetCurrentThread(), rawptr(_State.ContextBuf), Base) if Frames <= 1: _State.FrameCount = 0 Frames = WalkRbpChain(Rip, Rbp, Base) @@ -1993,20 +1989,20 @@ def Install() -> int: return 0 Plen: ULONG = wf.GetModuleFileNameA(None, Pb, ULONG(TRACEBACK_PATH_CAP)) if Plen == 0 or sizet(Plen) >= sizet(TRACEBACK_PATH_CAP): - stdlib.free(t.CPtr(Pb)) + stdlib.free(Pb) EmitEarly("[traceback] WARN: GetModuleFileNameA failed, ctrl handler not installed\n") return 0 if sizet(Plen) + 16 > sizet(TRACEBACK_PATH_CAP): # 16 bytes of slack covers both ".stackmap" (10) and ".stackdump.txt" (16). - stdlib.free(t.CPtr(Pb)) + stdlib.free(Pb) EmitEarly("[traceback] WARN: exe path too long to append suffix safely, ctrl handler not installed\n") return 0 string.strcpy(str(Pb + int(Plen)), ".stackmap") # (2) sidecar existence = master switch (absent -> return immediately, no side effects). - hFile: HANDLE = wf.CreateFileA(Pb, wf.GENERIC_READ, wf.FILE_SHARE_READ, t.CPtr(0), wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, t.CPtr(0)) + hFile: HANDLE = wf.CreateFileA(Pb, wf.GENERIC_READ, wf.FILE_SHARE_READ, None, wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, None) if hFile == INVALID_HANDLE_VALUE: Err0: ULONG = GetLastError() - stdlib.free(t.CPtr(Pb)) + stdlib.free(Pb) if Err0 != ULONG(ERROR_FILE_NOT_FOUND): EmitEarlyCode("[traceback] WARN: cannot open .stackmap, ctrl handler not installed ", Err0) return 0 @@ -2015,14 +2011,14 @@ def Install() -> int: # __sizeof__() allocation below covers them and the memset zeroes FrameCount. _State = stdlib.malloc(TracebackState.__sizeof__()) if _State == None: - stdlib.free(t.CPtr(Pb)) + stdlib.free(Pb) CloseHandle(hFile) EmitEarly("[traceback] WARN: state alloc failed, ctrl handler not installed\n") return 0 string.memset(_State, 0, TracebackState.__sizeof__()) _State.LineBuf = stdlib.malloc(TRACEBACK_LINE_CAP) - _State.ContextBuf = t.CPtr(stdlib.calloc(1, wp.CONTEXT.__sizeof__())) - _State.FrameBuf = t.CPtr(stdlib.calloc(1, dbg.STACKFRAME64.__sizeof__())) + _State.ContextBuf = rawptr(stdlib.calloc(1, wp.CONTEXT.__sizeof__())) + _State.FrameBuf = rawptr(stdlib.calloc(1, dbg.STACKFRAME64.__sizeof__())) _State.OutHandle = wf.GetStdHandle(wf.STD_ERROR_HANDLE) if _State.OutHandle == None or _State.OutHandle == INVALID_HANDLE_VALUE: _State.OutHandle = wf.GetStdHandle(wf.STD_OUTPUT_HANDLE) @@ -2033,7 +2029,7 @@ def Install() -> int: # Name the missing buffer now (not later in the callback thread); any missing buffer makes # Install return 0. _State exists here, so EmitEarly forwards to EmitText; if LineBuf is # the missing one, EmitEarly falls back to a direct WriteFile and the notice is not lost. - stdlib.free(t.CPtr(Pb)) + stdlib.free(Pb) CloseHandle(hFile) if _State.LineBuf == None: EmitEarly("[traceback] WARN: LineBuf alloc failed, ctrl handler not installed\n") @@ -2049,7 +2045,7 @@ def Install() -> int: # written too. Raw UTF-8 bytes, unaffected by the console code page; kept open for the # whole process lifetime. string.strcpy(str(Pb + int(Plen)), ".stackdump.txt") - _DumpFile = wf.CreateFileA(Pb, TRACEBACK_FILE_APPEND_DATA, wf.FILE_SHARE_READ | wf.FILE_SHARE_WRITE, t.CPtr(0), wf.OPEN_ALWAYS, wf.FILE_ATTRIBUTE_NORMAL, t.CPtr(0)) + _DumpFile = wf.CreateFileA(Pb, TRACEBACK_FILE_APPEND_DATA, wf.FILE_SHARE_READ | wf.FILE_SHARE_WRITE, None, wf.OPEN_ALWAYS, wf.FILE_ATTRIBUTE_NORMAL, None) if _DumpFile == INVALID_HANDLE_VALUE: _DumpFile = None EmitText("[traceback] WARN: cannot open stack dump file, console-only output\n") @@ -2065,7 +2061,7 @@ def Install() -> int: else: LoadMapFile(hFile, int64(Sz.QuadPart)) CloseHandle(hFile) - stdlib.free(t.CPtr(Pb)) + stdlib.free(Pb) # (5) dbghelp initialization (must happen here: Install runs at startup on the main thread, # while the Ctrl+C/Break callbacks run on new threads where dbghelp's module enumeration # may be unavailable) + the two cross-module callback addresses, resolved dynamically. diff --git a/viperio.vp b/viperio.vp index 34183a9..12658dc 100644 --- a/viperio.vp +++ b/viperio.vp @@ -1,7 +1,3 @@ -import t, c -from stdint import * - - class Buf: data: char* length: sizet @@ -32,13 +28,11 @@ class Buf: if self.length < self.capacity: self.data[self.length] = 0 return n - def cstr(self) -> char*: - return self.data + def cstr(self) -> char*: return self.data def reset(self): self.length = 0 - if self.data != None and self.capacity > 0: - self.data[0] = 0 + if self.data != None and self.capacity > 0: self.data[0] = 0 def __enter__(self) -> Buf*: return self def __exit__(self): self.reset() diff --git a/viperlib.vp b/viperlib.vp index 4480dee..1638299 100644 --- a/viperlib.vp +++ b/viperlib.vp @@ -1,6 +1,5 @@ import viperio from stdarg import arg -import t define TEMP_BUF_SIZE = 68 @@ -39,8 +38,8 @@ def _check_special_float(fv: double) -> int: return 1 return 0 -# The 4th parameter MUST stay named `args`: the printf wrappers forward their own va_list pointer -# here (vprintf style), and the `arg()` sugar resolves the forwarded va_list by that name. +# The 4th parameter MUST stay named `args`: the printf wrappers forward their own va_list pointer +# here (vprintf style), and the `arg()` sugar resolves the forwarded va_list by that name. export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int: if fmt is None: return 0 # Length detection mode: when buf is None, only calculate the formatted length, without actually writing @@ -138,7 +137,7 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int: else: ptr_i: int = arg() elif *fmt == 115: - s: str = arg(t.CPtr) + s: str = arg(rawptr) if s is None: s = "(None)" slen: int = 0 sc: str = s @@ -481,7 +480,7 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int: ptr += _step pad_count -= 1 elif *fmt == 112: - ptr_val: uint64 = uint64(arg(t.CPtr)) + ptr_val: uint64 = uint64(arg(rawptr)) if ptr_val == 0: temp[0] = 40 temp[1] = 110 diff --git a/vipersimd.vp b/vipersimd.vp index fde7ca6..a2b367c 100644 --- a/vipersimd.vp +++ b/vipersimd.vp @@ -623,7 +623,7 @@ vzeroupper""", op=[ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm2', 'rcx', 'r8', 'r10']) -def simd_dot_array(a: t.CPtr, b: t.CPtr, n: sizet, out: t.CPtr): +def simd_dot_array(a: double*, b: double*, n: sizet, out: double): """AVX2 batch: out[0] = dot(a[0:n], b[0:n]) using FMA accumulation""" __asm__(f"""mov rcx, {asminp(n, ASM_DESCR.REG_ANY)} shr rcx, 2 diff --git a/vthreading.vp b/vthreading.vp index e7eebb3..c875087 100644 --- a/vthreading.vp +++ b/vthreading.vp @@ -13,12 +13,12 @@ from rwlock import RWLock class Thread: """Thread class, wraps Windows CreateThread. - Thread callback signature: def thread_func(arg: t.CPtr) -> t.CPtr + Thread callback signature: def thread_func(arg: rawptr) -> rawptr Note: Windows API limits the return value to DWORD (32-bit), so 64-bit pointers will be truncated. If you need to return a 64-bit result, pass it via the arg parameter struct. Usage: - def worker(arg: t.CPtr) -> t.CPtr: + def worker(arg: rawptr) -> rawptr: # thread logic return NULL @@ -84,7 +84,7 @@ class local: Usage: tls: local = local() tls.set(value_ptr) - val: t.CPtr = tls.get() + val: rawptr = tls.get() """ index: ULONG