From 0f556463e70976f4a5d04a34e879f595fac8a3e0 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 23 Sep 2026 17:42:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=9A=84=E8=A1=A8=E8=BE=BE=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E6=9C=80=E5=90=8E=E5=8F=AF=E7=94=A8=E7=89=88=E6=9C=AC?= =?UTF-8?q?=EF=BC=8Cmlirlite=20=E5=B7=B2=E5=9F=BA=E6=9C=AC=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _dict.vp | 110 +- _fakeduck.vp | 24 +- _list.vp | 26 +- _variant.vp | 63 +- _withcontent.vp | 36 +- argparse.vp | 34 +- asm.vp | 63 +- ast/__init__.vp | 15 +- ast/astaux.vp | 70 +- ast/base.vp | 295 ++-- ast/exprs.vp | 189 +-- ast/lexer.vp | 449 ++++++- ast/match.vp | 67 +- ast/parser.vp | 939 ++++++++++++- ast/stmts.vp | 162 +-- ast/tokens.vp | 75 +- atom.vp | 30 +- base64.vp | 38 +- binascii.vp | 185 ++- builtins.vp | 48 +- coro.vp | 21 +- event.vp | 1 - fltk/__init__.vp | 159 +-- fltk/_cfl_browser.vp | 40 +- fltk/_cfl_draw.vp | 2 +- fltk/_cfl_input.vp | 16 +- fltk/_cfl_prefs.vp | 44 +- fltk/_cfl_term.vp | 10 +- fltk/_cfl_text.vp | 2 +- fltk/_cfl_tree.vp | 6 +- fltk/_cfl_valuator.vp | 4 +- fltk/_cfl_window.vp | 18 +- gzip.vp | 301 ++--- hashlib/__md5.vp | 39 +- hashlib/__sha1.vp | 35 +- hashlib/__sha256.vp | 43 +- hashlib/__sha512.vp | 43 +- hashtable.vp | 58 +- json/__init__.vp | 16 +- json/__parser.vp | 74 +- json/__writer.vp | 282 ++-- linkedlist.vp | 318 ++--- llvmlite/__builder.vp | 152 ++- llvmlite/__function.vp | 146 +- llvmlite/__init__.vp | 42 +- llvmlite/__module.vp | 66 +- llvmlite/__types.vp | 80 +- llvmlite/__values.vp | 28 +- llvmlite/__verify.vp | 38 +- math.vp | 440 ++++++ memhub.vp | 972 ++++++++++++-- mlirlite/README.md | 324 +++++ mlirlite/__builder.vp | 1884 ++++++++++++++++++++++++++ mlirlite/__function.vp | 2877 ++++++++++++++++++++++++++++++++++++++++ mlirlite/__init__.vp | 474 +++++++ mlirlite/__module.vp | 820 ++++++++++++ mlirlite/__types.vp | 1045 +++++++++++++++ mlirlite/__values.vp | 239 ++++ mlirlite/__verify.vp | 434 ++++++ numpy/__init__.vp | 302 +++-- openssl/bio.vp | 4 +- openssl/crypto.vp | 10 +- openssl/err.vp | 2 +- openssl/evp.vp | 24 +- openssl/hmac.vp | 6 +- openssl/md5.vp | 2 +- openssl/sha.vp | 10 +- os/__init__.vp | 2 +- os/_posix.vp | 6 +- os/_win32.vp | 10 +- os/path.vp | 62 +- platmacro.vp | 90 +- posix.vp | 172 +-- random.vp | 301 +++++ requests.vp.bak | 360 ----- requests/__init__.vp | 54 +- requests/download.vp | 76 +- requests/https.vp | 56 +- rwlock.vp | 1 - shutil.vp | 20 +- socket.vp | 62 +- spinlock.vp | 11 +- stdint.vp | 4 +- stdio.vp | 2 +- stdlib.vp | 6 +- string.vp | 46 +- subprocess.vp | 8 +- sys.vp | 117 +- testcheck.vp | 3 +- this.vp | 14 +- torch/__init__.vp | 21 +- vector.vp | 42 +- viperio.vp | 18 +- viperlib.vp | 483 ++++--- vipermath.vp | 551 -------- vipersimd.vp | 26 +- viperstring.vp | 1 - vqt6/__init__.vp | 109 +- vqt6/_qtcore.vp | 26 +- vqt6/_qtgui.vp | 2 +- vqt6/_qtnetwork.vp | 34 +- vqt6/_qtwidgets.vp | 16 +- vrandom.vp | 379 ------ vthreading.vp | 7 +- w32/fileio.vp | 86 +- w32/win32base.vp | 2 +- w32/win32memory.vp | 30 +- w32/win32process.vp | 4 +- w32/win32sync.vp | 45 +- zipfile.vp | 405 +++--- zlib/pyzlib.vp | 90 +- zlib/zchecksum.vp | 8 +- zlib/zdef.vp | 28 +- zlib/zdeflate.vp | 41 +- zlib/zhuff.vp | 1 - zlib/zinflate.vp | 25 +- 116 files changed, 13896 insertions(+), 4938 deletions(-) create mode 100644 math.vp create mode 100644 mlirlite/README.md create mode 100644 mlirlite/__builder.vp create mode 100644 mlirlite/__function.vp create mode 100644 mlirlite/__init__.vp create mode 100644 mlirlite/__module.vp create mode 100644 mlirlite/__types.vp create mode 100644 mlirlite/__values.vp create mode 100644 mlirlite/__verify.vp create mode 100644 random.vp delete mode 100644 requests.vp.bak delete mode 100644 vipermath.vp delete mode 100644 viperstring.vp delete mode 100644 vrandom.vp diff --git a/_dict.vp b/_dict.vp index 9bf99e7..451bf95 100644 --- a/_dict.vp +++ b/_dict.vp @@ -5,18 +5,18 @@ import json from stdint import * # Variant type tags (consistent with _variant.py) -VARIANT_NONE: t.CDefine = 0 # Untyped / null value -VARIANT_INT: t.CDefine = 1 # int (i64) -VARIANT_FLOAT: t.CDefine = 2 # float (f32) -VARIANT_DOUBLE: t.CDefine = 3 # double (f64) -VARIANT_STR: t.CDefine = 4 # str (i8*) -VARIANT_DICT: t.CDefine = 5 # dict* -VARIANT_LIST: t.CDefine = 6 # list* -VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32) -VARIANT_PTR: t.CDefine = 8 # Custom pointer type +define VARIANT_NONE = 0 # Untyped / null value +define VARIANT_INT = 1 # int (i64) +define VARIANT_FLOAT = 2 # float (f32) +define VARIANT_DOUBLE = 3 # double (f64) +define VARIANT_STR = 4 # str (i8*) +define VARIANT_DICT = 5 # dict* +define VARIANT_LIST = 6 # list* +define VARIANT_BOOL = 7 # bool (i1/i32) +define VARIANT_PTR = 8 # Custom pointer type # Variant structure size: vtype(i32, 4 bytes) + padding(4 bytes) + ptr(i8*, 8 bytes) = 16 bytes -_VARIANT_SIZE: t.CDefine = 16 +define _VARIANT_SIZE = 16 class dict: @@ -29,48 +29,48 @@ class dict: d: dict = dict(mb) d.set_int("x", 42) p: t.CPtr = d["x"] - v: int = c.Deref(p) + v: int = c.Deref((int | t.CPtr)(p)) # int 值按 i32 存,读回须给 int* 视图 # Nested dict inner: dict = dict(mb) inner.set_int("a", 1) d.set_dict("sub", inner) sub: dict = c.Deref(d["sub"]) - av: int = c.Deref(sub["a"]) + av: int = c.Deref((int | t.CPtr)(sub["a"])) """ - __keys__: t.CPtr - __values__: t.CPtr - __count__: t.CSizeT = 0 - __capacity__: t.CSizeT = 8 - __mbuddy__: rawptr[memhub.MemBuddy] - __iter_index__: t.CSizeT = 0 + __keys__: rawptr + __values__: rawptr + __count__: sizet = 0 + __capacity__: sizet = 8 + __mbuddy__: memhub.MemBuddy* + __iter_index__: sizet = 0 - def __new__(self, mb: rawptr[memhub.MemBuddy]) -> t.CPtr: + def __new__(self, mb: memhub.MemBuddy*): # Heap allocation for dict object return mb.alloc(dict.__sizeof__()) - def __init__(self, mb: rawptr[memhub.MemBuddy]): + def __init__(self, mb: memhub.MemBuddy*): self.__mbuddy__ = mb self.__keys__ = mb.alloc(self.__capacity__ * 8) self.__values__ = mb.alloc(self.__capacity__ * _VARIANT_SIZE) - def __len__(self) -> t.CSizeT: + def __len__(self) -> sizet: return self.__count__ - def _find(self, key: str) -> t.CSizeT: + def _find(self, key: str) -> sizet: """Find index of target key; returns __count__ if not found""" for i in range(self.__count__): - key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + i * 8) + key_ptr: str* = rawptr(uint64(self.__keys__) + i * 8) if string.strcmp(key_ptr[0], key) == 0: return i return self.__count__ def __getitem__(self, key: str) -> t.CPtr: """Return untyped pointer to value. Use c.Deref to resolve the actual value. - Example: p: t.CPtr = d["x"]; v: int = c.Deref(p)""" - idx: t.CSizeT = self._find(key) + Example: p: t.CPtr = d["x"]; v: int = c.Deref((int | t.CPtr)(p))""" + idx: sizet = self._find(key) if idx >= self.__count__: return None # Variant.ptr is located at offset 8 within Variant structure - val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8) + val_ptr: str | t.CPtr = t.CPtr(uint64(self.__values__) + idx * _VARIANT_SIZE + 8) return val_ptr[0] def __setitem__(self, key: str, val: t.CNeedPtr): @@ -81,16 +81,16 @@ class dict: def _set_variant_raw(self, key: str, vtype: t.CInt, ptr: t.CPtr): """Internal method: store Variant entry (vtype + ptr). No automatic address resolution.""" - idx: t.CSizeT = self._find(key) + idx: sizet = self._find(key) if idx < self.__count__: # Update existing key - vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE) + vtype_ptr: t.CInt | t.CPtr = t.CPtr(uint64(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: str | t.CPtr = t.CPtr(uint64(self.__values__) + idx * _VARIANT_SIZE + 8) val_ptr[0] = ptr return if self.__count__ >= self.__capacity__: - new_cap: t.CSizeT = self.__capacity__ * 2 + new_cap: sizet = 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 @@ -99,11 +99,11 @@ class dict: 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: str | t.CPtr = t.CPtr(uint64(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: t.CInt | t.CPtr = t.CPtr(uint64(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: str | t.CPtr = t.CPtr(uint64(self.__values__) + self.__count__ * _VARIANT_SIZE + 8) val_ptr[0] = ptr self.__count__ += 1 @@ -114,7 +114,7 @@ class dict: def set_int(self, key: str, val: int): """Store integer value (VARIANT_INT). Value is copied to persistent storage within __mbuddy__.""" storage: t.CPtr = self.__mbuddy__.alloc(8) - int_ptr: int | t.CPtr = t.CPtr(t.CUInt64T(storage)) + int_ptr: int | t.CPtr = t.CPtr(uint64(storage)) int_ptr[0] = val self._set_variant_raw(key, VARIANT_INT, storage) @@ -125,14 +125,14 @@ class dict: def set_float(self, key: str, val: float): """Store float value (VARIANT_FLOAT). Value is copied to persistent storage within __mbuddy__.""" storage: t.CPtr = self.__mbuddy__.alloc(8) - float_ptr: float | t.CPtr = t.CPtr(t.CUInt64T(storage)) + float_ptr: float | t.CPtr = t.CPtr(uint64(storage)) float_ptr[0] = val self._set_variant_raw(key, VARIANT_FLOAT, storage) def set_double(self, key: str, val: t.CDouble): """Store double value (VARIANT_DOUBLE). Value is copied to persistent storage within __mbuddy__.""" storage: t.CPtr = self.__mbuddy__.alloc(8) - dbl_ptr: t.CDouble | t.CPtr = t.CPtr(t.CUInt64T(storage)) + dbl_ptr: t.CDouble | t.CPtr = t.CPtr(uint64(storage)) dbl_ptr[0] = val self._set_variant_raw(key, VARIANT_DOUBLE, storage) @@ -147,7 +147,7 @@ class dict: def set_bool(self, key: str, val: t.CInt): """Store boolean value (VARIANT_BOOL). Value is copied to persistent storage within __mbuddy__.""" storage: t.CPtr = self.__mbuddy__.alloc(8) - bool_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(storage)) + bool_ptr: t.CInt | t.CPtr = t.CPtr(uint64(storage)) bool_ptr[0] = val self._set_variant_raw(key, VARIANT_BOOL, storage) @@ -157,23 +157,23 @@ class dict: def get_vtype(self, key: str) -> t.CInt: """Return Variant type tag associated with specified key.""" - idx: t.CSizeT = self._find(key) + idx: sizet = self._find(key) if idx >= self.__count__: return VARIANT_NONE - vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE) + vtype_ptr: t.CInt | t.CPtr = t.CPtr(uint64(self.__values__) + idx * _VARIANT_SIZE) return vtype_ptr[0] def get(self, key: str, default: t.CPtr) -> t.CPtr: """Return value pointer; return default pointer if key does not exist.""" - idx: t.CSizeT = self._find(key) + idx: sizet = self._find(key) if idx >= self.__count__: return default - val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8) + val_ptr: str | t.CPtr = t.CPtr(uint64(self.__values__) + idx * _VARIANT_SIZE + 8) return val_ptr[0] def contains(self, key: str) -> t.CInt: """Check whether target key exists.""" - idx: t.CSizeT = self._find(key) + idx: sizet = self._find(key) if idx < self.__count__: return 1 return 0 @@ -185,9 +185,9 @@ class dict: def __next__(self) -> str: if self.__iter_index__ >= self.__count__: raise StopIteration - idx: t.CSizeT = self.__iter_index__ + idx: sizet = self.__iter_index__ self.__iter_index__ = idx + 1 - key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + idx * 8) + key_ptr: str | t.CPtr = t.CPtr(uint64(self.__keys__) + idx * 8) return key_ptr[0] # ============================================================ @@ -198,34 +198,34 @@ class dict: """Convert dict instance to JsonValue object (JSON_OBJECT). Automatically select corresponding JSON value type according to Variant tag.""" obj: rawptr[json.JsonValue] = json.object(pool) - i: t.CSizeT = 0 + i: sizet = 0 while i < self.__count__: - key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + i * 8) - vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE) - val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE + 8) + key_ptr: str | t.CPtr = t.CPtr(uint64(self.__keys__) + i * 8) + vtype_ptr: t.CInt | t.CPtr = t.CPtr(uint64(self.__values__) + i * _VARIANT_SIZE) + val_ptr: str | t.CPtr = t.CPtr(uint64(self.__values__) + i * _VARIANT_SIZE + 8) vt: t.CInt = vtype_ptr[0] vp: t.CPtr = val_ptr[0] jv: rawptr[json.JsonValue] = json.null(pool) if jv != None: if vt == VARIANT_INT: jv.vtype = 2 # JSON_INT - ip: int | t.CPtr = t.CPtr(t.CUInt64T(vp)) + ip: int | t.CPtr = t.CPtr(uint64(vp)) 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.CPtr(t.CUInt64T(vp)) + bp: t.CInt | t.CPtr = t.CPtr(uint64(vp)) jv.bool_val = bp[0] elif vt == VARIANT_FLOAT: jv.vtype = 3 # JSON_FLOAT - fp: float | t.CPtr = t.CPtr(t.CUInt64T(vp)) + fp: float | t.CPtr = t.CPtr(uint64(vp)) jv.float_val = fp[0] elif vt == VARIANT_PTR: # Fallback: treat raw pointer as integer jv.vtype = 2 # JSON_INT - ip: int | t.CPtr = t.CPtr(t.CUInt64T(vp)) + ip: int | t.CPtr = t.CPtr(uint64(vp)) jv.int_val = ip[0] json.object_set(pool, obj, key_ptr[0], jv) i += 1 @@ -243,19 +243,19 @@ class dict: if cur.key != None: if cur.vtype == 2: # JSON_INT storage: t.CPtr = self.__mbuddy__.alloc(8) - ip: int | t.CPtr = t.CPtr(t.CUInt64T(storage)) + ip: int | t.CPtr = t.CPtr(uint64(storage)) 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.CPtr(t.CUInt64T(storage)) + bp: t.CInt | t.CPtr = t.CPtr(uint64(storage)) 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.CPtr(t.CUInt64T(storage)) + fp: float | t.CPtr = t.CPtr(uint64(storage)) fp[0] = cur.float_val self._set_variant_raw(cur.key, VARIANT_FLOAT, storage) cur = cur.next diff --git a/_fakeduck.vp b/_fakeduck.vp index 1cf05c5..3c35ed9 100644 --- a/_fakeduck.vp +++ b/_fakeduck.vp @@ -13,11 +13,11 @@ class _str: # (optional; no error will be raised if the field cannot be located) __requires__: list[str] = ['__mbuddy__'] __data__: str - __mbuddy__: rawptr[memhub.MemBuddy] + __mbuddy__: memhub.MemBuddy* def upper(self) -> str: src: str = self.__data__ - length: t.CSizeT = len(src) + length: sizet = len(src) buf: bytes = self.__mbuddy__.alloc(length + 1) if buf == None: return self.__data__ for i, ch in enumerate(src): @@ -33,7 +33,7 @@ class _str: def lower(self) -> str: src: str = self.__data__ - length: t.CSizeT = len(src) + length: sizet = len(src) buf: bytes = self.__mbuddy__.alloc(length + 1) if buf == None: return self.__data__ for i, ch in enumerate(src): @@ -49,7 +49,7 @@ class _str: def capitalize(self) -> str: src: str = self.__data__ - length: t.CSizeT = len(src) + length: sizet = len(src) buf: bytes = self.__mbuddy__.alloc(length + 1) if buf == None: return self.__data__ first: bool = True @@ -76,7 +76,7 @@ class _str: def swapcase(self) -> str: src: str = self.__data__ - length: t.CSizeT = len(src) + length: sizet = len(src) buf: bytes = self.__mbuddy__.alloc(length + 1) if buf == None: return self.__data__ for i, ch in enumerate(src): @@ -98,7 +98,7 @@ class _str: def title(self) -> str: src: str = self.__data__ - length: t.CSizeT = len(src) + length: sizet = len(src) buf: bytes = self.__mbuddy__.alloc(length + 1) if buf == None: return self.__data__ prev_alpha: bool = False @@ -136,7 +136,7 @@ class _str: def casefold(self) -> str: src: str = self.__data__ - length: t.CSizeT = len(src) + length: sizet = len(src) buf: bytes = self.__mbuddy__.alloc(length + 1) if buf == None: return self.__data__ for i, ch in enumerate(src): @@ -274,12 +274,12 @@ class _str: 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 + length: sizet = len(src) + delim_len: sizet = string.strlen(delimiter) + start: sizet = 0 + i: sizet = 0 cur: str = src - sub_len: t.CSizeT = 0 + sub_len: sizet = 0 sub: bytes = None src_off: bytes = None term: bytes = None diff --git a/_list.vp b/_list.vp index 6408219..9423171 100644 --- a/_list.vp +++ b/_list.vp @@ -22,17 +22,17 @@ class list[T]: lst: list[AST | t.CPtr] = list[AST | t.CPtr](pool, 8) """ __data__: t.CPtr - __count__: t.CSizeT - __capacity__: t.CSizeT + __count__: sizet + __capacity__: sizet __pool__: rawptr[memhub.MemManager] - __elem_size__: t.CSizeT - __iter_index__: t.CSizeT + __elem_size__: sizet + __iter_index__: sizet - def __new__(self, pool: rawptr[memhub.MemManager], elem_size: t.CSizeT = 0): + def __new__(self, pool: rawptr[memhub.MemManager], elem_size: sizet = 0): ret = pool.alloc(48) return ret - def __init__(self, pool: rawptr[memhub.MemManager], elem_size: t.CSizeT = 0): + def __init__(self, pool: rawptr[memhub.MemManager], elem_size: sizet = 0): self.__pool__ = pool self.__count__ = 0 self.__capacity__ = 8 @@ -43,12 +43,12 @@ class list[T]: self.__data__ = pool.alloc(self.__capacity__ * self.__elem_size__) self.__iter_index__ = 0 - def __len__(self) -> t.CSizeT: + def __len__(self) -> sizet: return self.__count__ def append(self, item: T): if self.__count__ >= self.__capacity__: - new_cap: t.CSizeT = self.__capacity__ * 2 + new_cap: sizet = 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__) @@ -58,19 +58,19 @@ class list[T]: elem_ptr[0] = item self.__count__ += 1 - def get(self, index: t.CSizeT) -> T: + def get(self, index: sizet) -> 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: + def __getitem__(self, index: sizet) -> 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): + def set(self, index: sizet, 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): + def __setitem__(self, index: sizet, value: T): elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) elem_ptr[0] = value @@ -89,7 +89,7 @@ class list[T]: def __next__(self) -> T: if self.__iter_index__ >= self.__count__: raise StopIteration - idx: t.CSizeT = self.__iter_index__ + idx: sizet = self.__iter_index__ self.__iter_index__ = idx + 1 elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + idx * self.__elem_size__) return elem_ptr[0] diff --git a/_variant.vp b/_variant.vp index 4da7f37..9c425c0 100644 --- a/_variant.vp +++ b/_variant.vp @@ -1,16 +1,16 @@ -import t, c -from stdint import * +import t + # Variant type tags (fixed enumeration + custom pointer type) -VARIANT_NONE: t.CDefine = 0 # Untyped / null value -VARIANT_INT: t.CDefine = 1 # int (i64) -VARIANT_FLOAT: t.CDefine = 2 # float (f32) -VARIANT_DOUBLE: t.CDefine = 3 # double (f64) -VARIANT_STR: t.CDefine = 4 # str (i8*) -VARIANT_DICT: t.CDefine = 5 # dict* -VARIANT_LIST: t.CDefine = 6 # list* -VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32) -VARIANT_PTR: t.CDefine = 8 # Custom pointer type +define VARIANT_NONE = 0 # Untyped / null value +define VARIANT_INT = 1 # int (i64) +define VARIANT_FLOAT = 2 # float (f32) +define VARIANT_DOUBLE = 3 # double (f64) +define VARIANT_STR = 4 # str (i8*) +define VARIANT_DICT = 5 # dict* +define VARIANT_LIST = 6 # list* +define VARIANT_BOOL = 7 # bool (i1/i32) +define VARIANT_PTR = 8 # Custom pointer type class Variant: @@ -22,11 +22,11 @@ class Variant: v2: Variant = Variant(VARIANT_STR, t.CNeedPtr("hello")) # Retrieve value - ptr: t.CPtr = v.ptr - i: int = c.Deref(ptr) + ptr: rawptr = v.ptr + i: int = *((int*)(ptr)) # int 值按 i32 存,读回须给 int* 视图 """ vtype: int - ptr: t.CPtr + ptr: rawptr def __init__(self, vtype: int, val: t.CNeedPtr): """Construct Variant instance. @@ -36,29 +36,12 @@ class Variant: self.vtype = vtype self.ptr = val - def is_none(self) -> int: - return self.vtype == VARIANT_NONE - - def is_int(self) -> int: - return self.vtype == VARIANT_INT - - def is_float(self) -> int: - return self.vtype == VARIANT_FLOAT - - def is_double(self) -> int: - return self.vtype == VARIANT_DOUBLE - - def is_str(self) -> int: - return self.vtype == VARIANT_STR - - def is_dict(self) -> int: - return self.vtype == VARIANT_DICT - - def is_list(self) -> int: - return self.vtype == VARIANT_LIST - - def is_bool(self) -> int: - return self.vtype == VARIANT_BOOL - - def is_ptr(self) -> int: - return self.vtype == VARIANT_PTR + def is_none(self) -> int: return self.vtype == VARIANT_NONE + def is_int(self) -> int: return self.vtype == VARIANT_INT + def is_float(self) -> int: return self.vtype == VARIANT_FLOAT + def is_double(self) -> int: return self.vtype == VARIANT_DOUBLE + def is_str(self) -> int: return self.vtype == VARIANT_STR + def is_dict(self) -> int: return self.vtype == VARIANT_DICT + def is_list(self) -> int: return self.vtype == VARIANT_LIST + def is_bool(self) -> int: return self.vtype == VARIANT_BOOL + def is_ptr(self) -> int: return self.vtype == VARIANT_PTR diff --git a/_withcontent.vp b/_withcontent.vp index 1dd1590..eee83ec 100644 --- a/_withcontent.vp +++ b/_withcontent.vp @@ -7,19 +7,18 @@ import string # Maximum provider stack depth (compiler verifies sufficiency; increase if needed) -_MAX_PROVIDER_DEPTH: t.CDefine = 32 +define _MAX_PROVIDER_DEPTH = 32 -@t.Object class _ProviderStack: """Provider stack, stores pairs of field names and pointers.""" - names: t.CArray[VOIDPTR, 32] - ptrs: t.CArray[VOIDPTR, 32] - top: UINT64 + names: [32]char + ptrs: [32]rawptr + top: uint64 # TLS index (global; all threads share the same index) -_tls_index: ULONG = 0 +_tls_index: ulong = 0 @t.TLS @@ -33,10 +32,10 @@ def _init_tls(): _tls_index = TlsAlloc() -def _get_stack() -> _ProviderStack | t.CPtr: +def _get_stack() -> _ProviderStack*: """Obtain current thread's provider stack. Allocate one if none exists.""" _init_tls() - stack: _ProviderStack | t.CPtr = TlsGetValue(_tls_index) + stack: _ProviderStack* = TlsGetValue(_tls_index) if stack == None: stack = stdlib.malloc(_ProviderStack.__sizeof__()) string.memset(stack, 0, _ProviderStack.__sizeof__()) @@ -44,9 +43,9 @@ def _get_stack() -> _ProviderStack | t.CPtr: return stack -def _push_provider(field_name: str, ptr: t.CPtr): +def _push_provider(field_name: str, ptr: rawptr): """Push a provider (field_name, ptr) onto the stack.""" - stack: _ProviderStack | t.CPtr = _get_stack() + stack: _ProviderStack* = _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 @@ -57,24 +56,25 @@ def _push_provider(field_name: str, ptr: t.CPtr): def _pop_provider(): """Pop the top provider entry from the stack.""" - stack: _ProviderStack | t.CPtr = _get_stack() + stack: _ProviderStack* = _get_stack() if stack.top > 0: stack.top = stack.top - 1 -def _find_provider(field_name: str) -> t.CPtr: +def _find_provider(field_name: str) -> rawptr: """Search for matching field_name starting from stack top. Return associated pointer, or NULL if no match found.""" - stack: _ProviderStack | t.CPtr = _get_stack() + stack: _ProviderStack* = _get_stack() # 上界显式转 t.CInt(有符号):本循环是「递减 + stop 为 -1」形态,若上界 - # 被当作无符号(stack.top 是 UINT64 字段),比较谓词会退化为 ugt,而 -1 在 + # 被当作无符号(stack.top 是 uint64 字段),比较谓词会退化为 ugt,而 -1 在 # 无符号域是 UINT32_MAX ⇒ 条件恒假、循环体不可达、本函数恒返回 NULL(with 的 # __mbuddy__ 注入全部失效,_str.upper 对 NULL 取 vtable 崩溃)。显式转换让 # 符号域与递减语义一致,与编译器侧「stop 为负字面量时退回有符号谓词」互为双保险。 - for i in range(t.CInt(stack.top) - 1, -1, -1): + for i in range(int(stack.top) - 1, -1, -1): # 字段名用 strcmp 内容比较:编译器对每次 create_global_string 生成 # 独立的字符串常量(TPV 不去重),push/find 的指针地址不同, # 指针 == 永假会导致 provider 匹配失败(__mbuddy__ 注入不上)。 - if string.strcmp((str)(stack.names[i]), field_name) == 0: - return stack.ptrs[i] - return None \ No newline at end of file + _cmp_tmp: [2]char = [0, 0] + _cmp_tmp = stack.names[i] + if string.strcmp(_cmp_tmp, field_name) == 0: return stack.ptrs[i] + return None diff --git a/argparse.vp b/argparse.vp index 05da897..23cd508 100644 --- a/argparse.vp +++ b/argparse.vp @@ -43,7 +43,7 @@ COUNT: t.CDefine = 3 MAX_ARGS: t.CDefine = 32 # Module-level membuddy pointer (assigned inside main by user) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================ @@ -68,13 +68,13 @@ class Argument: # ============================================================ class ParsedArgs: - _ht: rawptr[hashtable.HashTable] - __mbuddy__: rawptr[memhub.MemBuddy] + _ht: hashtable.HashTable* + __mbuddy__: memhub.MemBuddy* - def __new__(self, mb: rawptr[memhub.MemBuddy]) -> t.CPtr: + def __new__(self, mb: memhub.MemBuddy*) -> t.CPtr: return mb.alloc(16) - def __init__(self, mb: rawptr[memhub.MemBuddy]): + def __init__(self, mb: memhub.MemBuddy*): self.__mbuddy__ = mb self._ht = hashtable.HashTable(mb) @@ -125,19 +125,19 @@ class ArgumentParser: _description: str _args: Argument | t.CPtr _arg_count: int - __mbuddy__: rawptr[memhub.MemBuddy] + __mbuddy__: memhub.MemBuddy* def __new__(self, prog: str = "", description: str = "", - pool: rawptr[memhub.MemBuddy] = None) -> t.CPtr: - mb: rawptr[memhub.MemBuddy] = pool + pool: memhub.MemBuddy* = None) -> t.CPtr: + mb: memhub.MemBuddy* = pool if mb is None: mb = _mbuddy ret: t.CPtr = mb.alloc(40) return ret def __init__(self, prog: str = "", description: str = "", - pool: rawptr[memhub.MemBuddy] = None): - mb: rawptr[memhub.MemBuddy] = pool + pool: memhub.MemBuddy* = None): + mb: memhub.MemBuddy* = pool if mb is None: mb = _mbuddy self.__mbuddy__ = mb @@ -443,18 +443,16 @@ class ArgumentParser: # release — Release ParsedArgs and all internal resources # ============================================================ -def release(args: ParsedArgs | t.CPtr): +def release(args: rawptr[ParsedArgs]): """Free ParsedArgs object and its inner HashTable resources.""" - if args is None: - return - if args.__mbuddy__ is None: - return + if args is None: return + if args.__mbuddy__ is None: return if args._ht is not None: # 用临时变量拆分链式属性访问,避免 args._ht.__slots__ 跨模块类型推断失败 # 注意:类型注解必须用 hashtable.HashTable(带模块前缀), # 否则编译器无法解析 HashTable 类型,导致 ht.__slots__ 属性访问失败 - ht: rawptr[hashtable.HashTable] = args._ht + ht: hashtable.HashTable* = args._ht if ht.__slots__ is not None: args.__mbuddy__.free(ht.__slots__) - args.__mbuddy__.free(t.CPtr(t.CUInt64T(ht))) - args.__mbuddy__.free(t.CPtr(t.CUInt64T(args))) + args.__mbuddy__.free(ht) + args.__mbuddy__.free(args) diff --git a/asm.vp b/asm.vp index 2b13600..546d634 100644 --- a/asm.vp +++ b/asm.vp @@ -1,67 +1,58 @@ import t, c -def cli(): - c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY]) +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 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 +def inb(port: uint16) -> uint8: + value: uint32 # 模板内必须引用输出占位符 $0(DSL 约定,见 atom.vp),否则输出寄存器由 LLVM # 任意分配而结果取自硬编码 eax → 读到未定义寄存器;同时 in al,dx 改写 AL, # 需显式声明 ~{rax} clobber。 - c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + c.Asm(f"""mov edx, {c.AsmInp(uint32(port), t.ASM_DESCR.REG_ANY)} in al, dx movzx $0, al""", out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], op =[t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) - return t.CUInt8T(value) + return uint8(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)} +def outb(port: uint16, value: uint8): + c.Asm(f"""mov edx, {c.AsmInp(uint32(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(uint32(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)} +def inw(port: uint16) -> uint16: + value: uint32 + c.Asm(f"""mov edx, {c.AsmInp(uint32(port), t.ASM_DESCR.REG_ANY)} in ax, dx movzx eax, ax mov {c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)}, eax""", out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], op =[t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) - return t.CUInt16T(value) + return uint16(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)} +def outw(port: uint16, value: uint16): + c.Asm(f"""mov edx, {c.AsmInp(uint32(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(uint32(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)} +def inl(port: uint16) -> uint32: + value: uint32 + c.Asm(f"""mov edx, {c.AsmInp(uint32(port), t.ASM_DESCR.REG_ANY)} in eax, dx mov {c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)}, eax""", out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], op =[t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) 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)} +def outl(port: uint16, value: uint32): + c.Asm(f"""mov edx, {c.AsmInp(uint32(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]) @@ -74,7 +65,7 @@ def io_wait(): # 的 clobber 列表**不允许声明 RSP**(保留寄存器)⇒ 编译器无从得知 RSP 已被改写, # 若两块之间出现任何编译器生成的栈使用(spill/调用),会覆盖刚压栈的寄存器值。 # 故只可在**编译期不产生任何栈使用**的上下文(如 naked 汇编区)里成对使用。 -def pushall() -> t.CInline | t.CVoid: +inline def pushall(): c.Asm(f""" push rax push rbx @@ -94,7 +85,7 @@ def pushall() -> t.CInline | t.CVoid: [t.ASM_DESCR.CLOBBER_MEMORY] ) -def popall() -> t.CInline | t.CVoid: +inline def popall(): c.Asm(f""" pop r15 pop r14 @@ -119,7 +110,7 @@ def popall() -> t.CInline | t.CVoid: # 寄存器 clobber 是有意为之,而非疏漏。另:输入约束 REG_ANY='r' 是"仅寄存器", # 若改成声明 15 个通用寄存器 clobber,LLVM 将无寄存器可分配给输入 → 编译期 # "ran out of registers";RSP 亦无法声明。当前全仓无调用点。 -def cpu_switch_context(old_stack: t.CUInt64T | t.CPtr, new_stack: t.CUInt64T): +def cpu_switch_context(old_stack: uint64*, new_stack: uint64): c.Asm(f""" push rax push rbx diff --git a/ast/__init__.vp b/ast/__init__.vp index 02c9cb9..d2de36a 100644 --- a/ast/__init__.vp +++ b/ast/__init__.vp @@ -63,13 +63,12 @@ from .parser import get_parse_err_line, get_parse_err_col, get_parse_err_msg # Global Memory Pool Pointer (follows project rules: declare _mbuddy) # User initializes in main: ast._mbuddy = memhub.MemBuddy(arena, size) # ============================================================ -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================ # Common API: parse # ============================================================ - def parse(src: str, pool: rawptr[memhub.MemManager]) -> rawptr[AST]: """Parse Python source code, return the AST Module node. @@ -80,16 +79,13 @@ def parse(src: str, pool: rawptr[memhub.MemManager]) -> rawptr[AST]: Returns: AST Module node, or None """ - if src is None or pool is None: - return None + if src is None or pool is None: return None _init_tables(pool) lx: rawptr[Lexer] = new_lexer(pool) - if lx is None: - return None + if lx is None: return None _lexer_init(lx, src, pool) tokens: rawptr[Token] = tokenize(lx) - if tokens is None: - return None + if tokens is None: return None tree: rawptr[AST] = parse_tokens(pool, tokens) return tree @@ -104,8 +100,7 @@ def parse_expression(src: str, pool: rawptr[memhub.MemManager]) -> rawptr[Expres Returns: Expression node (包装节点,body 字段为实际表达式), or None """ - if src is None or pool is None: - return None + if src is None or pool is None: return None _init_tables(pool) lx: rawptr[Lexer] = new_lexer(pool) if lx is None: return None diff --git a/ast/astaux.vp b/ast/astaux.vp index 62fda68..19e33c9 100644 --- a/ast/astaux.vp +++ b/ast/astaux.vp @@ -12,21 +12,17 @@ from .base import ( # ============================================================ # ExceptHandler Node # ============================================================ - class ExceptHandler(AST): """ExceptHandler(type: AST, name: str)""" type: rawptr[AST] name: str - def __new__(self, pool: rawptr[memhub.MemManager], - type: rawptr[AST], name: str): + def __new__(self, pool: rawptr[memhub.MemManager], type: rawptr[AST], name: str): ptr: rawptr[ExceptHandler] = pool.alloc(ExceptHandler.__sizeof__()) - if ptr: - string.memset(ptr, 0, ExceptHandler.__sizeof__()) + if ptr: string.memset(ptr, 0, ExceptHandler.__sizeof__()) return ptr - def __init__(self, pool: rawptr[memhub.MemManager], - type: rawptr[AST], name: str): + def __init__(self, pool: rawptr[memhub.MemManager], type: rawptr[AST], name: str): _init_ast(self, pool, 0, 0) self.type = type self.name = _copy_str(pool, name) @@ -37,8 +33,7 @@ class ExceptHandler(AST): def type_name(self) -> str: return "ExceptHandler" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "ExceptHandler(type=") if self.type is not None: pos = self.type.dump(buf, size, pos) @@ -55,7 +50,6 @@ class ExceptHandler(AST): # ============================================================ # Arguments Node # ============================================================ - class Arguments(AST): """Arguments(args: list[AST | CPtr], vararg: AST, kwarg: AST, defaults: list[AST | CPtr], kw_defaults: list[AST | CPtr])""" @@ -71,8 +65,7 @@ class Arguments(AST): defaults: rawptr[list[rawptr[AST]]], kw_defaults: rawptr[list[rawptr[AST]]]): ptr: rawptr[Arguments] = pool.alloc(Arguments.__sizeof__()) - if ptr: - string.memset(ptr, 0, Arguments.__sizeof__()) + if ptr: string.memset(ptr, 0, Arguments.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -96,8 +89,8 @@ class Arguments(AST): def type_name(self) -> str: return "Arguments" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, + pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Arguments(args=") pos = _dump_list(self.args, buf, size, pos) pos = _emit(buf, size, pos, ", vararg=") @@ -121,21 +114,17 @@ class Arguments(AST): # ============================================================ # Arg Node # ============================================================ - class Arg(AST): """Arg(arg: str, annotation: AST)""" arg: str annotation: rawptr[AST] - def __new__(self, pool: rawptr[memhub.MemManager], - arg: str, annotation: rawptr[AST]): + def __new__(self, pool: rawptr[memhub.MemManager], arg: str, annotation: rawptr[AST]): ptr: rawptr[Arg] = pool.alloc(Arg.__sizeof__()) - if ptr: - string.memset(ptr, 0, Arg.__sizeof__()) + if ptr: string.memset(ptr, 0, Arg.__sizeof__()) return ptr - def __init__(self, pool: rawptr[memhub.MemManager], - arg: str, annotation: rawptr[AST]): + def __init__(self, pool: rawptr[memhub.MemManager], arg: str, annotation: rawptr[AST]): _init_ast(self, pool, 0, 0) self.arg = _copy_str(pool, arg) self.annotation = annotation @@ -146,8 +135,7 @@ class Arg(AST): def type_name(self) -> str: return "Arg" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Arg(arg='") pos = _emit_str(buf, size, pos, self.arg) pos = _emit(buf, size, pos, "', annotation=") @@ -162,21 +150,17 @@ class Arg(AST): # ============================================================ # Keyword Node # ============================================================ - class Keyword(AST): """Keyword(arg: str, value: AST)""" arg: str value: rawptr[AST] - def __new__(self, pool: rawptr[memhub.MemManager], - arg: str, value: rawptr[AST]): + def __new__(self, pool: rawptr[memhub.MemManager], arg: str, value: rawptr[AST]): ptr: rawptr[Keyword] = pool.alloc(Keyword.__sizeof__()) - if ptr: - string.memset(ptr, 0, Keyword.__sizeof__()) + if ptr: string.memset(ptr, 0, Keyword.__sizeof__()) return ptr - def __init__(self, pool: rawptr[memhub.MemManager], - arg: str, value: rawptr[AST]): + def __init__(self, pool: rawptr[memhub.MemManager], arg: str, value: rawptr[AST]): _init_ast(self, pool, 0, 0) self.arg = _copy_str(pool, arg) self.value = value @@ -187,8 +171,7 @@ class Keyword(AST): def type_name(self) -> str: return "Keyword" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Keyword(arg='") pos = _emit_str(buf, size, pos, self.arg) pos = _emit(buf, size, pos, "', value=") @@ -203,17 +186,14 @@ class Keyword(AST): # ============================================================ # Alias Node # ============================================================ - class Alias(AST): """Alias(name: str, asname: str)""" name: str asname: str - def __new__(self, pool: rawptr[memhub.MemManager], - name: str, asname: str): + def __new__(self, pool: rawptr[memhub.MemManager], name: str, asname: str): ptr: rawptr[Alias] = pool.alloc(Alias.__sizeof__()) - if ptr: - string.memset(ptr, 0, Alias.__sizeof__()) + if ptr: string.memset(ptr, 0, Alias.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -228,8 +208,7 @@ class Alias(AST): def type_name(self) -> str: return "Alias" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Alias(name='") pos = _emit_str(buf, size, pos, self.name) pos = _emit(buf, size, pos, "', asname='") @@ -247,11 +226,9 @@ class WithItem(AST): context_expr: rawptr[AST] optional_vars: rawptr[AST] - def __new__(self, pool: rawptr[memhub.MemManager], - context_expr: rawptr[AST], optional_vars: rawptr[AST]): + def __new__(self, pool: rawptr[memhub.MemManager], context_expr: rawptr[AST], optional_vars: rawptr[AST]): ptr: rawptr[WithItem] = pool.alloc(WithItem.__sizeof__()) - if ptr: - string.memset(ptr, 0, WithItem.__sizeof__()) + if ptr: string.memset(ptr, 0, WithItem.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -266,8 +243,7 @@ class WithItem(AST): def type_name(self) -> str: return "WithItem" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "WithItem(context_expr=") if self.context_expr is not None: pos = self.context_expr.dump(buf, size, pos) @@ -317,8 +293,8 @@ class Comprehension(AST): def type_name(self) -> str: return "Comprehension" - def dump(self, buf: bytes, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: bytes, size: sizet, + pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Comprehension(target=") if self.target is not None: pos = self.target.dump(buf, size, pos) diff --git a/ast/base.vp b/ast/base.vp index d07e563..c66cd54 100644 --- a/ast/base.vp +++ b/ast/base.vp @@ -9,184 +9,110 @@ from .tokens import TokOp # ============================================================ # ASTKind - Node type enum (kind() virtual function return value) # ============================================================ - -class ASTKind(t.CEnum): +enum ASTKind: # Core 15 nodes - Module: t.State - FunctionDef: t.State - ClassDef: t.State - Assign: t.State - If: t.State - For: t.State - While: t.State - Return: t.State - Expr: t.State - Name: t.State - Constant: t.State - BinOp: t.State - UnaryOp: t.State - Call: t.State - Compare: t.State + Module, FunctionDef, ClassDef, Assign + If, For, While, Return + Expr, Name, Constant + BinOp, UnaryOp + Call, Compare # Module Layer - Expression: t.State - Interactive: t.State - FunctionType: t.State + Expression, Interactive, FunctionType # Statement - Delete: t.State - AugAssign: t.State - AnnAssign: t.State - With: t.State - Raise: t.State - Try: t.State - Assert: t.State - Global: t.State - Nonlocal: t.State - Pass: t.State - Break: t.State - Continue: t.State - Import: t.State - ImportFrom: t.State - Match: t.State + Delete, AugAssign, AnnAssign + With, Raise, Try, Assert + Global, Nonlocal + Pass, Break, Continue + Import, ImportFrom, Match # Expression Layer - BoolOp: t.State - Lambda: t.State - IfExp: t.State - Dict: t.State - Set: t.State - ListComp: t.State - SetComp: t.State - DictComp: t.State - GeneratorExp: t.State - Await: t.State - Yield: t.State - YieldFrom: t.State - FormattedValue: t.State - JoinedStr: t.State - Attribute: t.State - Subscript: t.State - Starred: t.State - List: t.State - Tuple: t.State - Slice: t.State - NamedExpr: t.State + BoolOp, Lambda, IfExp + Dict, Set, ListComp, SetComp, DictComp + GeneratorExp, Await, Yield, YieldFrom + FormattedValue, JoinedStr + Attribute, Subscript + Starred + List, Tuple, Slice + NamedExpr # Auxiliary Nodes - ExceptHandler: t.State - Arguments: t.State - Arg: t.State - Keyword: t.State - Alias: t.State - WithItem: t.State - Comprehension: t.State - OpNode: t.State + ExceptHandler + Arguments, Arg + Keyword, Alias + WithItem, Comprehension, OpNode # Pattern Matching - MatchCase: t.State - MatchValue: t.State - MatchSingleton: t.State - MatchSequence: t.State - MatchMapping: t.State - MatchClass: t.State - MatchStar: t.State - MatchAs: t.State - MatchOr: t.State + MatchCase, MatchValue + MatchSingleton, MatchSequence, MatchMapping + MatchClass, MatchStar, MatchAs, MatchOr # ============================================================ # ASTCtx - Name context (Load/Store/Del) # ============================================================ - -class ASTCtx(t.CEnum): - Load: t.State - Store: t.State - Del: t.State +enum ASTCtx: + Load, Store, Del # ============================================================ # OpKind - Operator enum (BinOp/UnaryOp/Compare) # ============================================================ - -class OpKind(t.CEnum): +enum OpKind: # Binary arithmetic operators - Add: t.State - Sub: t.State - Mult: t.State - MatMult: t.State - Div: t.State - Mod: t.State - Pow: t.State - LShift: t.State - RShift: t.State - BitOr: t.State - BitXor: t.State - BitAnd: t.State - FloorDiv: t.State + Add, Sub + Mult, MatMult + Div, Mod, Pow + LShift, RShift + BitOr, BitXor, BitAnd + FloorDiv # Boolean operators - And: t.State - Or: t.State + And, Or # Comparison operators - Eq: t.State - Ne: t.State - Lt: t.State - Le: t.State - Gt: t.State - Ge: t.State - Is: t.State - IsNot: t.State - In: t.State - NotIn: t.State + Eq, Ne, Lt, Le, Gt, Ge + Is, IsNot + In, NotIn # Unary operators - Not: t.State - UAdd: t.State - USub: t.State - Invert: t.State - Deref: t.State - AddrOf: t.State + Not, UAdd, USub + Invert, Deref, AddrOf # None - NoneOp: t.State + NoneOp # Constant subtype identifiers -CONST_INT: t.CDefine = 1 -CONST_FLOAT: t.CDefine = 2 -CONST_STR: t.CDefine = 3 -CONST_BOOL: t.CDefine = 4 -CONST_NONE: t.CDefine = 5 -CONST_CHAR: t.CDefine = 6 +define CONST_INT = 1 +define CONST_FLOAT = 2 +define CONST_STR = 3 +define CONST_BOOL = 4 +define CONST_NONE = 5 +define CONST_CHAR = 6 # Node flags -FLAG_IS_ASYNC: t.CDefine = 1 -FLAG_SIMPLE: t.CDefine = 2 -FLAG_HAS_STAR: t.CDefine = 4 -FLAG_IS_EXTERN: t.CDefine = 8 -FLAG_IS_EXPORT: t.CDefine = 16 -FLAG_IS_DEFINE: t.CDefine = 32 +define FLAG_IS_ASYNC = 1 +define FLAG_SIMPLE = 2 +define FLAG_HAS_STAR = 4 +define FLAG_IS_EXTERN = 8 +define FLAG_IS_EXPORT = 16 +define FLAG_IS_DEFINE = 32 # ============================================================ # ASTFlag - Node flags enum # ============================================================ - -class ASTFlag(t.CEnum): - IsAsync: t.State - Simple: t.State - HasStar: t.State +enum ASTFlag: + IsAsync, Simple, HasStar # ============================================================ # Helper Functions # ============================================================ - def _copy_str(pool: rawptr[memhub.MemManager], src: str) -> str: """Allocate and copy a C string from pool.""" if src is None: return None - slen: t.CSizeT = string.strlen(src) + slen: sizet = 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: rawptr[AST], lineno: int, col_offset: int, - end_lineno: int, end_col_offset: int): +def _set_pos(node: rawptr[AST], lineno: int, col_offset: int, end_lineno: int, end_col_offset: int): if node is None: return node.lineno = lineno node.col_offset = col_offset @@ -202,8 +128,7 @@ def _inherit_pos(node: rawptr[AST], ref: rawptr[AST]): node.end_col_offset = ref.end_col_offset -def _init_ast(node: rawptr[AST], pool: rawptr[memhub.MemManager], - lineno: int, col: int): +def _init_ast(node: rawptr[AST], pool: rawptr[memhub.MemManager], lineno: int, col: int): """Initialize AST base fields.""" node.parent = None node.pool = pool @@ -217,13 +142,9 @@ def _init_ast(node: rawptr[AST], pool: rawptr[memhub.MemManager], def _set_parent_list(lst: list[rawptr[AST]] | t.CPtr, parent: rawptr[AST]): """Set list children parent pointers.""" if lst is None: return - n: t.CSizeT = lst.__len__() - i: t.CSizeT = 0 - while i < n: + for i in range(lst.__len__()): child: rawptr[AST] = lst.get(i) - if child is not None: - child.parent = parent - i += 1 + if child is not None: child.parent = parent def _append_child(lst: list[rawptr[AST]] | t.CPtr, node: rawptr[AST], @@ -231,8 +152,7 @@ def _append_child(lst: list[rawptr[AST]] | t.CPtr, node: rawptr[AST], """Append child nodes to a list (module-level function, to avoid conflicts with the AST.append method name). Call this function within the AST.append method to bypass the compiler mistaking list.append for a virtual function call to AST.append when doing type inference.""" - if lst is None or node is None: - return + if lst is None or node is None: return lst.append(node) @@ -288,43 +208,34 @@ def _cmpop_from_op(op_id: int) -> int: # dump Helper Functions # ============================================================ -def _emit(buf: str, size: t.CSizeT, pos: t.CSizeT, - text: str) -> t.CSizeT: +def _emit(buf: str, size: sizet, pos: sizet, text: str) -> sizet: """Append literal to buf+pos.""" - if buf is None or pos >= size: - return pos + if buf is None or pos >= size: return pos cur: str = str(uint64(buf) + pos) - rem: t.CSizeT = size - pos + rem: sizet = size - pos n: int = viperlib.snprintf(cur, rem, "%s", text) - if n < 0: - return pos - return pos + t.CSizeT(n) + if n < 0: return pos + return pos + sizet(n) -def _emit_str(buf: str, size: t.CSizeT, pos: t.CSizeT, - text: str) -> t.CSizeT: +def _emit_str(buf: str, size: sizet, pos: sizet, text: str) -> sizet: """Append a string value to buf pos (using %s format)""" - if buf is None or pos >= size: - return pos + if buf is None or pos >= size: return pos cur: str = str(uint64(buf) + pos) - rem: t.CSizeT = size - pos + rem: sizet = size - pos n: int = viperlib.snprintf(cur, rem, "%s", text) - if n < 0: - return pos - return pos + t.CSizeT(n) + if n < 0: return pos + return pos + sizet(n) -def _emit_int(buf: str, size: t.CSizeT, pos: t.CSizeT, - val: int64) -> t.CSizeT: +def _emit_int(buf: str, size: sizet, pos: sizet, val: int64) -> sizet: """Append an integer value to buf pos (using %lld format).""" - if buf is None or pos >= size: - return pos + if buf is None or pos >= size: return pos cur: str = str(uint64(buf) + pos) - rem: t.CSizeT = size - pos + rem: sizet = size - pos n: int = viperlib.snprintf(cur, rem, "%lld", val) - if n < 0: - return pos - return pos + t.CSizeT(n) + if n < 0: return pos + return pos + sizet(n) def _op_name(op: int) -> str: @@ -363,42 +274,31 @@ def _op_name(op: int) -> str: return "NoneOp" -def _dump_list(lst: list[rawptr[AST]] | t.CPtr, buf: str, - size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT: +def _dump_list(lst: list[rawptr[AST]] | t.CPtr, buf: str, size: sizet, pos: sizet) -> sizet: """Traverse a list[AST | CPtr] container, polymorphically dump each element.""" if lst is None: pos = _emit(buf, size, pos, "[]") return pos pos = _emit(buf, size, pos, "[") - n: t.CSizeT = lst.__len__() - i: t.CSizeT = 0 - while i < n: - if i > 0: - pos = _emit(buf, size, pos, ", ") + for i in range(lst.__len__()): + if i > 0: pos = _emit(buf, size, pos, ", ") child: rawptr[AST] = lst.get(i) - if child is not None: - pos = child.dump(buf, size, pos) - i += 1 + if child is not None: pos = child.dump(buf, size, pos) pos = _emit(buf, size, pos, "]") return pos -def _dump_op_list(lst: t.CPtr, buf: str, - size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT: +def _dump_op_list(lst: t.CPtr, buf: str, size: sizet, pos: sizet) -> sizet: """Traverse a list[CInt] (OpKind values), output a list of op names.""" if lst is None: pos = _emit(buf, size, pos, "[]") return pos ops_list: rawptr[list[int]] = (rawptr[list[int]])(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, ", ") + for i in range(ops_list.__len__()): + if i > 0: pos = _emit(buf, size, pos, ", ") op: int = ops_list.get(i) pos = _emit(buf, size, pos, _op_name(op)) - i += 1 pos = _emit(buf, size, pos, "]") return pos @@ -410,7 +310,6 @@ def _dump_op_list(lst: t.CPtr, buf: str, # Child nodes are stored in a list[AST | CPtr] container (O(1) random access, more efficient than linked lists) # The parent field maintains a pointer to the parent (used for upward traversal) # ============================================================ - @t.CVTable class AST: """AST node base class. All specific node classes inherit from this. @@ -438,8 +337,7 @@ class AST: """Return the node type name, subclasses override""" return "AST" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: """Polymorphic dump: subclasses override to define custom format. Returns the written pos""" return pos @@ -456,10 +354,8 @@ class AST: Note: list[AST|CPtr] is currently stored by value (compiler limitation), so you must set node.parent before appending, so the parent in the copy is correct.""" - if self is None or node is None: - return - if self.children is None: - self.children = list[rawptr[AST]](self.pool, 8) + if self is None or node is None: return + if self.children is None: self.children = list[rawptr[AST]](self.pool, 8) node.parent = self _append_child(self.children, node, self.pool) @@ -472,7 +368,6 @@ class AST: # (依赖 TPV isinstance 子类集合判定 + 三层 vtable 继承)。 # 不 override kind()(继承 AST 的 0),具体节点各自返回 ASTKind 值。 # ============================================================ - @t.CVTable class Stmt(AST): """语句节点基类(Assign/If/For/While/Return/...)""" @@ -487,7 +382,6 @@ class Stmt(AST): # 命名说明:不能叫 Expr——ASTKind.Expr(base.vp L23)与 stmts.vp 的 # Expr 类已是"表达式语句"(Expression Statement)的既有语义。 # ============================================================ - @t.CVTable class ExprNode(AST): """表达式节点基类(Name/Constant/Call/BinOp/...)""" @@ -496,15 +390,10 @@ class ExprNode(AST): # ============================================================ # Module dump function (for ast.dump(node, buf, size)) # ============================================================ - -def dump(node: rawptr[AST], buf: str, size: t.CSizeT): +def dump(node: rawptr[AST], buf: str, size: sizet): """Serialize AST node to buf (with capacity size)""" - if node is None or buf is None or size == 0: - return + if node is None or buf is None or size == 0: return buf[0] = '\0' - final_pos: t.CSizeT = node.dump(buf, size, 0) + final_pos: sizet = node.dump(buf, size, 0) # NUL-terminate to prevent printf overflow - if final_pos < size: - buf[final_pos] = '\0' - else: - buf[size - 1] = '\0' + buf[final_pos if final_pos < size else size - 1] = '\0' diff --git a/ast/exprs.vp b/ast/exprs.vp index f8de024..2cf442f 100644 --- a/ast/exprs.vp +++ b/ast/exprs.vp @@ -20,15 +20,12 @@ class Name(ExprNode): id: str ctx: int - def __new__(self, pool: rawptr[memhub.MemManager], - id: str, ctx: int): + def __new__(self, pool: rawptr[memhub.MemManager], id: str, ctx: int): ptr: rawptr[Name] = pool.alloc(Name.__sizeof__()) - if ptr: - string.memset(ptr, 0, Name.__sizeof__()) + if ptr: string.memset(ptr, 0, Name.__sizeof__()) return ptr - def __init__(self, pool: rawptr[memhub.MemManager], - id: str, ctx: int): + def __init__(self, pool: rawptr[memhub.MemManager], id: str, ctx: int): _init_ast(self, pool, 0, 0) self.id = _copy_str(pool, id) self.ctx = ctx @@ -39,8 +36,7 @@ class Name(ExprNode): def type_name(self) -> str: return "Name" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Name(id='") pos = _emit_str(buf, size, pos, self.id) pos = _emit(buf, size, pos, "', ctx=") @@ -56,29 +52,25 @@ class Name(ExprNode): def name_get_id(node: rawptr[Name]) -> str: """获取 Name.id 字段(跨模块访问器,stub 字段访问陷阱防护)""" - if node is None: - return None + if node is None: return None return node.id def constant_get_str_val(node: rawptr[Constant]) -> str: """获取 Constant.str_val 字段(跨模块访问器)""" - if node is None: - return None + if node is None: return None return node.str_val def binop_get_left(node: rawptr[BinOp]) -> rawptr[AST]: """获取 BinOp.left 字段(跨模块访问器)""" - if node is None: - return None + if node is None: return None return node.left def binop_get_right(node: rawptr[BinOp]) -> rawptr[AST]: """获取 BinOp.right 字段(跨模块访问器)""" - if node is None: - return None + if node is None: return None return node.right @@ -121,8 +113,7 @@ class Constant(ExprNode): def type_name(self) -> str: return "Constant" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Constant(value=") if self.const_kind == CONST_INT: pos = _emit_int(buf, size, pos, self.int_val) @@ -164,8 +155,7 @@ class BinOp(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], left: rawptr[AST], op: int, right: rawptr[AST]): ptr: rawptr[BinOp] = pool.alloc(BinOp.__sizeof__()) - if ptr: - string.memset(ptr, 0, BinOp.__sizeof__()) + if ptr: string.memset(ptr, 0, BinOp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -181,8 +171,7 @@ class BinOp(ExprNode): def type_name(self) -> str: return "BinOp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "BinOp(left=") if self.left is not None: pos = self.left.dump(buf, size, pos) @@ -211,8 +200,7 @@ class UnaryOp(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], op: int, operand: rawptr[AST]): ptr: rawptr[UnaryOp] = pool.alloc(UnaryOp.__sizeof__()) - if ptr: - string.memset(ptr, 0, UnaryOp.__sizeof__()) + if ptr: string.memset(ptr, 0, UnaryOp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -227,8 +215,7 @@ class UnaryOp(ExprNode): def type_name(self) -> str: return "UnaryOp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "UnaryOp(op=") pos = _emit(buf, size, pos, _op_name(self.op)) pos = _emit(buf, size, pos, ", operand=") @@ -255,8 +242,7 @@ class Compare(ExprNode): ops: t.CPtr, comparators: rawptr[list[rawptr[AST]]]): ptr: rawptr[Compare] = pool.alloc(Compare.__sizeof__()) - if ptr: - string.memset(ptr, 0, Compare.__sizeof__()) + if ptr: string.memset(ptr, 0, Compare.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -275,8 +261,7 @@ class Compare(ExprNode): def type_name(self) -> str: return "Compare" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Compare(left=") if self.left is not None: pos = self.left.dump(buf, size, pos) @@ -305,8 +290,7 @@ class Call(ExprNode): args: rawptr[list[rawptr[AST]]], keywords: rawptr[list[rawptr[AST]]]): ptr: rawptr[Call] = pool.alloc(Call.__sizeof__()) - if ptr: - string.memset(ptr, 0, Call.__sizeof__()) + if ptr: string.memset(ptr, 0, Call.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -326,8 +310,7 @@ class Call(ExprNode): def type_name(self) -> str: return "Call" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Call(func=") if self.func is not None: pos = self.func.dump(buf, size, pos) @@ -352,8 +335,7 @@ class BoolOp(ExprNode): op: int, values: rawptr[list[rawptr[AST]]]): ptr: rawptr[BoolOp] = pool.alloc(BoolOp.__sizeof__()) - if ptr: - string.memset(ptr, 0, BoolOp.__sizeof__()) + if ptr: string.memset(ptr, 0, BoolOp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -370,8 +352,7 @@ class BoolOp(ExprNode): def type_name(self) -> str: return "BoolOp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "BoolOp(op=") pos = _emit(buf, size, pos, _op_name(self.op)) pos = _emit(buf, size, pos, ", values=") @@ -392,8 +373,7 @@ class Lambda(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], args: rawptr[AST], body: rawptr[AST]): ptr: rawptr[Lambda] = pool.alloc(Lambda.__sizeof__()) - if ptr: - string.memset(ptr, 0, Lambda.__sizeof__()) + if ptr: string.memset(ptr, 0, Lambda.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -408,8 +388,7 @@ class Lambda(ExprNode): def type_name(self) -> str: return "Lambda" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Lambda(args=") if self.args is not None: pos = self.args.dump(buf, size, pos) @@ -438,8 +417,7 @@ class IfExp(ExprNode): test: rawptr[AST], body: rawptr[AST], orelse: rawptr[AST]): ptr: rawptr[IfExp] = pool.alloc(IfExp.__sizeof__()) - if ptr: - string.memset(ptr, 0, IfExp.__sizeof__()) + if ptr: string.memset(ptr, 0, IfExp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -456,8 +434,7 @@ class IfExp(ExprNode): def type_name(self) -> str: return "IfExp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "IfExp(test=") if self.test is not None: pos = self.test.dump(buf, size, pos) @@ -490,8 +467,7 @@ class Dict(ExprNode): keys: rawptr[list[rawptr[AST]]], values: rawptr[list[rawptr[AST]]]): ptr: rawptr[Dict] = pool.alloc(Dict.__sizeof__()) - if ptr: - string.memset(ptr, 0, Dict.__sizeof__()) + if ptr: string.memset(ptr, 0, Dict.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -509,8 +485,7 @@ class Dict(ExprNode): def type_name(self) -> str: return "Dict" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Dict(keys=") pos = _dump_list(self.keys, buf, size, pos) pos = _emit(buf, size, pos, ", values=") @@ -530,8 +505,7 @@ class Set(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], elts: rawptr[list[rawptr[AST]]]): ptr: rawptr[Set] = pool.alloc(Set.__sizeof__()) - if ptr: - string.memset(ptr, 0, Set.__sizeof__()) + if ptr: string.memset(ptr, 0, Set.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -546,8 +520,7 @@ class Set(ExprNode): def type_name(self) -> str: return "Set" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Set(elts=") pos = _dump_list(self.elts, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -567,8 +540,7 @@ class ListComp(ExprNode): elt: rawptr[AST], generators: rawptr[list[rawptr[AST]]]): ptr: rawptr[ListComp] = pool.alloc(ListComp.__sizeof__()) - if ptr: - string.memset(ptr, 0, ListComp.__sizeof__()) + if ptr: string.memset(ptr, 0, ListComp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -585,8 +557,7 @@ class ListComp(ExprNode): def type_name(self) -> str: return "ListComp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "ListComp(elt=") if self.elt is not None: pos = self.elt.dump(buf, size, pos) @@ -611,8 +582,7 @@ class SetComp(ExprNode): elt: rawptr[AST], generators: rawptr[list[rawptr[AST]]]): ptr: rawptr[SetComp] = pool.alloc(SetComp.__sizeof__()) - if ptr: - string.memset(ptr, 0, SetComp.__sizeof__()) + if ptr: string.memset(ptr, 0, SetComp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -629,8 +599,7 @@ class SetComp(ExprNode): def type_name(self) -> str: return "SetComp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "SetComp(elt=") if self.elt is not None: pos = self.elt.dump(buf, size, pos) @@ -656,8 +625,7 @@ class DictComp(ExprNode): key: rawptr[AST], value: rawptr[AST], generators: rawptr[list[rawptr[AST]]]): ptr: rawptr[DictComp] = pool.alloc(DictComp.__sizeof__()) - if ptr: - string.memset(ptr, 0, DictComp.__sizeof__()) + if ptr: string.memset(ptr, 0, DictComp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -675,8 +643,7 @@ class DictComp(ExprNode): def type_name(self) -> str: return "DictComp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "DictComp(key=") if self.key is not None: pos = self.key.dump(buf, size, pos) @@ -706,8 +673,7 @@ class GeneratorExp(ExprNode): elt: rawptr[AST], generators: rawptr[list[rawptr[AST]]]): ptr: rawptr[GeneratorExp] = pool.alloc(GeneratorExp.__sizeof__()) - if ptr: - string.memset(ptr, 0, GeneratorExp.__sizeof__()) + if ptr: string.memset(ptr, 0, GeneratorExp.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -724,8 +690,7 @@ class GeneratorExp(ExprNode): def type_name(self) -> str: return "GeneratorExp" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "GeneratorExp(elt=") if self.elt is not None: pos = self.elt.dump(buf, size, pos) @@ -747,8 +712,7 @@ class Await(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[Await] = pool.alloc(Await.__sizeof__()) - if ptr: - string.memset(ptr, 0, Await.__sizeof__()) + if ptr: string.memset(ptr, 0, Await.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -761,8 +725,7 @@ class Await(ExprNode): def type_name(self) -> str: return "Await" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Await(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -782,8 +745,7 @@ class Yield(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[Yield] = pool.alloc(Yield.__sizeof__()) - if ptr: - string.memset(ptr, 0, Yield.__sizeof__()) + if ptr: string.memset(ptr, 0, Yield.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -796,8 +758,7 @@ class Yield(ExprNode): def type_name(self) -> str: return "Yield" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Yield(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -817,8 +778,7 @@ class YieldFrom(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[YieldFrom] = pool.alloc(YieldFrom.__sizeof__()) - if ptr: - string.memset(ptr, 0, YieldFrom.__sizeof__()) + if ptr: string.memset(ptr, 0, YieldFrom.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -831,8 +791,7 @@ class YieldFrom(ExprNode): def type_name(self) -> str: return "YieldFrom" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "YieldFrom(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -856,8 +815,7 @@ class FormattedValue(ExprNode): value: rawptr[AST], conversion: int, format_spec: rawptr[AST]): ptr: rawptr[FormattedValue] = pool.alloc(FormattedValue.__sizeof__()) - if ptr: - string.memset(ptr, 0, FormattedValue.__sizeof__()) + if ptr: string.memset(ptr, 0, FormattedValue.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -874,8 +832,7 @@ class FormattedValue(ExprNode): def type_name(self) -> str: return "FormattedValue" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "FormattedValue(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -900,8 +857,7 @@ class JoinedStr(ExprNode): """JoinedStr(values: list[AST | CPtr])""" values: rawptr[list[rawptr[AST]]] - def __new__(self, pool: rawptr[memhub.MemManager], - values: rawptr[list[rawptr[AST]]]): + def __new__(self, pool: rawptr[memhub.MemManager], values: rawptr[list[rawptr[AST]]]): ptr: rawptr[JoinedStr] = pool.alloc(JoinedStr.__sizeof__()) if ptr: string.memset(ptr, 0, JoinedStr.__sizeof__()) @@ -919,8 +875,7 @@ class JoinedStr(ExprNode): def type_name(self) -> str: return "JoinedStr" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "JoinedStr(values=") pos = _dump_list(self.values, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -940,8 +895,7 @@ class Attribute(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST], attr: str, ctx: int): ptr: rawptr[Attribute] = pool.alloc(Attribute.__sizeof__()) - if ptr: - string.memset(ptr, 0, Attribute.__sizeof__()) + if ptr: string.memset(ptr, 0, Attribute.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -957,8 +911,7 @@ class Attribute(ExprNode): def type_name(self) -> str: return "Attribute" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Attribute(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -981,15 +934,13 @@ class Attribute(ExprNode): # ============================================================ def attribute_get_value(node: rawptr[Attribute]) -> rawptr[AST]: """获取 Attribute.value 字段(跨模块访问器)""" - if node is None: - return None + if node is None: return None return node.value def attribute_get_attr(node: rawptr[Attribute]) -> str: """获取 Attribute.attr 字段(跨模块访问器)""" - if node is None: - return None + if node is None: return None return node.attr @@ -1006,8 +957,7 @@ class Subscript(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST], slice: rawptr[AST], ctx: int): ptr: rawptr[Subscript] = pool.alloc(Subscript.__sizeof__()) - if ptr: - string.memset(ptr, 0, Subscript.__sizeof__()) + if ptr: string.memset(ptr, 0, Subscript.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1023,8 +973,7 @@ class Subscript(ExprNode): def type_name(self) -> str: return "Subscript" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Subscript(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -1053,8 +1002,7 @@ class Starred(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST], ctx: int): ptr: rawptr[Starred] = pool.alloc(Starred.__sizeof__()) - if ptr: - string.memset(ptr, 0, Starred.__sizeof__()) + if ptr: string.memset(ptr, 0, Starred.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1069,8 +1017,7 @@ class Starred(ExprNode): def type_name(self) -> str: return "Starred" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Starred(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -1094,8 +1041,7 @@ class List(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], elts: rawptr[list[rawptr[AST]]], ctx: int): ptr: rawptr[List] = pool.alloc(List.__sizeof__()) - if ptr: - string.memset(ptr, 0, List.__sizeof__()) + if ptr: string.memset(ptr, 0, List.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1111,8 +1057,7 @@ class List(ExprNode): def type_name(self) -> str: return "List" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "List(elts=") pos = _dump_list(self.elts, buf, size, pos) pos = _emit(buf, size, pos, ", ctx=") @@ -1133,8 +1078,7 @@ class Tuple(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], elts: rawptr[list[rawptr[AST]]], ctx: int): ptr: rawptr[Tuple] = pool.alloc(Tuple.__sizeof__()) - if ptr: - string.memset(ptr, 0, Tuple.__sizeof__()) + if ptr: string.memset(ptr, 0, Tuple.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1150,8 +1094,7 @@ class Tuple(ExprNode): def type_name(self) -> str: return "Tuple" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Tuple(elts=") pos = _dump_list(self.elts, buf, size, pos) pos = _emit(buf, size, pos, ", ctx=") @@ -1174,8 +1117,7 @@ class Slice(ExprNode): lower: rawptr[AST], upper: rawptr[AST], step: rawptr[AST]): ptr: rawptr[Slice] = pool.alloc(Slice.__sizeof__()) - if ptr: - string.memset(ptr, 0, Slice.__sizeof__()) + if ptr: string.memset(ptr, 0, Slice.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1192,8 +1134,7 @@ class Slice(ExprNode): def type_name(self) -> str: return "Slice" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Slice(lower=") if self.lower is not None: pos = self.lower.dump(buf, size, pos) @@ -1225,8 +1166,7 @@ class NamedExpr(ExprNode): def __new__(self, pool: rawptr[memhub.MemManager], target: rawptr[AST], value: rawptr[AST]): ptr: rawptr[NamedExpr] = pool.alloc(NamedExpr.__sizeof__()) - if ptr: - string.memset(ptr, 0, NamedExpr.__sizeof__()) + if ptr: string.memset(ptr, 0, NamedExpr.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1241,8 +1181,7 @@ class NamedExpr(ExprNode): def type_name(self) -> str: return "NamedExpr" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "NamedExpr(target=") if self.target is not None: pos = self.target.dump(buf, size, pos) @@ -1267,8 +1206,7 @@ class OpNode(AST): def __new__(self, pool: rawptr[memhub.MemManager], op: int): ptr: rawptr[OpNode] = pool.alloc(OpNode.__sizeof__()) - if ptr: - string.memset(ptr, 0, OpNode.__sizeof__()) + if ptr: string.memset(ptr, 0, OpNode.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], op: int): @@ -1281,8 +1219,7 @@ class OpNode(AST): def type_name(self) -> str: return "OpNode" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "OpNode(op=") pos = _emit(buf, size, pos, _op_name(self.op)) pos = _emit(buf, size, pos, ")") diff --git a/ast/lexer.vp b/ast/lexer.vp index 71cc2eb..e3a5a1f 100644 --- a/ast/lexer.vp +++ b/ast/lexer.vp @@ -2,14 +2,320 @@ import t, c from stdint import * import memhub import string +import stdio +import stdlib from .tokens import ( Token, TokenType, TokOp, _init_tables, _kw_lookup, _op_head, OpEntry, new_token, token_set_str, token_set_str_literal, ) +# ============================================================ +# 整数字面量溢出(词法层 fail-fast) +# +# 整数常量在 token/AST 中是 int64(tokens.vp `int_val` / exprs.vp `int_val`)。 +# 旧实现用 `string.atoll`(string.vp:292)在 int64 下 `num = num * 10 + digit` +# 逐位累加 ⇒ 值 > 2^64-1 时**静默回绕**(如 2^64 回绕成 0,2^64-1 回绕成 -1)。 +# 本实现在 `_emit_number` 里对**整数**字面量先做纯文本幅值判定 +# (`_lex_int_exceeds_u64`,与 AssignGenMixin._int_text_exceeds_64 同口径:按 +# 进制统计有效位数 / 与 2^64-1 的十进制文本做长度+字典序比较,**不落进任何定宽 +# 容器、不回绕后再比较**),超出 2^64-1 即记录 fail-fast(不再静默回绕)。 +# 合法范围 0..2^64-1 仍按 64 位位模式存入 int64(既有合法路径的产物形态不变, +# 如 0xFFFFFFFFFFFFFFFF → int64 -1、0xA5A5A5A5A5A5A5A5 保持其 64 位位模式)。 +# 各进制(2/8/10/16)口径与 TPC(Python int(x, 0),任意精度)一致:接受区间同为 +# [-2^63, 2^64-1](字面量本身无符号,负数侧由一元减表达),超出即拒绝。 +# +# 上报通道:lexer 无独立 fatal 出口,故记录到模块级三元组(`_lex_record_overflow`), +# 由 parser 的 parse_tokens 取出后转写 _g_parse_err_*(位置 + 消息),复用既有 +# Traceback/SyntaxError 报告路径("文件:行:列 + 源码行"由该路径补全并终止编译)。 +# 这覆盖全部源码字面量(文件级解析必经 parse_tokens);parse_expression 只用于编译器 +# 合成的短类型串,不承载源码字面量,故不另设通道。 +# ============================================================ +_g_lex_err_line: int = 0 +_g_lex_err_col: int = 0 +_g_lex_err_msg: str = None + + +def get_lex_err_line() -> int: + """最近一次词法层 fail-fast 的行号(0=无) + + 供 parser.parse_tokens 取出后转写解析错误通道(_g_parse_err_*)。 + """ + return _g_lex_err_line + + +def get_lex_err_col() -> int: + """最近一次词法层 fail-fast 的列号(0-based;-1 表示无列信息)""" + return _g_lex_err_col + + +def get_lex_err_msg() -> str: + """最近一次词法层 fail-fast 的消息(含字面量原文 / 超出的位宽 / 上限 / 修法建议)""" + return _g_lex_err_msg + + +def _lex_reset_err(): + """清空词法层 fail-fast 三元组(每次 tokenize 入口调用,避免跨文件串用旧错误)""" + global _g_lex_err_line, _g_lex_err_col, _g_lex_err_msg + _g_lex_err_line = 0 + _g_lex_err_col = 0 + _g_lex_err_msg = None + + +def _lex_record_overflow(text: str, lineno: int, col: int): + """记录整数字面量溢出(fail-fast;只记首次)。 + + 报文含:字面量原文 + **超出的位宽(至少 65 位,上限 2^64-1)** + 修法建议; + 文件:行:列 与源码行由调用方(parser.parse_tokens → dump_parse_traceback)补全。 + """ + global _g_lex_err_line, _g_lex_err_col, _g_lex_err_msg + if _g_lex_err_line != 0: + return + _g_lex_err_line = lineno + _g_lex_err_col = col + msg_buf: str = stdlib.malloc(512) + if msg_buf is not None: + stdio.snprintf(msg_buf, 512, + "[TPV] 整数字面量溢出: 字面量 '%s' 超出 64 位可表示范围" + "(按位模式解释的上限为 18446744073709551615 = 2^64-1," + "该字面量需要的位宽至少 65 位)。" + "禁止静默回绕/截断,已终止编译。" + "修法: 把该字面量改到 0..18446744073709551615 的 64 位位模式范围内;" + "本语言不存在更宽的整数类型,如需更大数值请拆分为多个 64 位字表达。", text) + _g_lex_err_msg = msg_buf + else: + _g_lex_err_msg = text + + +def _lex_int_exceeds_u64(text: str) -> int: + """整数字面量文本的幅值是否超出 64 位位模式上限 2^64-1(1=超出,0=未超出)。 + + 纯文本判定(与 AssignGenMixin._int_text_exceeds_64 同口径;**不落进任何定宽 + 容器、不回绕后再比较**)。只处理整数字面量(调用方保证 is_float==0);字面量 + 文本不含正负号(一元加/减是独立 token,不属于字面量本身)。 + + 十进制:去 '_' 与前导零后,与 '18446744073709551615'(2^64-1,20 位)按 + 长度 + 字典序比较(同位数时字典序 = 数值序)。 + 0x/0X :有效位数 > 16 ⇒ 超出(16 位十六进制的最大值为 2^64-1)。 + 0o/0O :有效位数 > 22 ⇒ 超出;== 22 位且首位 > '1' ⇒ 超出 + (8^21 = 2^63 ⇒ 22 位以 '1' 开头恰为 2^64-1 为上限)。 + 0b/0B :有效位数 > 64 ⇒ 超出。 + """ + if text is None: + return 0 + tl: sizet = string.strlen(text) + if tl == 0: + return 0 + # 进制判定(前缀大小写皆可) + base: int = 10 + start: sizet = 0 + if tl >= 2 and text[0] == '0': + pfx: char = text[1] + if pfx == 'x' or pfx == 'X': + base = 16 + start = 2 + elif pfx == 'o' or pfx == 'O': + base = 8 + start = 2 + elif pfx == 'b' or pfx == 'B': + base = 2 + start = 2 + # 统计有效位数(跳过 '_' 与前导零),并记下首个有效位 + sig: int = 0 + first: char = '0' + j: sizet = start + while j < tl: + ch: char = text[j] + j += 1 + if ch == '_': + continue + ok_digit: int = 0 + if base == 16: + if (ch >= '0' and ch <= '9') or (ch >= 'a' and ch <= 'f') or (ch >= 'A' and ch <= 'F'): + ok_digit = 1 + elif base == 10: + if ch >= '0' and ch <= '9': + ok_digit = 1 + elif base == 8: + if ch >= '0' and ch <= '7': + ok_digit = 1 + else: + if ch == '0' or ch == '1': + ok_digit = 1 + if ok_digit == 0: + break + if sig == 0: + if ch == '0': + continue # 前导零不计 + first = ch + sig += 1 + if sig == 0: + return 0 # 值 0 + if base == 16: + return 1 if sig > 16 else 0 + if base == 2: + return 1 if sig > 64 else 0 + if base == 8: + if sig > 22: + return 1 + if sig == 22 and first > '1': + return 1 + return 0 + # 十进制:有效位数与 2^64-1 的文本长度比较 + mlen: sizet = 20 + if sig > mlen: + return 1 + if sig < mlen: + return 0 + # 等长(20 位):逐位与 '18446744073709551615' 字典序比较 + max_text: str = "18446744073709551615" + d: sizet = 0 + k: sizet = start + lead: int = 1 + while k < tl and d < mlen: + c: char = text[k] + k += 1 + if c == '_': + continue + if c < '0' or c > '9': + return 0 + if lead != 0 and c == '0': + continue + lead = 0 + mc: char = max_text[d] + if c > mc: + return 1 + if c < mc: + return 0 + d += 1 + return 0 + + + +def _lex_mag_digit_val(ch: char, base: int) -> int: + """数字字符 → 位值(十六进制含 a-f/A-F;其余进制为 '0'..基-1)。""" + if base == 16: + return _hex_val(ch) + return int(ch) - 48 + + +def _lex_mag_gt_text(text: str, base: int, start: sizet, sig: int, max_text: str) -> int: + """整数字面量文本的有效数字是否 > 同位数上限文本(1=大于,0=不大于)。 + + 两侧均跳过 '_' 与前导零,逐位按**位值**比较(十六进制用 _hex_val,其余进制 + 字符序即位值序);纯文本判定,不落定宽容器、不回绕。 + """ + d: sizet = 0 + k: sizet = start + tl: sizet = string.strlen(text) + lead: int = 1 + while k < tl and d < sizet(sig): + c: char = text[k] + k += 1 + if c == '_': + continue + if base == 16: + if not ((c >= '0' and c <= '9') or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F')): + break + elif base == 10: + if c < '0' or c > '9': + break + elif base == 8: + if c < '0' or c > '7': + break + else: + if c != '0' and c != '1': + break + if lead != 0 and c == '0': + continue + lead = 0 + cv: int = _lex_mag_digit_val(c, base) + mv: int = _lex_mag_digit_val(max_text[d], base) + if cv > mv: + return 1 + if cv < mv: + return 0 + d += 1 + return 0 + + +def _lex_int_neg_exceeds_i64(text: str) -> int: + """整数字面量幅值是否**严格大于** 2^63(1=超出,0=未超出)。 + + 用于"一元减 + 整数字面量"的联合越界判定:`-` 是独立的一元运算符、不属于 + 字面量,故幅值合法的字面量(≤ 2^64-1,`_lex_int_exceeds_u64` 已放行)在取负 + 后可能 < -2^63。幅值恰为 2^63 时一元减结果 = INT64_MIN = -9223372036854775808 + (合法),故本判据用**严格大于**。 + + 纯文本判定(与 _lex_int_exceeds_u64 同口径,不落定宽容器、不回绕)。 + 2^63 的幅值文本:十进制 19 位 `9223372036854775808`;0x 16 位 + `8000000000000000`;0o 22 位 `1000000000000000000000`;0b 64 位(1 + 63 个 0)。 + """ + if text is None: + return 0 + tl: sizet = string.strlen(text) + if tl == 0: + return 0 + base: int = 10 + start: sizet = 0 + if tl >= 2 and text[0] == '0': + pfx: char = text[1] + if pfx == 'x' or pfx == 'X': + base = 16 + start = 2 + elif pfx == 'o' or pfx == 'O': + base = 8 + start = 2 + elif pfx == 'b' or pfx == 'B': + base = 2 + start = 2 + sig: int = 0 + j: sizet = start + while j < tl: + ch: char = text[j] + j += 1 + if ch == '_': + continue + ok_digit: int = 0 + if base == 16: + if (ch >= '0' and ch <= '9') or (ch >= 'a' and ch <= 'f') or (ch >= 'A' and ch <= 'F'): + ok_digit = 1 + elif base == 10: + if ch >= '0' and ch <= '9': + ok_digit = 1 + elif base == 8: + if ch >= '0' and ch <= '7': + ok_digit = 1 + else: + if ch == '0' or ch == '1': + ok_digit = 1 + if ok_digit == 0: + break + if sig == 0 and ch == '0': + continue # 前导零不计 + sig += 1 + if sig == 0: + return 0 # 值 0 + if base == 16: + if sig > 16: return 1 + if sig < 16: return 0 + return _lex_mag_gt_text(text, 16, start, sig, "8000000000000000") + if base == 2: + if sig > 64: return 1 + if sig < 64: return 0 + return _lex_mag_gt_text(text, 2, start, sig, + "1000000000000000000000000000000000000000000000000000000000000000") + if base == 8: + if sig > 22: return 1 + if sig < 22: return 0 + return _lex_mag_gt_text(text, 8, start, sig, "1000000000000000000000") + if sig > 19: return 1 + if sig < 19: return 0 + return _lex_mag_gt_text(text, 10, start, sig, "9223372036854775808") + + # Maximum Indentation Stack Depth -LEXER_MAX_INDENT: t.CDefine = 256 +define LEXER_MAX_INDENT = 256 # ============================================================ @@ -17,8 +323,8 @@ LEXER_MAX_INDENT: t.CDefine = 256 # ============================================================ class Lexer: src: str # Source code (NUL-terminated) - pos: t.CSizeT # Current position - len: t.CSizeT # Source code length + pos: sizet # Current position + len: sizet # Source code length lineno: int # Current line number (1-based) col: int # Current column number (0-based) pool: rawptr[memhub.MemManager] # Memory pool @@ -32,8 +338,7 @@ class Lexer: def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[Lexer] = pool.alloc(Lexer.__sizeof__()) - if ptr: - string.memset(ptr, 0, Lexer.__sizeof__()) + if ptr: string.memset(ptr, 0, Lexer.__sizeof__()) return ptr @@ -42,8 +347,7 @@ def new_lexer(pool: rawptr[memhub.MemManager]) -> rawptr[Lexer]: return Lexer(pool) -def _lexer_init(lx: rawptr[Lexer], src: str, - pool: rawptr[memhub.MemManager]): +def _lexer_init(lx: rawptr[Lexer], src: str, pool: rawptr[memhub.MemManager]): """Initialize Lexer""" if lx == None: return lx.src = src @@ -54,8 +358,7 @@ def _lexer_init(lx: rawptr[Lexer], src: str, lx.pool = pool # Allocate indentation stack lx.indent_stack = pool.alloc(LEXER_MAX_INDENT * 8) - if lx.indent_stack != None: - string.memset(lx.indent_stack, 0, LEXER_MAX_INDENT * 8) + if lx.indent_stack != None: string.memset(lx.indent_stack, 0, LEXER_MAX_INDENT * 8) lx.indent_top = -1 # Push 0 (base indent) if lx.indent_stack != None: @@ -73,25 +376,22 @@ def _lexer_init(lx: rawptr[Lexer], src: str, # Auxiliary Functions # ============================================================ -def _peek(lx: rawptr[Lexer], offset: t.CSizeT) -> t.CChar: +def _peek(lx: rawptr[Lexer], offset: sizet) -> char: """Peek character at position pos+offset, return '\0' if out of bounds""" - p: t.CSizeT = lx.pos + offset - if p >= lx.len: - return '\0' + p: sizet = lx.pos + offset + if p >= lx.len: return '\0' return lx.src[p] -def _peek_cur(lx: rawptr[Lexer]) -> t.CChar: - if lx.pos >= lx.len: - return '\0' +def _peek_cur(lx: rawptr[Lexer]) -> char: + if lx.pos >= lx.len: return '\0' return lx.src[lx.pos] -def _advance(lx: rawptr[Lexer]) -> t.CChar: +def _advance(lx: rawptr[Lexer]) -> char: """Advance one character, return the character""" - if lx.pos >= lx.len: - return '\0' - ch: t.CChar = lx.src[lx.pos] + if lx.pos >= lx.len: return '\0' + ch: char = lx.src[lx.pos] lx.pos += 1 if ch == '\n': lx.lineno += 1 @@ -101,32 +401,32 @@ def _advance(lx: rawptr[Lexer]) -> t.CChar: return ch -def _is_alpha(ch: t.CChar) -> int: +def _is_alpha(ch: char) -> int: 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) -> int: +def _is_digit(ch: char) -> int: if ch >= '0' and ch <= '9': return 1 return 0 -def _is_alnum(ch: t.CChar) -> int: +def _is_alnum(ch: char) -> int: if _is_alpha(ch): return 1 if _is_digit(ch): return 1 return 0 -def _is_hex(ch: t.CChar) -> int: +def _is_hex(ch: char) -> int: 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 _hex_val(ch: t.CChar) -> int: +def _hex_val(ch: char) -> int: """十六进制字符转数值 0-15(供 \xNN 转义解析)""" if ch >= '0' and ch <= '9': return int(ch) - 48 if ch >= 'a' and ch <= 'f': return int(ch) - 87 @@ -134,8 +434,8 @@ def _hex_val(ch: t.CChar) -> int: return 0 -def _is_space(ch: t.CChar) -> int: - if ch == ' ': return 1 +def _is_space(ch: char) -> int: + if ch == ' ': return 1 if ch == '\t': return 1 if ch == '\f': return 1 if ch == '\v': return 1 @@ -173,11 +473,11 @@ def _handle_indent(lx: rawptr[Lexer]): # Skip empty lines and comment lines while lx.pos < lx.len: # Save line start position for non-empty lines - line_start_pos: t.CSizeT = lx.pos + line_start_pos: sizet = lx.pos line_start_col: int = lx.col # Skip whitespace, not across lines while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if ch == ' ' or ch == '\t' or ch == '\f' or ch == '\v': lx.pos += 1 lx.col += 1 @@ -220,10 +520,10 @@ def _handle_indent(lx: rawptr[Lexer]): # Calculate current line indent indent: int = 0 - save_pos: t.CSizeT = lx.pos + save_pos: sizet = lx.pos save_col: int = lx.col while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if ch == ' ': indent += 1 lx.pos += 1 @@ -269,17 +569,17 @@ def _handle_indent(lx: rawptr[Lexer]): # ============================================================ def _read_name(lx: rawptr[Lexer]): - start: t.CSizeT = lx.pos + start: sizet = lx.pos start_lineno: int = lx.lineno start_col: int = lx.col while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if _is_alnum(ch): lx.pos += 1 lx.col += 1 else: break - length: t.CSizeT = lx.pos - start + length: sizet = lx.pos - start tok: rawptr[Token] = new_token(lx.pool, TokenType.Name, start_lineno, start_col) if tok == None: return token_set_str(lx.pool, tok, lx.src, start, length) @@ -287,8 +587,7 @@ def _read_name(lx: rawptr[Lexer]): tok.end_col_offset = start_col + int(length) # Look up keyword if any kw_id: int = _kw_lookup(tok.str_val) - if kw_id: - tok.kw_subtype = kw_id + if kw_id: tok.kw_subtype = kw_id _emit(lx, tok) @@ -297,21 +596,21 @@ def _read_name(lx: rawptr[Lexer]): # ============================================================ def _read_number(lx: rawptr[Lexer]): - start: t.CSizeT = lx.pos + start: sizet = lx.pos start_lineno: int = lx.lineno start_col: int = lx.col is_float: int = 0 is_complex: int = 0 - ch0: t.CChar = lx.src[lx.pos] + ch0: char = lx.src[lx.pos] # Handle 0x/0o/0b prefix if ch0 == '0' and lx.pos + 1 < lx.len: - ch1: t.CChar = lx.src[lx.pos + 1] + ch1: char = 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] + ch: char = lx.src[lx.pos] if _is_hex(ch) or ch == '_': lx.pos += 1 lx.col += 1 @@ -323,7 +622,7 @@ def _read_number(lx: rawptr[Lexer]): lx.pos += 2 lx.col += 2 while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if ch >= '0' and ch <= '7': lx.pos += 1 lx.col += 1 @@ -338,7 +637,7 @@ def _read_number(lx: rawptr[Lexer]): lx.pos += 2 lx.col += 2 while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if ch == '0' or ch == '1' or ch == '_': lx.pos += 1 lx.col += 1 @@ -349,7 +648,7 @@ def _read_number(lx: rawptr[Lexer]): # Decimal integer/float while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if _is_digit(ch) or ch == '_': lx.pos += 1 lx.col += 1 @@ -362,7 +661,7 @@ def _read_number(lx: rawptr[Lexer]): lx.pos += 1 lx.col += 1 while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if _is_digit(ch) or ch == '_': lx.pos += 1 lx.col += 1 @@ -371,7 +670,7 @@ def _read_number(lx: rawptr[Lexer]): # Exponent part if lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if ch == 'e' or ch == 'E': is_float = 1 lx.pos += 1 @@ -382,7 +681,7 @@ def _read_number(lx: rawptr[Lexer]): lx.pos += 1 lx.col += 1 while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if _is_digit(ch) or ch == '_': lx.pos += 1 lx.col += 1 @@ -399,10 +698,10 @@ def _read_number(lx: rawptr[Lexer]): _emit_number(lx, start, start_lineno, start_col, is_float, is_complex, 0) -def _emit_number(lx: rawptr[Lexer], start: t.CSizeT, +def _emit_number(lx: rawptr[Lexer], start: sizet, start_lineno: int, start_col: int, is_float: int, is_complex: int, is_hex: int): - length: t.CSizeT = lx.pos - start + length: sizet = lx.pos - start tok: rawptr[Token] = new_token(lx.pool, TokenType.Number, start_lineno, start_col) if tok == None: return token_set_str(lx.pool, tok, lx.src, start, length) @@ -414,6 +713,10 @@ def _emit_number(lx: rawptr[Lexer], start: t.CSizeT, if is_float: tok.float_val = string.atof(tok.str_val) else: + # 整数字面量幅值 > 2^64-1:词法层 fail-fast(纯文本判定,不静默回绕)。 + # 合法区间 0..2^64-1 仍按 64 位位模式存入 int64(产物形态不变)。 + if _lex_int_exceeds_u64(tok.str_val) != 0: + _lex_record_overflow(tok.str_val, start_lineno, start_col) tok.int_val = string.atoll(tok.str_val) _emit(lx, tok) @@ -429,14 +732,14 @@ def _read_string(lx: rawptr[Lexer]): Later we need to support string prefixes like i16/i24""" start_lineno: int = lx.lineno start_col: int = lx.col - prefix_start: t.CSizeT = lx.pos + prefix_start: sizet = lx.pos # Read prefix (r/b/u/f) is_raw: int = 0 is_bytes: int = 0 is_fstring: int = 0 while lx.pos < lx.len: - ch: t.CChar = lx.src[lx.pos] + ch: char = lx.src[lx.pos] if ch == 'r' or ch == 'R': is_raw = 1 lx.pos += 1 @@ -460,7 +763,7 @@ def _read_string(lx: rawptr[Lexer]): return # Determine quote type - quote: t.CChar = lx.src[lx.pos] + quote: char = lx.src[lx.pos] if quote != '\'' and quote != '"': lx.error_count += 1 return @@ -471,7 +774,7 @@ def _read_string(lx: rawptr[Lexer]): 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 + content_start: sizet = lx.pos if is_triple: lx.pos += 3 lx.col += 3 @@ -480,7 +783,7 @@ def _read_string(lx: rawptr[Lexer]): lx.col += 1 # Read string content - content_buf_start: t.CSizeT = lx.pos + content_buf_start: sizet = lx.pos # f-string {} 表达式块嵌套深度(PEP 701 同引号嵌套字符串支持用) fstr_depth: int = 0 while lx.pos < lx.len: @@ -532,11 +835,11 @@ def _read_string(lx: rawptr[Lexer]): if fstr_depth > 0 and (ch == '\'' or ch == '"'): # {} 表达式块内允许嵌套字符串字面量(PEP 701 同引号嵌套): # 跳过到匹配引号,块内引号不终止外层 f-string。 - nq: t.CChar = ch + nq: char = ch lx.pos += 1 lx.col += 1 while lx.pos < lx.len: - c2: t.CChar = lx.src[lx.pos] + c2: char = lx.src[lx.pos] if c2 == '\\': lx.pos += 2 lx.col += 2 @@ -568,7 +871,7 @@ def _read_string(lx: rawptr[Lexer]): lx.pos += 1 lx.col += 1 - content_end: t.CSizeT = lx.pos + content_end: sizet = lx.pos # Skip the closing quote if is_triple: if lx.pos + 2 < lx.len: @@ -584,9 +887,9 @@ def _read_string(lx: rawptr[Lexer]): # Create token tok: rawptr[Token] = new_token(lx.pool, TokenType.String, start_lineno, start_col) if tok == None: return - content_len: t.CSizeT = content_end - content_buf_start + content_len: sizet = content_end - content_buf_start # esc_len: Actual bytes after escaping (used to check single character) - esc_len: t.CSizeT = content_len + esc_len: sizet = content_len # Handle escape sequences (non-raw strings) if is_raw == 0 and content_len > 0: @@ -595,13 +898,13 @@ def _read_string(lx: rawptr[Lexer]): 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 + wpos: sizet = 0 + rpos: sizet = 0 while rpos < content_len: - ch: t.CChar = lx.src[content_buf_start + rpos] + ch: char = 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] + next_ch: char = lx.src[content_buf_start + rpos] if next_ch == 'n': conv_buf[wpos] = '\n' elif next_ch == 't': @@ -629,11 +932,11 @@ def _read_string(lx: rawptr[Lexer]): # 此前当作未知转义保留('\\'+'x' 2 字节)→ esc_len≠1 → # '\x1b' 被判为 CONST_STR 而非 CONST_CHAR(27) → 字符数组 # 元素提取失败(desktop _ps2_set1 索引 1 恒 0 根因)。 - h1: t.CChar = lx.src[content_buf_start + rpos + 1] - h2: t.CChar = lx.src[content_buf_start + rpos + 2] + h1: char = lx.src[content_buf_start + rpos + 1] + h2: char = lx.src[content_buf_start + rpos + 2] if _is_hex(h1) != 0 and _is_hex(h2) != 0: hex_v: int = (_hex_val(h1) << 4) | _hex_val(h2) - conv_buf[wpos] = t.CChar(hex_v) + conv_buf[wpos] = char(hex_v) wpos += 1 rpos += 3 continue @@ -681,7 +984,7 @@ def _read_operator(lx: rawptr[Lexer]): """Greedy match operator""" start_lineno: int = lx.lineno start_col: int = lx.col - remaining: t.CSizeT = lx.len - lx.pos + remaining: sizet = lx.len - lx.pos # Traverse operator table, find longest match best_entry: rawptr[OpEntry] = None @@ -691,8 +994,8 @@ def _read_operator(lx: rawptr[Lexer]): if cur.length <= int(remaining): # Compare cur.name with src[pos:pos+cur.length] match: int = 1 - i: t.CSizeT = 0 - while i < t.CSizeT(cur.length): + i: sizet = 0 + while i < sizet(cur.length): if lx.src[lx.pos + i] != cur.name[i]: match = 0 break @@ -720,8 +1023,8 @@ def _read_operator(lx: rawptr[Lexer]): tok: rawptr[Token] = _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) + token_set_str(lx.pool, tok, lx.src, lx.pos, sizet(best_len)) + lx.pos += sizet(best_len) lx.col += best_len _emit(lx, tok) @@ -740,7 +1043,7 @@ def tokenize(lx: rawptr[Lexer]) -> rawptr[Token]: if lx.pos >= lx.len: break - ch: t.CChar = _peek_cur(lx) + ch: char = _peek_cur(lx) if ch == '\0': break @@ -799,13 +1102,13 @@ def tokenize(lx: rawptr[Lexer]) -> rawptr[Token]: 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] + ch1: char = lx.src[lx.pos + 1] if ch1 == '\'' or ch1 == '"': _read_string(lx) continue # Double prefixes like rb, br, rf, fr if lx.pos + 2 < lx.len: - ch2: t.CChar = lx.src[lx.pos + 2] + ch2: char = 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 == '"')): diff --git a/ast/match.vp b/ast/match.vp index 3d711a2..02ef401 100644 --- a/ast/match.vp +++ b/ast/match.vp @@ -10,9 +10,8 @@ from .base import ( # ============================================================ -# MatchCase 节点Node +# MatchCase Node # ============================================================ - class MatchCase(AST): """MatchCase(pattern: AST, guard: AST)""" pattern: rawptr[AST] @@ -21,8 +20,7 @@ class MatchCase(AST): def __new__(self, pool: rawptr[memhub.MemManager], pattern: rawptr[AST], guard: rawptr[AST]): ptr: rawptr[MatchCase] = pool.alloc(MatchCase.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchCase.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchCase.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -37,8 +35,7 @@ class MatchCase(AST): def type_name(self) -> str: return "MatchCase" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchCase(pattern=") if self.pattern is not None: pos = self.pattern.dump(buf, size, pos) @@ -54,15 +51,13 @@ class MatchCase(AST): # ============================================================ # MatchValue Node # ============================================================ - class MatchValue(AST): """MatchValue(value: AST)""" value: rawptr[AST] def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[MatchValue] = pool.alloc(MatchValue.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchValue.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchValue.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -75,8 +70,7 @@ class MatchValue(AST): def type_name(self) -> str: return "MatchValue" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchValue(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -87,15 +81,13 @@ class MatchValue(AST): # ============================================================ # MatchSingleton Node # ============================================================ - class MatchSingleton(AST): """MatchSingleton(value: AST)""" value: rawptr[AST] def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[MatchSingleton] = pool.alloc(MatchSingleton.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchSingleton.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchSingleton.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -108,8 +100,7 @@ class MatchSingleton(AST): def type_name(self) -> str: return "MatchSingleton" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchSingleton(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -120,7 +111,6 @@ class MatchSingleton(AST): # ============================================================ # MatchSequence Node # ============================================================ - class MatchSequence(AST): """MatchSequence(patterns: list[rawptr[AST]])""" patterns: rawptr[list[rawptr[AST]]] @@ -128,8 +118,7 @@ class MatchSequence(AST): def __new__(self, pool: rawptr[memhub.MemManager], patterns: rawptr[list[rawptr[AST]]]): ptr: rawptr[MatchSequence] = pool.alloc(MatchSequence.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchSequence.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchSequence.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -144,8 +133,7 @@ class MatchSequence(AST): def type_name(self) -> str: return "MatchSequence" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchSequence(patterns=") pos = _dump_list(self.patterns, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -155,7 +143,6 @@ class MatchSequence(AST): # ============================================================ # MatchMapping Node # ============================================================ - class MatchMapping(AST): """MatchMapping(keys: list[rawptr[AST]], patterns: list[rawptr[AST]], rest: str)""" keys: rawptr[list[rawptr[AST]]] @@ -167,8 +154,7 @@ class MatchMapping(AST): patterns: rawptr[list[rawptr[AST]]], rest: str): ptr: rawptr[MatchMapping] = pool.alloc(MatchMapping.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchMapping.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchMapping.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -188,8 +174,7 @@ class MatchMapping(AST): def type_name(self) -> str: return "MatchMapping" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchMapping(keys=") pos = _dump_list(self.keys, buf, size, pos) pos = _emit(buf, size, pos, ", patterns=") @@ -218,8 +203,7 @@ class MatchClass(AST): kwd_attrs: rawptr[list[rawptr[AST]]], kwd_patterns: rawptr[list[rawptr[AST]]]): ptr: rawptr[MatchClass] = pool.alloc(MatchClass.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchClass.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchClass.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -242,11 +226,9 @@ class MatchClass(AST): def type_name(self) -> str: return "MatchClass" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchClass(cls=") - if self.cls is not None: - pos = self.cls.dump(buf, size, pos) + 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=") @@ -267,8 +249,7 @@ class MatchStar(AST): def __new__(self, pool: rawptr[memhub.MemManager], name: str): ptr: rawptr[MatchStar] = pool.alloc(MatchStar.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchStar.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchStar.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], name: str): @@ -281,8 +262,7 @@ class MatchStar(AST): def type_name(self) -> str: return "MatchStar" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchStar(name='") pos = _emit_str(buf, size, pos, self.name) pos = _emit(buf, size, pos, "')") @@ -301,8 +281,7 @@ class MatchAs(AST): def __new__(self, pool: rawptr[memhub.MemManager], pattern: rawptr[AST], name: str): ptr: rawptr[MatchAs] = pool.alloc(MatchAs.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchAs.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchAs.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -317,11 +296,9 @@ class MatchAs(AST): def type_name(self) -> str: return "MatchAs" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchAs(pattern=") - if self.pattern is not None: - pos = self.pattern.dump(buf, size, pos) + 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, "')") @@ -339,8 +316,7 @@ class MatchOr(AST): def __new__(self, pool: rawptr[memhub.MemManager], patterns: rawptr[list[rawptr[AST]]]): ptr: rawptr[MatchOr] = pool.alloc(MatchOr.__sizeof__()) - if ptr: - string.memset(ptr, 0, MatchOr.__sizeof__()) + if ptr: string.memset(ptr, 0, MatchOr.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -355,8 +331,7 @@ class MatchOr(AST): def type_name(self) -> str: return "MatchOr" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "MatchOr(patterns=") pos = _dump_list(self.patterns, buf, size, pos) pos = _emit(buf, size, pos, ")") diff --git a/ast/parser.vp b/ast/parser.vp index 7a1129b..a5bfef3 100644 --- a/ast/parser.vp +++ b/ast/parser.vp @@ -32,7 +32,11 @@ from .match import ( MatchCase, MatchValue, MatchSingleton, MatchSequence, MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr, ) -from .lexer import Lexer, _lexer_init, tokenize, new_lexer +from .lexer import ( + Lexer, _lexer_init, tokenize, new_lexer, + get_lex_err_line, get_lex_err_col, get_lex_err_msg, + _lex_int_neg_exceeds_i64, +) # ============================================================ @@ -41,14 +45,18 @@ from .lexer import Lexer, _lexer_init, tokenize, new_lexer class Parser: tokens: rawptr[Token] # token linked list head cur: rawptr[Token] # current token + prev: rawptr[Token] # 上一个被消费的 token(供 `T*(x)` 紧邻判据) pool: rawptr[memhub.MemManager] # memory pool error_count: int # error count pending_decorators: rawptr[list[rawptr[AST]]] # pending decorators list + # 当前正在解析的套件的**直接拥有者**是否 class(1=类体,0=其它)。 + # 由 _parse_suite_into_children 按 owner_is_class 维护,供 virtual/novirtual + # 修饰符判"方法级修饰符是否直接写在类体内"(见 _ParseVirtualModified)。 + in_class_body: int def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[Parser] = pool.alloc(Parser.__sizeof__()) - if ptr: - string.memset(ptr, 0, Parser.__sizeof__()) + if ptr: string.memset(ptr, 0, Parser.__sizeof__()) return ptr @@ -62,9 +70,11 @@ def _parser_init(ps: rawptr[Parser], tokens: rawptr[Token], if ps is None: return ps.tokens = tokens ps.cur = tokens + ps.prev = None ps.pool = pool ps.error_count = 0 ps.pending_decorators = None + ps.in_class_body = 0 # ============================================================ @@ -75,6 +85,7 @@ def _advance(ps: rawptr[Parser]): """Advance to the next token""" if ps.cur is None: return if ps.cur.next is not None: + ps.prev = ps.cur ps.cur = ps.cur.next @@ -110,17 +121,12 @@ def _is_funcdef_kw(ps: rawptr[Parser], kw: int) -> int: # extern/export def A(...) 或 extern/export A(...) # (extern/export 后是 def 或 Name+'(/'[') nxt: rawptr[Token] = ps.cur.next - if nxt is None: - return 0 - if nxt.kw_subtype == Keyword.Def: - return 1 - if nxt.type != TokenType.Name: - return 0 + if nxt is None: return 0 + if nxt.kw_subtype == Keyword.Def: return 1 + if nxt.type != TokenType.Name: return 0 nxt2: rawptr[Token] = nxt.next - if nxt2 is None: - return 0 - if nxt2.type == TokenType.Op \ - and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): + if nxt2 is None: return 0 + if nxt2.type == TokenType.Op and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): return 1 return 0 if kw == Keyword.Fn or kw == Keyword.Fun \ @@ -143,6 +149,42 @@ def _is_funcdef_kw(ps: rawptr[Parser], kw: int) -> int: return 0 +def _is_define_const(ps: rawptr[Parser]) -> int: + """define 常量声明的软关键字 lookahead(1=是,0=否)。 + + `define NAME[: T] = <字面量>`:下一个 token 是 Name,再下一个是 '='(无注解) + 或 ':'(带注解)。 + - `define NAME(...)`(宏函数,`_is_funcdef_kw` 的既有形态)第二个 token 是 + '(' / '[' ⇒ 此处不命中,宏函数语义逐字不变; + - 把 define 当标识符的写法(`define = 5` / `define(x)`)同样不命中; + - `define NAME: T`(**缺 `=`**)会命中(下一个是 ':'),随后在 + `_parse_define_const` 里 `_expect_op(Equal)` 失败 ⇒ 响亮失败(非静默)。 + """ + if _cur_kw(ps) != Keyword.Define: return 0 + nxt: rawptr[Token] = ps.cur.next + if nxt is None or nxt.type != TokenType.Name: return 0 + nxt2: rawptr[Token] = nxt.next + if nxt2 is None or nxt2.type != TokenType.Op: return 0 + if nxt2.op_subtype == TokOp.Equal or nxt2.op_subtype == TokOp.Colon: return 1 + return 0 + + +def _is_typedef(ps: rawptr[Parser]) -> int: + """typedef 类型别名声明的软关键字判定(1=是,0=否)。 + + `typedef T1 = T2` 与 `T1: t.CTypedef = T2` **完全等价**(同族同风格于 + `enum`/`define`:展开为既有形态,落到同一条 typedef 注册/查找路径)。 + + `typedef` 是**语句级保留字**:全仓冲突普查确认它只在注释/文档字符串中出现, + 没有任何变量/参数/字段/函数/类/模块以其命名 ⇒ 语句起始出现 `typedef` 即按 + 本语法处理;非法形态(`typedef = 1` / `typedef A` / `typedef A = ` 缺 RHS) + 在 `_parse_typedef` 内 `_record_parse_err` **响亮失败**(非静默)。 + """ + if _cur_kw(ps) != Keyword.Typedef: + return 0 + return 1 + + def _is_match_stmt(ps: rawptr[Parser]) -> int: """match 是软关键字(CPython 3.10+):lookahead 判断是否为 match 语句 @@ -152,15 +194,11 @@ def _is_match_stmt(ps: rawptr[Parser]) -> int: case/type 同理为软关键字(case 仅在 match 套件内消费,type 无语句分发)。 """ nxt: rawptr[Token] = ps.cur.next - if nxt is None: - return 0 - if nxt.type == TokenType.NewLine or nxt.type == TokenType.EndMarker: - return 0 + if nxt is None: return 0 + if nxt.type == TokenType.NewLine or nxt.type == TokenType.EndMarker: return 0 if nxt.type == TokenType.Op: - if nxt.op_subtype == TokOp.Colon: - return 0 - if nxt.op_subtype == TokOp.Equal: - return 0 + if nxt.op_subtype == TokOp.Colon: return 0 + if nxt.op_subtype == TokOp.Equal: return 0 walk: rawptr[Token] = nxt depth: int = 0 while walk is not None: @@ -204,6 +242,308 @@ def _record_parse_err(ps: rawptr[Parser]): _g_parse_err_msg = err_s +def _record_neg_literal_overflow(lit_text: str, lineno: int, col: int): + """记录"一元减 + 整数字面量"的联合越界(fail-fast;只记首次)。 + + `-` 是独立的一元运算符、不属于字面量,故幅值合法(≤ 2^64-1)的字面量在取负 + 后可能 < -2^63。报文含:**字面量原文(含负号)** + 允许范围 [-2^63, 2^64-1] + + 修法;`文件:行:列` 与源码行由 parse_tokens → dump_parse_traceback 补全 + (与词法层 `_lex_record_overflow` 同一上报路径)。 + """ + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + if _g_parse_err_line != 0: + return + _g_parse_err_line = lineno + _g_parse_err_col = col + buf: str = stdlib.malloc(512) + if buf is not None: + stdio.snprintf(buf, 512, + "[TPV] 负数整数字面量越界: 一元减作用于整数字面量后的结果超出 64 位" + "有符号可表示范围(允许范围 -9223372036854775808..18446744073709551615" + " = [-2^63, 2^64-1];负数结果必须 >= -2^63)。字面量原文: '-%s'。" + "禁止静默回绕/截断,已终止编译。" + "修法: 把该负数改到 -9223372036854775808..-1 的范围内(本语言不存在" + "更宽的整数类型,如需更大数值请拆分为多个 64 位字表达)。", lit_text) + _g_parse_err_msg = buf + else: + _g_parse_err_msg = lit_text + + +# ============================================================ +# 类型描述符 const / volatile(软关键字,仅注解位置生效) +# ============================================================ +def _IsDescriptorKeyword(ps: rawptr[Parser]) -> int: + """当前 token 是否为类型描述符关键字(const / volatile),1=是 / 0=否。 + + const/volatile 是**软关键字**:只在**注解位置**(`:` 后的参数/AnnAssign 注解、 + `->` 后的返回注解)由 `_parse_type_ann` 消费;作标识符的写法 + (`t.attr.const()`,TransPyV/Test/App/attr_test.vp:142)不在注解位置, + 属性名/调用名解析只看 TokenType.Name,不看 kw_subtype,故不受影响。 + """ + if _cur_type(ps) != TokenType.Name: + return 0 + if _cur_kw(ps) == Keyword.Const or _cur_kw(ps) == Keyword.Volatile: + return 1 + return 0 + + +def _MakeDescriptorMarker(ps: rawptr[Parser]) -> rawptr[AST]: + """由当前描述符关键字构造标记节点 Attribute(Name('t'), 'CConst'/'CVolatile')。 + + 与 TPC 侧 `SymbolUtils._ExpandTypeDescriptors` 的文本展开产物 + (`t.CConst` / `t.CVolatile`)**逐字段同形**:两侧落到同一条既有识别路径 + (TPC:HandlesTypeMerge/TypeAnnotationResolver 的 t 模块类型限定符分支 → + DataConst/DataVolatile;TPV:注解解析的 t 模块属性分支),不新造第二套表示。 + """ + attr_name: str = "CConst" + if _cur_kw(ps) == Keyword.Volatile: + attr_name = "CVolatile" + marker: rawptr[AST] = Attribute(ps.pool, Name(ps.pool, "t", ASTCtx.Load), + attr_name, ASTCtx.Load) + _set_pos(marker, _cur_lineno(ps), _cur_col(ps), 0, 0) + return marker + + +def _PrependDescriptorMarkers(ps: rawptr[Parser], + base: rawptr[AST], + mods: rawptr[list[rawptr[AST]]], + mod_count: int) -> rawptr[AST]: + """把描述符标记贴到类型联合的**最左操作数**位置(与 TPC 文本展开同形)。 + + TPC 把 `const volatile int | t.CPtr` 展开为文本 + `t.CConst | t.CVolatile | int | t.CPtr`,其解析树是左结合 + `(((t.CConst | t.CVolatile) | int) | t.CPtr)`。本函数据此把描述符串整体 + 贴到 `base` 最左操作数的左侧,产出**同一棵树**(而非 + `t.CConst | (t.CVolatile | int | t.CPtr)`——那会让两侧 AST 不同形)。 + """ + slot_parent: rawptr[BinOp] = None # 最左 BitOr 节点:其 left 即"最左操作数" + slot_node: rawptr[AST] = base + cur: rawptr[AST] = base + while cur is not None and cur.kind() == ASTKind.BinOp: + b: rawptr[BinOp] = (rawptr[BinOp])(cur) + if b.op != OpKind.BitOr or b.left is None: + break + nxt: rawptr[AST] = b.left + if nxt.kind() == ASTKind.BinOp: + nb: rawptr[BinOp] = (rawptr[BinOp])(nxt) + if nb.op == OpKind.BitOr and nb.left is not None: + cur = nxt + continue + slot_parent = b + slot_node = nxt + break + # 描述符串按源码顺序左结合:`const volatile` → (t.CConst | t.CVolatile) + chain: rawptr[AST] = mods.get(0) + i: int = 1 + while i < mod_count: + chain = BinOp(ps.pool, chain, OpKind.BitOr, mods.get(i)) + i += 1 + newnode: rawptr[AST] = BinOp(ps.pool, chain, OpKind.BitOr, slot_node) + if slot_parent is None: + return newnode + slot_parent.left = newnode + return base + + +def _RecordDescriptorErr(detail: str, lineno: int, col: int): + """记录类型描述符非法形态(fail-fast;只记首次)。 + + 报文含**期望形态 + 正确示例**;`文件:行:列` 与源码行 + `^` 列标记由 + parse_tokens → dump_parse_traceback 补全(与 `_record_neg_literal_overflow` + 同一上报路径)。描述符**绝不静默忽略**:缺类型 / 后随非类型 / 裸用都终止编译。 + """ + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + if _g_parse_err_line != 0: + return + _g_parse_err_line = lineno + _g_parse_err_col = col + buf: str = stdlib.malloc(1024) + if buf is not None: + stdio.snprintf(buf, 1024, + "类型描述符非法(%s)。const/volatile 是只在类型位置生效的软关键字," + "必须写成 `名字: const 类型` / `名字: volatile 类型`" + "(可组合 `名字: const volatile 类型`)。正确示例:a: const int / " + "a: volatile int / a: const volatile t.CInt32T / " + "def f(p: const rawptr[Foo]) -> const int。" + "(描述符不会被静默忽略:缺类型 / 后随非类型 / 裸用一律终止编译)", detail) + _g_parse_err_msg = buf + else: + _g_parse_err_msg = detail + + +# ============================================================ +# virtual / novirtual 修饰符(软关键字,仅"语句起始 + 紧跟 class/def"生效) +# ============================================================ +# 语法:`virtual class C:` / `novirtual class C:` / `virtual def m(...)` / +# `novirtual def m(...)`(修饰符写在 class/def **之前**)。 +# +# 语义:与**手写装饰器同一套表示**——virtual → `@t.CVTable`,novirtual → `@t.NoVTable`: +# - 类级:CVTable 强制有虚表 / NoVTable 强制无虚表 +# (ClassGenBase._detect_vtable_status) +# - 方法级:CVTable 进虚表槽 / NoVTable 不进虚表槽 +# (ClassGenBase._should_method_be_virtual) +# 本层只"合成同名装饰器",下游零新增判据,不新造第二套表示;位置/报文与 TPC 端 +# (lib/vast/Parser.py:_ParseVirtualModified)逐条对齐。 +# +# 软关键字边界(非保留字):只在**语句起始**判定;作标识符的写法 +# (`x = d.virtual` / 形参名 / for 目标 / 字典键)token 仍是 Name,那些位置只看 +# TokenType.Name、不看 kw_subtype,故语义逐字不变。 +# +# 非法形态**响亮失败**(不静默丢修饰符): +# - 后随非 class/def; +# - `virtual def` / `novirtual def` 不直接写在类体内(模块级 / 函数体 / 分支体)。 +# 组合与重复形态(由"后随必须是 class/def"这一条唯一判据统一挡住): +# `virtual novirtual class` / `virtual virtual class` / `novirtual virtual def` +# 都因"修饰符后随的是另一个修饰符"而响亮失败,不会被静默折叠或忽略。 +# `novirtual class` 内写 `virtual def` **合法**:与既有"@t.NoVTable 类 + 方法级 +# @t.CVTable"语义完全一致(_detect_vtable_status → _has_any_func_cvtable ⇒ 该类 +# 仍生成虚表,且槽里只有被标记的方法)。 +def _IsVirtualModifier(ps: rawptr[Parser]) -> int: + """当前 token 是否为 virtual / novirtual 修饰符(1=是 / 0=否)。 + + 只在**语句起始**(_parse_statement_into 分派处)调用;作标识符的位置不经过 + 本判据,故 `x = d.virtual` / 形参名 / for 目标 / 字典键不受影响。 + """ + if _cur_type(ps) != TokenType.Name: + return 0 + if _cur_kw(ps) == Keyword.Virtual or _cur_kw(ps) == Keyword.Novirtual: + return 1 + return 0 + + +def _MakeVirtualMarker(ps: rawptr[Parser]) -> rawptr[AST]: + """由当前 virtual/novirtual token 构造标记节点 Attribute(Name('t'), 'CVTable'|'NoVTable')。 + + 与**手写** `@t.CVTable` / `@t.NoVTable` 装饰器逐字段同形(_parse_decorators 的 + 产物形态),故下游 `ClassGenBase._has_decorator` 零新增判据。 + """ + attr_name: str = "CVTable" + if _cur_kw(ps) == Keyword.Novirtual: + attr_name = "NoVTable" + marker: rawptr[AST] = Attribute(ps.pool, Name(ps.pool, "t", ASTCtx.Load), + attr_name, ASTCtx.Load) + _set_pos(marker, _cur_lineno(ps), _cur_col(ps), 0, 0) + return marker + + +def _RecordVirtualErr(detail: str, lineno: int, col: int, extra: str): + """记录 virtual/novirtual 修饰符非法形态(fail-fast;只记首次)。 + + 报文含**允许出现的位置 + 正确示例 + 修法**;`文件:行:列` 与源码行 + `^` 列标记 + 由 parse_tokens → dump_parse_traceback 补全(与 _RecordDescriptorErr 同一上报 + 路径)。修饰符**绝不静默忽略**:后随非 class/def / 方法级不在类体内都终止编译。 + + 两个入参(detail / extra)由调用方用 **f-string 插值**构建:本语言的 str 是 + i8*,**没有** `str + str` 的拼接语义,`"a" + x` 会退化成裸指针 add ⇒ 非法 IR + (opt: invalid operand type for instruction)。故本文件所有含变量的报文一律 + 走 f-string / snprintf,禁止对 str 用 `+` 拼接。 + """ + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + if _g_parse_err_line != 0: + return + _g_parse_err_line = lineno + _g_parse_err_col = col + buf: str = stdlib.malloc(1536) + if buf is not None: + stdio.snprintf(buf, 1536, + "[TPV] virtual/novirtual 修饰符非法(%s)。可写位置:类级 " + "`virtual class C:` / `novirtual class C:`;方法级 " + "`virtual def m(self): ...` / `novirtual def m(self): ...`" + "(只能直接写在类体内:virtual class / class / novirtual class 的类体)。" + "正确示例:virtual class Shape: / novirtual class Node: / " + "class A: virtual def run(self) -> int: ... / " + "novirtual class B: novirtual def helper(self) -> int: ...。%s" + "(修饰符不会被静默忽略:非法形态一律终止编译)", detail, extra) + _g_parse_err_msg = buf + else: + _g_parse_err_msg = detail + + +def _ParseVirtualModified(ps: rawptr[Parser], parent: rawptr[AST]): + """`virtual class` / `novirtual class` / `virtual def` / `novirtual def`。 + + 合成 `@t.CVTable` / `@t.NoVTable` 装饰器(与用户既有装饰器合并,标记追加在末尾; + 位置无关——`_has_decorator` 按名判定)后交给 _parse_classdef / _parse_funcdef, + 产出与**手写同名装饰器**逐字段同形的 AST,故下游零新增分支。 + """ + mod_lineno: int = _cur_lineno(ps) + mod_col: int = _cur_col(ps) + mod_name: str = "virtual" + if _cur_kw(ps) == Keyword.Novirtual: + mod_name = "novirtual" + marker: rawptr[AST] = _MakeVirtualMarker(ps) + _advance(ps) # 消费修饰符 + # 修饰符后必须是 class / def(def 的别名 fn/fun/func/function 同样接受: + # 与 _is_funcdef_kw 口径一致,也与 TPC 端逐条对齐——TPC 的 fn→def 文本展开 + # 只命中行首 fn,`virtual fn m()` 不先展开,故两端都在本层显式接受别名) + kw2: int = _cur_kw(ps) + is_class: int = 0 + is_def: int = 0 + if kw2 == Keyword.Class: + is_class = 1 + elif kw2 == Keyword.Def or kw2 == Keyword.Fn or kw2 == Keyword.Fun \ + or kw2 == Keyword.Func or kw2 == Keyword.Function: + is_def = 1 + if is_class == 0 and is_def == 0: + nxt_s: str = _cur_str(ps) + if nxt_s is None: + nxt_s = "(none)" + _RecordVirtualErr(f"`{mod_name}` 后随 '{nxt_s}'(非 class/def)", + mod_lineno, mod_col, + f"`{mod_name}` 只在 class/def 前生效;" + f"若此处本意是普通标识符名,请改名" + f"(该词在语句起始会被判为修饰符)。") + ps.error_count += 1 + # 余下 token 交给通用语句分派消费(不制造死循环,也不覆盖首次错误)。 + _parse_simple_stmt_into(ps, parent) + return + if is_def != 0 and ps.in_class_body == 0: + _RecordVirtualErr(f"{mod_name} def 出现在类体之外", mod_lineno, mod_col, + f"{mod_name} def 描述的是「类体内方法的虚/非虚」," + f"模块级 / 函数体 / 分支体内没有可归属的类。") + ps.error_count += 1 + # 合并既有装饰器(`@deco` + virtual class/def 组合)后交给既有 class/def 解析 + merged: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](ps.pool, 8) + if merged is None: + return + if ps.pending_decorators is not None: + dn: sizet = len(ps.pending_decorators) + di: sizet = 0 + while di < dn: + merged.append(ps.pending_decorators.get(di)) + di += 1 + merged.append(marker) + ps.pending_decorators = merged + stmt: rawptr[AST] = None + if is_class != 0: + stmt = _parse_classdef(ps) + else: + stmt = _parse_funcdef(ps, 0) + if stmt is not None: + parent.append(stmt) + + +def _IsBareDescriptor(ps: rawptr[Parser]) -> int: + """裸用描述符判定:整条语句只有一个描述符串(const[: volatile]),1=是 / 0=否。 + + 只在"描述符串后直接换行 / 文件尾 / 分号"时命中;作普通标识符的写法 + (`const = 5` / `const(x)` / `t.attr.const()`)不命中(软关键字边界)。 + """ + if _IsDescriptorKeyword(ps) == 0: + return 0 + nxt: rawptr[Token] = ps.cur.next + while nxt is not None and nxt.type == TokenType.Name \ + and (nxt.kw_subtype == Keyword.Const or nxt.kw_subtype == Keyword.Volatile): + nxt = nxt.next + if nxt is None: + return 1 + if nxt.type == TokenType.NewLine or nxt.type == TokenType.EndMarker: + return 1 + if nxt.type == TokenType.Op and nxt.op_subtype == TokOp.Semi: + return 1 + return 0 + + def get_parse_err_line() -> int: """获取最近一次解析错误的行号(0=无错误)""" return _g_parse_err_line @@ -237,14 +577,14 @@ def _cur_col(ps: rawptr[Parser]) -> int: def _skip_nl(ps: rawptr[Parser]): """Skip TokenType.Nl token""" while ps.cur is not None and ps.cur.type == TokenType.Nl: - ps.cur = ps.cur.next + _advance(ps) def _skip_nls_and_newlines(ps: rawptr[Parser]): """Skip TokenType.Nl and TokenType.NewLine (used for line continuation)""" while ps.cur is not None: if ps.cur.type == TokenType.Nl or ps.cur.type == TokenType.NewLine: - ps.cur = ps.cur.next + _advance(ps) else: break @@ -335,7 +675,7 @@ def _dbg_lookup_lit_val(ptr: uint64) -> double: _g_dbg_lit_found = 0 if _g_dbg_pts is None or _g_dbg_vals is None: return 0.0 - i: t.CSizeT = 0 + i: sizet = 0 while i < _g_dbg_cnt: if _g_dbg_pts[i] == ptr: _g_dbg_lit_found = 1 @@ -429,8 +769,8 @@ def _fix_store_ctx(node: rawptr[AST]): ls: rawptr[List] = (rawptr[List])(node) tp_elts = ls.elts if tp_elts is not None: - n: t.CSizeT = tp_elts.__len__() - i: t.CSizeT = 0 + n: sizet = tp_elts.__len__() + i: sizet = 0 while i < n: cur: rawptr[AST] = tp_elts.get(i) _fix_store_ctx(cur) @@ -750,11 +1090,144 @@ def _parse_arith(ps: rawptr[Parser]) -> rawptr[AST]: return left +# ============================================================ +# C 风格指针后缀('*' / '**')—— 与 TransPyC lib/vast 的 _AtPtrSuffix 同源 +# ============================================================ +def _ptr_suffix_end_op(op: int) -> int: + """后缀末尾 token 是否为“无右操作数”位置(']' ',' ')' ':' '=')。 + + 这些位置后接 '*'/'**' 时,乘法/幂本就缺右操作数(原语法错误), + 故按指针后缀处理不会改变任何合法表达式的语义(x[a * b] / a ** b 等不受影响)。 + """ + if op == TokOp.Rsqb or op == TokOp.Comma or op == TokOp.RPar \ + or op == TokOp.Colon or op == TokOp.Equal: + return 1 + return 0 + + +def _at_ptr_suffix(ps: rawptr[Parser], base: rawptr[AST]) -> int: + """判定当前 '*'/'**' 串是否为作用于 base 的 C 风格指针后缀。 + + 判据(与 vast 一致):base 是类型原子(Name/Attribute/Subscript), + 且从当前 '*'/'**' 起跨过连续 '*'/'**' 与 Nl 后,紧跟 ']' / ',' / ')' / ':' / '='。 + 该判据同时覆盖注解与表达式上下文(如 list[ast.AST*] / list[ast.AST*]*)。 + """ + if base is None: + return 0 + k: int = base.kind() + if k != ASTKind.Name and k != ASTKind.Attribute and k != ASTKind.Subscript: + return 0 + nxt: rawptr[Token] = ps.cur + stars: int = 0 + while nxt is not None: + if nxt.type == TokenType.Op \ + and (nxt.op_subtype == TokOp.Star or nxt.op_subtype == TokOp.StarStar): + stars += 1 + nxt = nxt.next + elif nxt.type == TokenType.Nl: + nxt = nxt.next + else: + break + if stars == 0 or nxt is None or nxt.type != TokenType.Op: + return 0 + return _ptr_suffix_end_op(nxt.op_subtype) + + +def _make_ptr_type(ps: rawptr[Parser], base: rawptr[AST]) -> rawptr[AST]: + """构造一层指针包装:base | t.CPtr。""" + cptr: rawptr[AST] = Attribute(ps.pool, Name(ps.pool, "t", ASTCtx.Load), + "CPtr", ASTCtx.Load) + node: rawptr[AST] = BinOp(ps.pool, base, OpKind.BitOr, cptr) + _set_pos(node, base.lineno, base.col_offset, 0, 0) + return node + + +def _consume_ptr_suffix(ps: rawptr[Parser], base: rawptr[AST]) -> rawptr[AST]: + """消费连续的 C 风格指针后缀('*' 一层 / '**' 两层),展开为 base | t.CPtr 链。""" + while True: + _skip_nl(ps) + if _match_op(ps, TokOp.StarStar): + _advance(ps) + base = _make_ptr_type(ps, base) + base = _make_ptr_type(ps, base) + continue + if _match_op(ps, TokOp.Star): + _advance(ps) + base = _make_ptr_type(ps, base) + continue + break + return base + + +def _at_ptr_suffix_call(ps: rawptr[Parser], base: rawptr[AST]) -> int: + """判定当前 '*'/'**' 串是否为 `T*(x)` 形式的指针后缀**强转调用**。 + + 判据(与 TPC lib/vast 的 _AtPtrSuffixCall 同源): + 1. base 是类型原子(Name/Attribute/Subscript); + 2. base 与 '*'/'**' 串**紧贴**(token 行列相邻、同行,无空白/换行); + 3. '*'/'**' 串(串内逐个 token 紧贴)之后**紧贴**一个 '('。 + + 即整段写作**无空白**的 `T*(x)`(C 风格强转写法)。为什么 '(' 不进 + _ptr_suffix_end_op 表:`a * (b)` 是合法乘法('(' 可作乘法右操作数起点), + 无条件计入会误伤乘法。故叠加"前驱是类型原子 + 两侧紧贴";`a * (b + c)` / + `n * (m - 1)` 等有空格者仍按乘法解析。 + """ + if base is None: + return 0 + k: int = base.kind() + if k != ASTKind.Name and k != ASTKind.Attribute and k != ASTKind.Subscript: + return 0 + nxt: rawptr[Token] = ps.cur + pv: rawptr[Token] = ps.prev + if pv is None or nxt is None: + return 0 + if pv.type == TokenType.Nl or pv.type == TokenType.NewLine: + return 0 + if pv.end_lineno != nxt.lineno or pv.end_col_offset != nxt.col_offset: + return 0 # base 与 '*'/'**' 之间有空白/换行:非 C 风格强转写法 + stars: int = 0 + prev: rawptr[Token] = None + last: rawptr[Token] = None + while nxt is not None: + if nxt.type == TokenType.Op \ + and (nxt.op_subtype == TokOp.Star or nxt.op_subtype == TokOp.StarStar): + if prev is not None \ + and (nxt.lineno != prev.end_lineno or nxt.col_offset != prev.end_col_offset): + return 0 # 星串内部出现空白:非紧邻,不判为强转 + stars += 1 + prev = nxt + last = nxt + nxt = nxt.next + else: + break + if stars == 0 or last is None or nxt is None: + return 0 + if nxt.type != TokenType.Op or nxt.op_subtype != TokOp.LPar: + return 0 + if nxt.lineno != last.end_lineno or nxt.col_offset != last.end_col_offset: + return 0 + return 1 + + +def _consume_ptr_suffix_call(ps: rawptr[Parser], base: rawptr[AST]) -> rawptr[AST]: + """把已认定为 `T*(...)` 的指针后缀强转解析为**调用**。 + + 产物与既有强转形态 `(T | t.CPtr)(...)` 逐字同形:同为 Call + (func = base 展开的 `base | t.CPtr` 链,args/keywords = 括号实参), + 不新造第二套 cast 表示。 + """ + func: rawptr[AST] = _consume_ptr_suffix(ps, base) + return _parse_call(ps, func) + + def _parse_term(ps: rawptr[Parser]) -> rawptr[AST]: left: rawptr[AST] = _parse_factor(ps) if left is None: return None while True: _skip_nl(ps) # 括号内行首 '*'/'/'/'//'/'%'/'@': (a\n * b) + if _match_op(ps, TokOp.Star) and _at_ptr_suffix(ps, left) != 0: + left = _consume_ptr_suffix(ps, left) # C 风格指针后缀,不按乘法处理 + continue op_token: int = 0 if _match_op(ps, TokOp.Star): op_token = TokOp.Star elif _match_op(ps, TokOp.Slash): op_token = TokOp.Slash @@ -780,6 +1253,16 @@ def _parse_factor(ps: rawptr[Parser]) -> rawptr[AST]: lineno: int = _cur_lineno(ps) col: int = _cur_col(ps) _advance(ps) + # 一元减 + 整数字面量的**联合越界判定**:`-` 是一元运算符、不属于字面量, + # 故幅值合法(≤ 2^64-1,词法层已放行)的字面量取负后可能 < -2^63。 + # 只有"直接作用于整数常量"的一元减在此判定:`1 - 2` / `a - b` 是二元减 + # (经 _parse_arith,不进入本分支);`-x`(变量)操作数不是常量,不判定。 + if op_token == TokOp.Minus and _cur_type(ps) == TokenType.Number \ + and ps.cur.is_float == 0 \ + and _lex_int_neg_exceeds_i64(_cur_str(ps)) != 0: + _record_neg_literal_overflow(_cur_str(ps), lineno, col) + ps.error_count += 1 + return None operand: rawptr[AST] = _parse_factor(ps) ast_op: int = OpKind.UAdd if op_token == TokOp.Minus: @@ -800,6 +1283,8 @@ def _parse_power(ps: rawptr[Parser]) -> rawptr[AST]: """power: await_expr ['**' factor] | atom_expr ['**' factor]""" base: rawptr[AST] = _parse_atom_expr(ps) if base is None: return None + if _match_op(ps, TokOp.StarStar) and _at_ptr_suffix(ps, base) != 0: + return _consume_ptr_suffix(ps, base) # C 风格指针后缀('**' 计 2 层) if _match_op(ps, TokOp.StarStar): _advance(ps) exp: rawptr[AST] = _parse_factor(ps) @@ -823,7 +1308,13 @@ def _parse_atom_expr(ps: rawptr[Parser]) -> rawptr[AST]: if base is None: return None # trailer loop while True: - if _match_op(ps, TokOp.Dot): + if (_match_op(ps, TokOp.Star) or _match_op(ps, TokOp.StarStar)) \ + and _at_ptr_suffix_call(ps, base) != 0: + # `T*(x)` / `T**(x)` 指针后缀强转:解析为 cast 调用(与 + # `(T | t.CPtr)(x)` 同形)。在 trailer 循环里消费,故其后的 + # `.attr` / `[i]` / `(…)` 仍由本循环继续挂接。 + base = _consume_ptr_suffix_call(ps, base) + elif _match_op(ps, TokOp.Dot): _advance(ps) if _cur_type(ps) != TokenType.Name: ps.error_count += 1 @@ -1209,8 +1700,8 @@ def _append_str_value(pool: rawptr[memhub.MemManager], if node.kind() == ASTKind.JoinedStr: js_val: rawptr[JoinedStr] = (rawptr[JoinedStr])(node) if js_val.values is not None: - n_v: t.CSizeT = js_val.values.__len__() - i_v: t.CSizeT + n_v: sizet = js_val.values.__len__() + i_v: sizet for i_v in range(n_v): values.append(js_val.values.get(i_v)) else: @@ -1234,8 +1725,8 @@ def _concat_str_nodes(pool: rawptr[memhub.MemManager], cb_c: rawptr[Constant] = (rawptr[Constant])(b) if ca_c.const_kind == CONST_STR and cb_c.const_kind == CONST_STR \ and ca_c.str_val is not None and cb_c.str_val is not None: - la_c: t.CSizeT = string.strlen(ca_c.str_val) - lb_c: t.CSizeT = string.strlen(cb_c.str_val) + la_c: sizet = string.strlen(ca_c.str_val) + lb_c: sizet = string.strlen(cb_c.str_val) buf_c: str = pool.alloc(la_c + lb_c + 1) if buf_c is not None: string.memcpy(buf_c, ca_c.str_val, la_c) @@ -1257,15 +1748,15 @@ def _parse_fstring(ps: rawptr[Parser], content: str, """Parse f-string content, building JoinedStr or FormattedValue nodes""" pool: rawptr[memhub.MemManager] = ps.pool values: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](pool, 8) - i: t.CSizeT = 0 - content_len: t.CSizeT = string.strlen(content) + i: sizet = 0 + content_len: sizet = string.strlen(content) # Literal text buffer for f-string content lit_buf: str = pool.alloc(content_len + 1) if lit_buf is None: return None - lit_pos: t.CSizeT = 0 + lit_pos: sizet = 0 while i < content_len: - ch: t.CChar = content[i] + ch: char = content[i] if ch == '{': # {{ → Literal { if i + 1 < content_len and content[i + 1] == '{': @@ -1282,19 +1773,19 @@ def _parse_fstring(ps: rawptr[Parser], content: str, if lit_buf is None: break lit_pos = 0 # Find matching closing '}' while tracking nested '{}' and string literals inside the f-string - j: t.CSizeT = i + 1 + j: sizet = i + 1 depth: int = 1 - conv_pos: t.CSizeT = 0 - fmt_pos: t.CSizeT = 0 + conv_pos: sizet = 0 + fmt_pos: sizet = 0 while j < content_len and depth > 0: - c: t.CChar = content[j] + c: char = content[j] if c == '\'' or c == '"': # 跳过表达式块内的嵌套字符串字面量(PEP 701 同引号嵌套), # 避免其内部字符干扰 {} 深度/转换/格式分隔符定位 - nq: t.CChar = c + nq: char = c j += 1 while j < content_len: - c2: t.CChar = content[j] + c2: char = content[j] if c2 == '\\': j += 2 continue @@ -1312,10 +1803,10 @@ def _parse_fstring(ps: rawptr[Parser], content: str, elif depth == 1: if c == '!' and conv_pos == 0 and fmt_pos == 0: if j + 1 < content_len: - nc: t.CChar = content[j + 1] + nc: char = content[j + 1] if nc == 's' or nc == 'r' or nc == 'a': if j + 2 < content_len: - after: t.CChar = content[j + 2] + after: char = content[j + 2] if after == ':' or after == '}': conv_pos = j elif j + 2 == content_len: @@ -1328,12 +1819,12 @@ def _parse_fstring(ps: rawptr[Parser], content: str, ps.error_count += 1 break # Extract expression text - expr_end: t.CSizeT = j + expr_end: sizet = j if conv_pos > 0: expr_end = conv_pos elif fmt_pos > 0: expr_end = fmt_pos - expr_len: t.CSizeT = expr_end - i - 1 + expr_len: sizet = expr_end - i - 1 if expr_len == 0: _record_parse_err(ps) ps.error_count += 1 @@ -1348,7 +1839,7 @@ def _parse_fstring(ps: rawptr[Parser], content: str, # Conversion specifier conversion: int = -1 if conv_pos > 0: - conv_char: t.CChar = content[conv_pos + 1] + conv_char: char = content[conv_pos + 1] if conv_char == 's': conversion = 115 elif conv_char == 'r': @@ -1358,7 +1849,7 @@ def _parse_fstring(ps: rawptr[Parser], content: str, # Format specifier format_spec: rawptr[AST] = None if fmt_pos > 0: - spec_len: t.CSizeT = j - fmt_pos - 1 + spec_len: sizet = j - fmt_pos - 1 if spec_len > 0: spec_buf: str = pool.alloc(spec_len + 1) if spec_buf is not None: @@ -1579,8 +2070,21 @@ def _parse_varargslist(ps: rawptr[Parser], is_lambda: int = 0) -> rawptr[AST]: def _parse_type_ann(ps: rawptr[Parser]) -> rawptr[AST]: - """解析类型注解,支持 C 风格指针后缀(* / **)。 + """解析类型注解,支持类型描述符前缀(const / volatile)与 C 风格指针后缀(* / **)。 + 类型描述符(软关键字,只在注解位置生效;与 TPC 侧 + `SymbolUtils._ExpandTypeDescriptors` 的展开产物逐字段同形): + const int → t.CConst | int + volatile int → t.CVolatile | int + const volatile int → t.CConst | t.CVolatile | int(顺序任意,两限定符都累积) + const t.CInt32T → t.CConst | t.CInt32T + const rawptr[Foo] → t.CConst | rawptr[Foo] + const int | t.CPtr → t.CConst | int | t.CPtr(粘贴在联合的最左操作数:与 + TPC 文本展开 `t.CConst | int | t.CPtr` 的解析树同形) + 非法形态**响亮失败**(非静默,不丢描述符):缺类型(`a: const`)/ + 后随非类型(`a: const 1`)/ 裸用(语句只有 `const`,见 _is_bare_descriptor)。 + + C 风格指针后缀: int* → rawptr[int] (i32*) int** → (rawptr[int]) | t.CPtr (i32**) int****** → 6 层嵌套 (i32******) @@ -1590,11 +2094,37 @@ def _parse_type_ann(ps: rawptr[Parser]) -> rawptr[AST]: ('int***' 形态为 BinOp(Pow, UnaryOp(Deref, None)),StarStar+Star)。 本函数回收该形态并恢复 error_count,再按层数嵌套构造 BinOp(BitOr, t.CPtr)。 """ + # 类型描述符前缀:收集 const / volatile 标记(软关键字,仅本位置消费) + mods: rawptr[list[rawptr[AST]]] = None + mod_count: int = 0 + mod_lineno: int = _cur_lineno(ps) + mod_col: int = _cur_col(ps) + while _IsDescriptorKeyword(ps) != 0: + if mods is None: + mods = list[rawptr[AST]](ps.pool, 4) + mods.append(_MakeDescriptorMarker(ps)) + mod_count += 1 + _advance(ps) + if mod_count > 0 and _cur_type(ps) != TokenType.Name: + # 描述符后缺类型(`a: const` / `a: const = 1` / `def f(a: const)`): + # 响亮失败——**不**把描述符静默丢掉。 + _RecordDescriptorErr("描述符后缺少类型", mod_lineno, mod_col) + ps.error_count += 1 + return None before_ec: int = ps.error_count base: rawptr[AST] = _parse_test(ps) if base is None: + if mod_count > 0: + # 描述符已消费但类型解析失败(如 `a: const = 1`):响亮失败保描述符报错。 + _RecordDescriptorErr("描述符后缺少类型(类型解析失败)", mod_lineno, mod_col) _record_parse_err(ps) # 注解解析失败:记录具体位置(error_count 已在 _parse_test 内增加) return None + if mod_count > 0 and base.kind() == ASTKind.Constant: + # 后随非类型(`a: const 1` / `a: const "x"` / `a: const True`):响亮失败 + # (描述符只修饰类型,常量不是类型——不得静默降级/丢弃)。 + _RecordDescriptorErr("描述符后随非类型(描述符只修饰类型)", mod_lineno, mod_col) + ps.error_count += 1 + return None ptr_level: int = 0 # 回收垃圾节点(_parse_test 对后缀 * / ** 的消费产物) if base.kind() == ASTKind.BinOp: @@ -1628,6 +2158,9 @@ def _parse_type_ann(ps: rawptr[Parser]) -> rawptr[AST]: "CPtr", ASTCtx.Load) base = BinOp(ps.pool, base, OpKind.BitOr, cptr_an) li_an += 1 + # 描述符最后粘贴:与 TPC 文本展开同形(见 _PrependDescriptorMarkers) + if mod_count > 0: + base = _PrependDescriptorMarkers(ps, base, mods, mod_count) return base @@ -1653,15 +2186,25 @@ def _parse_arg_def(ps: rawptr[Parser], is_lambda: int = 0) -> rawptr[AST]: # Statement parsing (Design: directly append to parent, do not return a list) # ============================================================ -def _parse_suite_into_children(ps: rawptr[Parser], parent: rawptr[AST]): +def _parse_suite_into_children(ps: rawptr[Parser], parent: rawptr[AST], + owner_is_class: int = 0): """Parse statement suite, directly append to parent's children. - suite: TokenType.NewLine TokenType.Indent stmt+ TokenType.Dedent | simple_stmt""" + suite: TokenType.NewLine TokenType.Indent stmt+ TokenType.Dedent | simple_stmt + + owner_is_class:本套件的**直接拥有者**是否 ClassDef。套件解析期间置 + ps.in_class_body,供 _ParseVirtualModified 判 `virtual def`/`novirtual def` + 是否"直接写在类体内"(函数体 / 分支体 / 循环体都不算)。默认 0 ⇒ 除类体外的 + 所有套件拥有者天然正确,无需逐个改动调用点。 + """ + prev_in_class: int = ps.in_class_body + ps.in_class_body = owner_is_class _skip_nl(ps) if _cur_type(ps) == TokenType.NewLine: _advance(ps) _skip_nl(ps) if _cur_type(ps) != TokenType.Indent: ps.error_count += 1 + ps.in_class_body = prev_in_class return _advance(ps) sidx: int = 0 @@ -1678,9 +2221,11 @@ def _parse_suite_into_children(ps: rawptr[Parser], parent: rawptr[AST]): _advance(ps) _skip_nl(ps) _expect_type(ps, TokenType.Dedent) + ps.in_class_body = prev_in_class return # Single-line suite _parse_simple_stmt_into(ps, parent) + ps.in_class_body = prev_in_class def _parse_statement_into(ps: rawptr[Parser], parent: rawptr[AST]): @@ -1688,12 +2233,49 @@ def _parse_statement_into(ps: rawptr[Parser], parent: rawptr[AST]): ttype: int = _cur_type(ps) kw: int = _cur_kw(ps) if ttype == TokenType.Name: + # define 常量声明:`define NAME[: T] = <字面量>`(**无括号**)。 + # 必须早于 _parse_simple_stmt_into 分派——否则 `define` 被当普通标识符 + # 解析成表达式语句,随后的 NAME 沦为残留 token(虽响亮失败但定位错误)。 + # `define NAME(...)`(宏函数)被 _is_define_const 的 lookahead 排除, + # 仍走下方 _is_funcdef_kw 分支,语义逐字不变。 + if kw == Keyword.Define and _is_define_const(ps) != 0: + dc_stmt: rawptr[AST] = _parse_define_const(ps) + if dc_stmt is not None: + parent.append(dc_stmt) + return + # typedef 类型别名声明:`typedef T1 = T2`(语句级保留字,无 lookahead—— + # typedef 不在任何既有源码中作标识符)。非法形态在 _parse_typedef 内 + # 响亮失败(_record_parse_err),不静默。 + if _is_typedef(ps) != 0: + td_stmt: rawptr[AST] = _parse_typedef(ps) + if td_stmt is not None: + parent.append(td_stmt) + return + # virtual / novirtual 修饰符(软关键字):只在"语句起始 + 紧跟 class/def" + # 时生效;合成既有装饰器 @t.CVTable / @t.NoVTable 后照常走 class/def 解析 + # (见 _ParseVirtualModified)。放在 class/def 分派之前:修饰符必须先被消费, + # 后面的 class/def 才能落到 _is_funcdef_kw / Keyword.Class 分支。 + # 与软关键字 fn→def 的关系:两种写法都接受(def 的别名 fn/fun/func/function), + # 与 TPC 端(先做 fn→def 文本展开、再判修饰符)结果一致。 + if _IsVirtualModifier(ps) != 0: + _ParseVirtualModified(ps, parent) + return + # 类型描述符裸用:整条语句只有 `const` / `volatile`(缺类型)⇒ 响亮失败。 + # 只在"描述符串后直接换行/文件尾/分号"时命中(软关键字边界),故 + # `const = 5`(作标识符的赋值)/ `t.attr.const()` 等写法不命中、语义不变。 + # 记录自定义报文后**继续走通用 simple_stmt 分派**:既消费 token(不制造 + # 死循环),也不覆盖首次错误(_record_parse_err 只记首次错误)。 + if _IsBareDescriptor(ps) != 0: + _RecordDescriptorErr("裸用描述符(整条语句只有描述符,缺类型)", + _cur_lineno(ps), _cur_col(ps)) + ps.error_count += 1 if kw == Keyword.If or kw == Keyword.While or kw == Keyword.For or kw == Keyword.Try: stmt: rawptr[AST] = _parse_compound(ps) if stmt is not None: parent.append(stmt) return - if kw == Keyword.With or _is_funcdef_kw(ps, kw) != 0 or kw == Keyword.Class: + if kw == Keyword.With or _is_funcdef_kw(ps, kw) != 0 or kw == Keyword.Class \ + or kw == Keyword.Enum: stmt = _parse_compound(ps) if stmt is not None: parent.append(stmt) @@ -2134,6 +2716,8 @@ def _parse_compound(ps: rawptr[Parser]) -> rawptr[AST]: return _parse_funcdef(ps, 0) if kw == Keyword.Class: return _parse_classdef(ps) + if kw == Keyword.Enum: + return _parse_enumdef(ps) if kw == Keyword.Async: _advance(ps) if _is_funcdef_kw(ps, _cur_kw(ps)) != 0: @@ -2501,7 +3085,240 @@ def _parse_classdef(ps: rawptr[Parser]) -> rawptr[AST]: dec_list: rawptr[list[rawptr[AST]]] = ps.pending_decorators ps.pending_decorators = None node: rawptr[ClassDef] = ClassDef(ps.pool, name, bases, keywords, dec_list, type_params) + # owner_is_class=1:类体期间 ps.in_class_body=1,供 virtual/novirtual 修饰符判 + # "方法级修饰符是否直接写在类体内"(见 _ParseVirtualModified / _parse_suite_into_children) + _parse_suite_into_children(ps, node, 1) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# enum 语法糖(与 class X(t.CEnum): 完全等价) +# +# 规格:`enum Name:` 头行 + 成员行(`A` / `A: T` / `A = 0`)。 +# 语义与手写 `class Name(t.CEnum):` **完全等价**——本函数合成的 ClassDef +# 与 _parse_classdef 的产物逐字段同形,故下游(ClassGenDef 分派 → +# ClassGenEnum._translate_enum_def → EnumTable 编译期常量)只有**同一条** +# 实现路径,不存在第二套枚举实现。 +# ============================================================ + +def _enum_member_annassign(ps: rawptr[Parser], owner: rawptr[AST], + name_node: rawptr[AST], + lineno: int, col: int, + end_lineno: int, end_col: int) -> rawptr[AST]: + """把单个成员名节点改写为 `Name: t.State` 的 AnnAssign(enum 成员统一形态)。 + + target=Name(id, Store)、annotation=Attribute(Name('t'), 'State')、 + value=None、simple=1 —— 与手写 `class X(t.CEnum): A: t.State` 逐字段同形。 + """ + ann: rawptr[AST] = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "State", ASTCtx.Load) + _set_pos(ann, lineno, col, end_lineno, end_col) + aa: rawptr[AST] = AnnAssign(ps.pool, name_node, ann, None, 1) + _fix_store_ctx(name_node) + _set_pos(aa, lineno, col, end_lineno, end_col) + aa.parent = owner # 与 AST.append 一致地维护父指针 + return aa + + +def _convert_enum_bare_members(ps: rawptr[Parser], node: rawptr[ClassDef]): + """把 enum 体里的裸名 / 逗号分组成员行就地改写为 `Name: t.State` 的 AnnAssign。 + + 成员收集(ClassGenEnum._translate_enum_def 只认 Assign / AnnAssign 的 Name + 目标;TPC 侧 HandlesClassDef._RegisterEnumMembers 同口径)**不认**裸名语句 + (表达式语句 `Expr(Name)`)与逗号分组语句(表达式语句 `Expr(Tuple)`)—— + 两者此前都会被**静默漏掉**(成员凭空消失,直到访问处 NameError / 别处误报)。 + + 两种成员**行**形态(与 TPC 侧 SymbolUtils._ExpandEnumBlocks 同口径): + - `A` → `A: t.State`(整条语句替换为一个 AnnAssign) + - `A, B, C` → `A: t.State` / `B: t.State` / `C: t.State`(三条 AnnAssign) + 逗号组要求"全是简单标识符且 ≥2 个"(尾随逗号在 AST 上与正常组不可区分,按 + 正常组处理);带值逗号组 `A, B = 1`、带注解逗号组 `A, B: T`、单名尾随逗号 + `A,` 与其余语句**不**在此改写——它们由注册处的"源码可见成员名数 ≠ 实际登记 + 成员数"fail-fast 拦住(ClassGenEnum._translate_enum_def),不再静默丢成员。 + 缩进/空行/注释的容忍由 _parse_suite_into_children 承担(本函数只看语句种类)。 + """ + children: rawptr[list[rawptr[AST]]] = node.children + if children is None: + return + cn: sizet = len(children) + # 重建子表:逗号组一行 → 多条 AnnAssign。list 无 insert,故整体重建;赋值形态 + # 与 AST.append(base.vp:358 `self.children = list[rawptr[AST]](...)`)逐字同形。 + node.children = list[rawptr[AST]](ps.pool, 8) + out: rawptr[list[rawptr[AST]]] = node.children + i: sizet = 0 + while i < cn: + stmt: rawptr[AST] = children.get(i) + handled: int = 0 + if stmt is not None and stmt.kind() == ASTKind.Expr: + ex: rawptr[Expr] = (rawptr[Expr])(stmt) + if ex.value is not None and ex.value.kind() == ASTKind.Name: + out.append(_enum_member_annassign(ps, node, ex.value, + ex.lineno, ex.col_offset, + ex.end_lineno, ex.end_col_offset)) + handled = 1 + elif ex.value is not None and ex.value.kind() == ASTKind.Tuple: + tup: rawptr[Tuple] = (rawptr[Tuple])(ex.value) + if tup.elts is not None and len(tup.elts) >= 2: + all_names: int = 1 + k: sizet = 0 + while k < len(tup.elts): + el: rawptr[AST] = tup.elts.get(k) + if el is None or el.kind() != ASTKind.Name: + all_names = 0 + break + k += 1 + if all_names == 1: + k = 0 + while k < len(tup.elts): + el2: rawptr[AST] = tup.elts.get(k) + out.append(_enum_member_annassign(ps, node, el2, + el2.lineno, el2.col_offset, + el2.end_lineno, el2.end_col_offset)) + k += 1 + handled = 1 + if handled == 0 and stmt is not None: + out.append(stmt) + i += 1 + + +def _parse_define_const(ps: rawptr[Parser]) -> rawptr[AST]: + """`define NAME[: T] = <字面量>` → 与 `NAME: [T |] t.CDefine = <字面量>` + 逐字段同形的 AnnAssign(define 常量声明语法糖)。 + + - 与手写 `NAME: t.CDefine = 值` 落到**同一条** CDefine 注册路径 + (AssignGen 的 is_cdefine_annotation 分支);不新增第二套常量实现。 + - 带类型时 T 写在联合**前面**(`T | t.CDefine`):与 TPC 侧 + `SymbolUtils._ExpandDefineConsts` 的展开产物同形,使"值必须能放进 T" + 这条判据有据可依(TPV 的 is_cdefine_annotation 与顺序无关, + 仅取"含 CDefine"这一事实)。 + - 行号/列号取自 define 关键字所在位置,报错回显定位到真实源码行。 + - 语句必须换行/文件尾结束(与 _parse_simple_stmt_into 同口径); + 残留 token 属语法错误(_record_parse_err,fail-fast,不静默)。 + """ + lineno: int = _cur_lineno(ps) + col: int = _cur_col(ps) + _advance(ps) # define + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + _record_parse_err(ps) + return None + name: str = _cur_str(ps) + _advance(ps) + explicit_ann: rawptr[AST] = None + if _accept_op(ps, TokOp.Colon): + explicit_ann = _parse_type_ann(ps) + if explicit_ann is None: + return None + if _expect_op(ps, TokOp.Equal) == 0: + return None + value: rawptr[AST] = _parse_test(ps) + if value is None: + ps.error_count += 1 + _record_parse_err(ps) + return None + cdefine_marker: rawptr[AST] = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "CDefine", ASTCtx.Load) + annotation: rawptr[AST] = cdefine_marker + if explicit_ann is not None: + annotation = BinOp(ps.pool, explicit_ann, OpKind.BitOr, cdefine_marker) + target: rawptr[AST] = Name(ps.pool, name, ASTCtx.Store) + _set_pos(target, lineno, col, 0, 0) + node: rawptr[AST] = AnnAssign(ps.pool, target, annotation, value, 1) + _set_pos(node, lineno, col, 0, 0) + _skip_nl(ps) + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + _record_parse_err(ps) + ps.error_count += 1 + return None + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + return node + + +def _parse_typedef(ps: rawptr[Parser]) -> rawptr[AST]: + """`typedef T1 = T2` → 与 `T1: t.CTypedef = T2` 逐字段同形的 AnnAssign。 + + - 与手写 `T1: t.CTypedef = T2` 落到**同一条** typedef 注册/查找路径 + (AssignGenMixin.translate_annassign 的 CTypedef 分支 → ScanCTypedefDeclarations + / TypeGenCType.register_ctypedef);**不新增第二套 typedef 实现**。 + - 注解为 `Attribute(Name('t'), 'CTypedef')`,与 TPC 侧展开产物 + `SymbolUtils._ExpandTypedefs` 同形(`t.CTypedef`)。 + - RHS 即"类型表达式"(写在值位,按 `_parse_test` 解析):裸名 `int32` / + `t.X` / 并集 `char | t.CPtr` / 泛型 `array[E, N]` / 链式 `A = B`。 + - 行号/列号取自 typedef 关键字所在位置,报错回显定位到真实源码行。 + - 非法形态(缺名字 / 缺 `=` / 缺 RHS)⇒ `_record_parse_err` **响亮失败** + (fail-fast,不静默);语句必须换行/文件尾结束(与 _parse_define_const 同口径)。 + """ + lineno: int = _cur_lineno(ps) + col: int = _cur_col(ps) + _advance(ps) # typedef + if _cur_type(ps) != TokenType.Name: + # 缺别名(如 `typedef = 1` / `typedef : x`):响亮失败。 + _record_parse_err(ps) + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + if _expect_op(ps, TokOp.Equal) == 0: + # 缺 `=`(如 `typedef A`):响亮失败。 + return None + value: rawptr[AST] = _parse_test(ps) + if value is None: + # 缺 RHS(如 `typedef A = `):响亮失败。 + ps.error_count += 1 + _record_parse_err(ps) + return None + ctypedef_marker: rawptr[AST] = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "CTypedef", ASTCtx.Load) + target: rawptr[AST] = Name(ps.pool, name, ASTCtx.Store) + _set_pos(target, lineno, col, 0, 0) + node: rawptr[AST] = AnnAssign(ps.pool, target, ctypedef_marker, value, 1) + _set_pos(node, lineno, col, 0, 0) + _skip_nl(ps) + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + _record_parse_err(ps) + ps.error_count += 1 + return None + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + return node + + +def _parse_enumdef(ps: rawptr[Parser]) -> rawptr[AST]: + """enum NAME: 语法糖 → 与 `class NAME(t.CEnum):` 逐字段同形的 ClassDef。 + + 成员书写形态(与 TPC 侧 SymbolUtils._ExpandEnumBlocks 同口径): + - 裸名 `A` → `A: t.State`(默认编号 0..N,宽度默认 i32) + - 逗号组 `A, B` → 同行拆成多条 `A: t.State` / `B: t.State`(≥2 个简单标识符) + - 带注解 `A: T` → 原样(自定义具体类型,参与"最宽成员类型"宽度推导) + - 带值 `A = 0` → 原样(显式编号) + + 基类固定为 Attribute(Name('t'), 'CEnum'),与手写 `class X(t.CEnum):` 的 + bases[0] 逐字段同形(同一 _parse_classdef 基类解析产物)。行号/列号原样继承 + 自各成员语句,故报错回显(如"枚举成员 'P' 不能是指针类型")定位到真实源码行。 + """ + lineno: int = _cur_lineno(ps) + col: int = _cur_col(ps) + _advance(ps) # enum + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + bases: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](ps.pool, 8) + bases.append(Attribute(ps.pool, Name(ps.pool, "t", ASTCtx.Load), + "CEnum", ASTCtx.Load)) + keywords: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](ps.pool, 8) + dec_list: rawptr[list[rawptr[AST]]] = ps.pending_decorators + ps.pending_decorators = None + _expect_op(ps, TokOp.Colon) + node: rawptr[ClassDef] = ClassDef(ps.pool, name, bases, keywords, dec_list, None) _parse_suite_into_children(ps, node) + _convert_enum_bare_members(ps, node) _set_pos(node, lineno, col, 0, 0) return node @@ -2611,6 +3428,13 @@ def _parse_closed_pattern(ps: rawptr[Parser]) -> rawptr[AST]: _advance(ps) if _cur_type(ps) == TokenType.Number: tok = ps.cur + # 一元减 + 整数字面量的联合越界判定(与 _parse_factor 同口径): + # 幅值 > 2^63 的负数字面量(如 -18446744073709551615、-9223372036854775809) + # 结果 < -2^63 ⇒ fail-fast,不静默回绕。 + if tok.is_float == 0 and _lex_int_neg_exceeds_i64(_cur_str(ps)) != 0: + _record_neg_literal_overflow(_cur_str(ps), lineno, col) + ps.error_count += 1 + return None _advance(ps) if tok.is_float: val = _new_const_float(ps.pool, -tok.float_val, lineno, col) @@ -2890,6 +3714,16 @@ def parse_tokens(pool: rawptr[memhub.MemManager], _g_parse_err_line = 0 _g_parse_err_col = 0 _g_parse_err_msg = None + # 词法层 fail-fast 优先上报:tokenize 期间记录的溢出(如整数字面量 > 2^64-1)在此 + # 转写到解析错误通道,复用 dump_parse_traceback 的 "文件:行:列 + 源码行 + + # SyntaxError: 消息" 报告路径(并终止编译)。lexer 无独立 fatal 出口,这是它 + # 唯一的对外上报点。 + lex_line: int = get_lex_err_line() + if lex_line != 0: + _g_parse_err_line = lex_line + _g_parse_err_col = get_lex_err_col() + _g_parse_err_msg = get_lex_err_msg() + return None ps: rawptr[Parser] = new_parser(pool) if ps is None: return None _parser_init(ps, tokens, pool) @@ -2897,6 +3731,5 @@ def parse_tokens(pool: rawptr[memhub.MemManager], _parse_module_body(ps, module_node) # fail-fast: 解析出错(error_count > 0)时返回 None,由调用方(TPV 等)报错终止, # 避免错误代码静默编译(如 `func12344444 avg3(...)` 缺 def 关键字的函数定义残留)。 - if ps.error_count > 0: - return None + if ps.error_count > 0: return None return module_node diff --git a/ast/stmts.vp b/ast/stmts.vp index 1209c6f..00975a5 100644 --- a/ast/stmts.vp +++ b/ast/stmts.vp @@ -20,8 +20,7 @@ class Module(AST): def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[Module] = pool.alloc(Module.__sizeof__()) - if ptr: - string.memset(ptr, 0, Module.__sizeof__()) + if ptr: string.memset(ptr, 0, Module.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager]): @@ -33,8 +32,7 @@ class Module(AST): def type_name(self) -> str: return "Module" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Module(body=") pos = _dump_list(self.children, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -53,8 +51,7 @@ class Assign(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], targets: rawptr[list[rawptr[AST]]], value: rawptr[AST]): ptr: rawptr[Assign] = pool.alloc(Assign.__sizeof__()) - if ptr: - string.memset(ptr, 0, Assign.__sizeof__()) + if ptr: string.memset(ptr, 0, Assign.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -70,8 +67,7 @@ class Assign(Stmt): def type_name(self) -> str: return "Assign" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Assign(targets=") pos = _dump_list(self.targets, buf, size, pos) pos = _emit(buf, size, pos, ", value=") @@ -96,8 +92,7 @@ class If(Stmt): test: rawptr[AST], orelse: rawptr[list[rawptr[AST]]]): ptr: rawptr[If] = pool.alloc(If.__sizeof__()) - if ptr: - string.memset(ptr, 0, If.__sizeof__()) + if ptr: string.memset(ptr, 0, If.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -114,8 +109,7 @@ class If(Stmt): def type_name(self) -> str: return "If" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "If(test=") if self.test is not None: pos = self.test.dump(buf, size, pos) @@ -145,8 +139,7 @@ class For(Stmt): orelse: rawptr[list[rawptr[AST]]], is_async: int): ptr: rawptr[For] = pool.alloc(For.__sizeof__()) - if ptr: - string.memset(ptr, 0, For.__sizeof__()) + if ptr: string.memset(ptr, 0, For.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -169,8 +162,7 @@ class For(Stmt): def type_name(self) -> str: return "For" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "For(target=") if self.target is not None: pos = self.target.dump(buf, size, pos) @@ -200,8 +192,7 @@ class While(Stmt): test: rawptr[AST], orelse: rawptr[list[rawptr[AST]]]): ptr: rawptr[While] = pool.alloc(While.__sizeof__()) - if ptr: - string.memset(ptr, 0, While.__sizeof__()) + if ptr: string.memset(ptr, 0, While.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -218,8 +209,7 @@ class While(Stmt): def type_name(self) -> str: return "While" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "While(test=") if self.test is not None: pos = self.test.dump(buf, size, pos) @@ -241,8 +231,7 @@ class Return(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[Return] = pool.alloc(Return.__sizeof__()) - if ptr: - string.memset(ptr, 0, Return.__sizeof__()) + if ptr: string.memset(ptr, 0, Return.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -255,8 +244,7 @@ class Return(Stmt): def type_name(self) -> str: return "Return" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Return(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -276,8 +264,7 @@ class Expr(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): ptr: rawptr[Expr] = pool.alloc(Expr.__sizeof__()) - if ptr: - string.memset(ptr, 0, Expr.__sizeof__()) + if ptr: string.memset(ptr, 0, Expr.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], value: rawptr[AST]): @@ -290,8 +277,7 @@ class Expr(Stmt): def type_name(self) -> str: return "Expr" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Expr(value=") if self.value is not None: pos = self.value.dump(buf, size, pos) @@ -324,8 +310,7 @@ class FunctionDef(Stmt): decorator_list: rawptr[list[rawptr[AST]]], returns: rawptr[AST], is_async: int): ptr: rawptr[FunctionDef] = pool.alloc(FunctionDef.__sizeof__()) - if ptr: - string.memset(ptr, 0, FunctionDef.__sizeof__()) + if ptr: string.memset(ptr, 0, FunctionDef.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -351,8 +336,7 @@ class FunctionDef(Stmt): def type_name(self) -> str: return "FunctionDef" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "FunctionDef(name='") pos = _emit_str(buf, size, pos, self.name) pos = _emit(buf, size, pos, "', args=") @@ -384,8 +368,7 @@ class Expression(AST): def __new__(self, pool: rawptr[memhub.MemManager], body: rawptr[AST]): ptr: rawptr[Expression] = pool.alloc(Expression.__sizeof__()) - if ptr: - string.memset(ptr, 0, Expression.__sizeof__()) + if ptr: string.memset(ptr, 0, Expression.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -399,8 +382,7 @@ class Expression(AST): def type_name(self) -> str: return "Expression" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Expression(body=") if self.body is not None: pos = self.body.dump(buf, size, pos) @@ -421,8 +403,7 @@ class Interactive(AST): def __new__(self, pool: rawptr[memhub.MemManager], body: rawptr[AST]): ptr: rawptr[Interactive] = pool.alloc(Interactive.__sizeof__()) - if ptr: - string.memset(ptr, 0, Interactive.__sizeof__()) + if ptr: string.memset(ptr, 0, Interactive.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -436,8 +417,7 @@ class Interactive(AST): def type_name(self) -> str: return "Interactive" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Interactive(body=") if self.body is not None: pos = self.body.dump(buf, size, pos) @@ -460,8 +440,7 @@ class FunctionType(AST): argtypes: rawptr[list[rawptr[AST]]], returns: rawptr[AST]): ptr: rawptr[FunctionType] = pool.alloc(FunctionType.__sizeof__()) - if ptr: - string.memset(ptr, 0, FunctionType.__sizeof__()) + if ptr: string.memset(ptr, 0, FunctionType.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -477,8 +456,7 @@ class FunctionType(AST): def type_name(self) -> str: return "FunctionType" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "FunctionType(argtypes=") pos = _dump_list(self.argtypes, buf, size, pos) pos = _emit(buf, size, pos, ", returns=") @@ -513,8 +491,7 @@ class ClassDef(Stmt): decorator_list: rawptr[list[rawptr[AST]]], type_params: rawptr[list[str]] = None): ptr: rawptr[ClassDef] = pool.alloc(ClassDef.__sizeof__()) - if ptr: - string.memset(ptr, 0, ClassDef.__sizeof__()) + if ptr: string.memset(ptr, 0, ClassDef.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -537,8 +514,7 @@ class ClassDef(Stmt): def type_name(self) -> str: return "ClassDef" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "ClassDef(name='") pos = _emit_str(buf, size, pos, self.name) pos = _emit(buf, size, pos, "', bases=") @@ -564,8 +540,7 @@ class Delete(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], targets: rawptr[list[rawptr[AST]]]): ptr: rawptr[Delete] = pool.alloc(Delete.__sizeof__()) - if ptr: - string.memset(ptr, 0, Delete.__sizeof__()) + if ptr: string.memset(ptr, 0, Delete.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -580,8 +555,7 @@ class Delete(Stmt): def type_name(self) -> str: return "Delete" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Delete(targets=") pos = _dump_list(self.targets, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -601,8 +575,7 @@ class AugAssign(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], target: rawptr[AST], op: int, value: rawptr[AST]): ptr: rawptr[AugAssign] = pool.alloc(AugAssign.__sizeof__()) - if ptr: - string.memset(ptr, 0, AugAssign.__sizeof__()) + if ptr: string.memset(ptr, 0, AugAssign.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -618,8 +591,7 @@ class AugAssign(Stmt): def type_name(self) -> str: return "AugAssign" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "AugAssign(target=") if self.target is not None: pos = self.target.dump(buf, size, pos) @@ -651,8 +623,7 @@ class AnnAssign(Stmt): target: rawptr[AST], annotation: rawptr[AST], value: rawptr[AST], simple: int): ptr: rawptr[AnnAssign] = pool.alloc(AnnAssign.__sizeof__()) - if ptr: - string.memset(ptr, 0, AnnAssign.__sizeof__()) + if ptr: string.memset(ptr, 0, AnnAssign.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -670,8 +641,7 @@ class AnnAssign(Stmt): def type_name(self) -> str: return "AnnAssign" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "AnnAssign(target=") if self.target is not None: pos = self.target.dump(buf, size, pos) @@ -706,8 +676,7 @@ class With(Stmt): items: rawptr[list[rawptr[AST]]], is_async: int): ptr: rawptr[With] = pool.alloc(With.__sizeof__()) - if ptr: - string.memset(ptr, 0, With.__sizeof__()) + if ptr: string.memset(ptr, 0, With.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -727,8 +696,7 @@ class With(Stmt): def type_name(self) -> str: return "With" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "With(items=") pos = _dump_list(self.items, buf, size, pos) pos = _emit(buf, size, pos, ", body=") @@ -749,8 +717,7 @@ class Raise(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], exc: rawptr[AST], cause: rawptr[AST]): ptr: rawptr[Raise] = pool.alloc(Raise.__sizeof__()) - if ptr: - string.memset(ptr, 0, Raise.__sizeof__()) + if ptr: string.memset(ptr, 0, Raise.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -765,8 +732,7 @@ class Raise(Stmt): def type_name(self) -> str: return "Raise" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Raise(exc=") if self.exc is not None: pos = self.exc.dump(buf, size, pos) @@ -797,8 +763,7 @@ class Try(Stmt): orelse: rawptr[list[rawptr[AST]]], finalbody: rawptr[list[rawptr[AST]]]): ptr: rawptr[Try] = pool.alloc(Try.__sizeof__()) - if ptr: - string.memset(ptr, 0, Try.__sizeof__()) + if ptr: string.memset(ptr, 0, Try.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -819,8 +784,7 @@ class Try(Stmt): def type_name(self) -> str: return "Try" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Try(body=") pos = _dump_list(self.children, buf, size, pos) pos = _emit(buf, size, pos, ", handlers=") @@ -845,8 +809,7 @@ class Assert(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], test: rawptr[AST], msg: rawptr[AST]): ptr: rawptr[Assert] = pool.alloc(Assert.__sizeof__()) - if ptr: - string.memset(ptr, 0, Assert.__sizeof__()) + if ptr: string.memset(ptr, 0, Assert.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -861,8 +824,7 @@ class Assert(Stmt): def type_name(self) -> str: return "Assert" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Assert(test=") if self.test is not None: pos = self.test.dump(buf, size, pos) @@ -888,8 +850,7 @@ class Global(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], names: rawptr[list[rawptr[AST]]]): ptr: rawptr[Global] = pool.alloc(Global.__sizeof__()) - if ptr: - string.memset(ptr, 0, Global.__sizeof__()) + if ptr: string.memset(ptr, 0, Global.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -904,8 +865,7 @@ class Global(Stmt): def type_name(self) -> str: return "Global" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Global(names=") pos = _dump_list(self.names, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -923,8 +883,7 @@ class Nonlocal(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], names: rawptr[list[rawptr[AST]]]): ptr: rawptr[Nonlocal] = pool.alloc(Nonlocal.__sizeof__()) - if ptr: - string.memset(ptr, 0, Nonlocal.__sizeof__()) + if ptr: string.memset(ptr, 0, Nonlocal.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -939,8 +898,7 @@ class Nonlocal(Stmt): def type_name(self) -> str: return "Nonlocal" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Nonlocal(names=") pos = _dump_list(self.names, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -956,8 +914,7 @@ class Pass(Stmt): def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[Pass] = pool.alloc(Pass.__sizeof__()) - if ptr: - string.memset(ptr, 0, Pass.__sizeof__()) + if ptr: string.memset(ptr, 0, Pass.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager]): @@ -969,8 +926,7 @@ class Pass(Stmt): def type_name(self) -> str: return "Pass" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Pass()") return pos @@ -984,8 +940,7 @@ class Break(Stmt): def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[Break] = pool.alloc(Break.__sizeof__()) - if ptr: - string.memset(ptr, 0, Break.__sizeof__()) + if ptr: string.memset(ptr, 0, Break.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager]): @@ -997,8 +952,7 @@ class Break(Stmt): def type_name(self) -> str: return "Break" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Break()") return pos @@ -1012,8 +966,7 @@ class Continue(Stmt): def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[Continue] = pool.alloc(Continue.__sizeof__()) - if ptr: - string.memset(ptr, 0, Continue.__sizeof__()) + if ptr: string.memset(ptr, 0, Continue.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager]): @@ -1025,8 +978,7 @@ class Continue(Stmt): def type_name(self) -> str: return "Continue" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Continue()") return pos @@ -1042,8 +994,7 @@ class Import(Stmt): def __new__(self, pool: rawptr[memhub.MemManager], names: rawptr[list[rawptr[AST]]]): ptr: rawptr[Import] = pool.alloc(Import.__sizeof__()) - if ptr: - string.memset(ptr, 0, Import.__sizeof__()) + if ptr: string.memset(ptr, 0, Import.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1058,8 +1009,7 @@ class Import(Stmt): def type_name(self) -> str: return "Import" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Import(names=") pos = _dump_list(self.names, buf, size, pos) pos = _emit(buf, size, pos, ")") @@ -1081,8 +1031,7 @@ class ImportFrom(Stmt): names: rawptr[list[rawptr[AST]]], level: int): ptr: rawptr[ImportFrom] = pool.alloc(ImportFrom.__sizeof__()) - if ptr: - string.memset(ptr, 0, ImportFrom.__sizeof__()) + if ptr: string.memset(ptr, 0, ImportFrom.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1101,8 +1050,7 @@ class ImportFrom(Stmt): def type_name(self) -> str: return "ImportFrom" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "ImportFrom(module='") pos = _emit_str(buf, size, pos, self.module) pos = _emit(buf, size, pos, "', names=") @@ -1126,8 +1074,7 @@ class Match(Stmt): subject: rawptr[AST], cases: rawptr[list[rawptr[AST]]]): ptr: rawptr[Match] = pool.alloc(Match.__sizeof__()) - if ptr: - string.memset(ptr, 0, Match.__sizeof__()) + if ptr: string.memset(ptr, 0, Match.__sizeof__()) return ptr def __init__(self, pool: rawptr[memhub.MemManager], @@ -1144,8 +1091,7 @@ class Match(Stmt): def type_name(self) -> str: return "Match" - def dump(self, buf: str, size: t.CSizeT, - pos: t.CSizeT) -> t.CSizeT: + def dump(self, buf: str, size: sizet, pos: sizet) -> sizet: pos = _emit(buf, size, pos, "Match(subject=") if self.subject is not None: pos = self.subject.dump(buf, size, pos) diff --git a/ast/tokens.vp b/ast/tokens.vp index f75515b..f6bbea3 100644 --- a/ast/tokens.vp +++ b/ast/tokens.vp @@ -84,6 +84,33 @@ class Keyword(t.CEnum): # define 宏函数关键字(与 def 语义一致,返回注解自动追加 t.CDefine 标记 # 为宏函数;软判定见 _is_funcdef_kw) Define: t.State + # enum 枚举定义关键字(语法糖:`enum X:` 与 `class X(t.CEnum):` 等价, + # 见 parser.vp 的 _parse_enumdef)。追加在**表尾**而非插在 Class 之后: + # 本枚举成员的值按声明序递增,插在中间会平移 Class 之后所有关键字的编号 + # (kw_subtype 数值),追加则既有编号逐字不变。 + Enum: t.State + # typedef 类型别名关键字(语法糖:`typedef T1 = T2` 与 + # `T1: t.CTypedef = T2` 等价,见 parser.vp 的 _parse_typedef)。同样追加在 + # **表尾**:既有关键字编号(kw_subtype)逐字不变。 + Typedef: t.State + # 类型描述符关键字 const / volatile(语法糖:描述符写在类型前, + # `a: const int` 与 `a: t.CConst | int` 等价,见 parser.vp 的 _parse_type_ann)。 + # 同样追加在**表尾**:既有关键字编号(kw_subtype)逐字不变。 + # 二者是**软关键字**——只在注解位置(`:` 后 / `->` 后)生效;作标识符的写法 + # (t.attr.const(),TransPyV/Test/App/attr_test.vp:142)不受影响: + # 该处 token 类型仍是 Name,属性名解析只看 TokenType.Name,不看 kw_subtype。 + Const: t.State + Volatile: t.State + # virtual / novirtual 修饰符关键字(语法糖:`virtual class C:` / + # `novirtual class C:` / `virtual def m(...)` / `novirtual def m(...)`, + # 与手写类/方法装饰器 `@t.CVTable` / `@t.NoVTable` **同一套表示**, + # 见 parser.vp 的 _ParseVirtualModified)。同样追加在**表尾**:既有关键字 + # 编号(kw_subtype)逐字不变。 + # 二者是**软关键字**——只在"语句起始 + 紧跟 class/def"时生效;作标识符的写法 + # (`x = d.virtual` / 形参名 / for 目标 / 字典键)不受影响:那些位置按 + # TokenType.Name 解析,不看 kw_subtype。 + Virtual: t.State + Novirtual: t.State # ============================================================ @@ -164,8 +191,7 @@ class Token: def __new__(self, pool: rawptr[memhub.MemManager]): """Allocate zero‑initialized Token struct memory from mpool""" ptr: rawptr[Token] = pool.alloc(Token.__sizeof__()) - if ptr: - string.memset(ptr, 0, Token.__sizeof__()) + if ptr: string.memset(ptr, 0, Token.__sizeof__()) return ptr @@ -180,8 +206,7 @@ class KwEntry: def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[KwEntry] = pool.alloc(KwEntry.__sizeof__()) - if ptr: - string.memset(ptr, 0, KwEntry.__sizeof__()) + if ptr: string.memset(ptr, 0, KwEntry.__sizeof__()) return ptr @@ -190,12 +215,12 @@ _kw_head: rawptr[KwEntry] = None _kw_pool: rawptr[memhub.MemManager] = None # 关键字哈希索引(开放寻址 | 线性探测):槽为 u64,0=空槽,否则存 KwEntry 地址。 -# 目的:把 _kw_lookup 的 45 项链表线性扫描降为期望 O(1)(不改链表本身)。索引与 +# 目的:把 _kw_lookup 的 46 项链表线性扫描降为期望 O(1)(不改链表本身)。索引与 # 链表同源——在 _init_keywords 里由同一批 _kw_intern 派生,不另抄关键字列表。 # 关键字为静态集合且一次性注册完毕 ⇒ 索引是"完整"的:查找未命中等价于原扫描 # 返回 0(无需回退链表扫描);回退仅用于索引未建成(分配失败)时,保证正确性。 -_kw_index: sizet | t.CPtr = None -# 索引槽数(2 的幂且 > 2*45,负载 < 0.5,探测必然终止) +_kw_index: sizet* = None +# 索引槽数(2 的幂且 > 2*46,负载 < 0.5,探测必然终止) _KW_IDX_CAP: t.CDefine = 128 # FNV-1a 64 位常量(与 hashtable.vp 同款) _KW_FNV_OFFSET: t.CUInt64T = 0xcbf29ce484222325 @@ -221,11 +246,11 @@ def _kw_index_put(entry: rawptr[KwEntry]): """ if _kw_index == None: return h: uint64 = _kw_hash_str(entry.name) - mask: t.CSizeT = t.CSizeT(_KW_IDX_CAP - 1) - idx: t.CSizeT = t.CSizeT(h) & mask + mask: sizet = sizet(_KW_IDX_CAP - 1) + idx: sizet = sizet(h) & mask i: int = 0 while i < _KW_IDX_CAP: - slot: sizet | t.CPtr = (sizet | t.CPtr)(t.CPtr(uint64(_kw_index) + uint64(idx * 8))) + slot: sizet* = (sizet*)(t.CPtr(uint64(_kw_index) + uint64(idx * 8))) cur_s: sizet = slot[0] if cur_s == 0: slot[0] = sizet(entry) @@ -242,7 +267,7 @@ def _kw_intern(pool: rawptr[memhub.MemManager], name: str, kw_id: int): global _kw_head entry: rawptr[KwEntry] = KwEntry(pool) if entry == None: return - slen: t.CSizeT = string.strlen(name) + slen: sizet = string.strlen(name) buf: str = pool.alloc(slen + 1) if buf == None: return string.memcpy(buf, name, slen + 1) @@ -261,11 +286,11 @@ def _kw_lookup(name: str) -> int: """ if _kw_index != None: h: uint64 = _kw_hash_str(name) - mask: t.CSizeT = t.CSizeT(_KW_IDX_CAP - 1) - idx: t.CSizeT = t.CSizeT(h) & mask + mask: sizet = sizet(_KW_IDX_CAP - 1) + idx: sizet = sizet(h) & mask i: int = 0 while i < _KW_IDX_CAP: - slot: sizet | t.CPtr = (sizet | t.CPtr)(t.CPtr(uint64(_kw_index) + uint64(idx * 8))) + slot: sizet* = (sizet*)(t.CPtr(uint64(_kw_index) + uint64(idx * 8))) cur_s: sizet = slot[0] if cur_s == 0: return 0 @@ -289,7 +314,7 @@ def _init_keywords(pool: rawptr[memhub.MemManager]): if _kw_head != None: return _kw_pool = pool # 建哈希索引槽数组(一次性分配;分配失败则 _kw_index 保持 None → 查找回退链表扫描) - idx_buf: sizet | t.CPtr = pool.alloc(_KW_IDX_CAP * 8) + idx_buf: sizet* = pool.alloc(_KW_IDX_CAP * 8) if idx_buf != None: string.memset(idx_buf, 0, _KW_IDX_CAP * 8) _kw_index = idx_buf @@ -339,6 +364,15 @@ def _init_keywords(pool: rawptr[memhub.MemManager]): _kw_intern(pool, "extern", Keyword.Extern) _kw_intern(pool, "export", Keyword.Export) _kw_intern(pool, "define", Keyword.Define) + _kw_intern(pool, "enum", Keyword.Enum) + _kw_intern(pool, "typedef", Keyword.Typedef) + # 类型描述符软关键字(仅注解位置生效,见 parser.vp 的 _parse_type_ann) + _kw_intern(pool, "const", Keyword.Const) + _kw_intern(pool, "volatile", Keyword.Volatile) + # virtual / novirtual 修饰符软关键字(仅"语句起始 + 紧跟 class/def"生效, + # 见 parser.vp 的 _ParseVirtualModified) + _kw_intern(pool, "virtual", Keyword.Virtual) + _kw_intern(pool, "novirtual", Keyword.Novirtual) # ============================================================ @@ -354,8 +388,7 @@ class OpEntry: def __new__(self, pool: rawptr[memhub.MemManager]): ptr: rawptr[OpEntry] = pool.alloc(OpEntry.__sizeof__()) - if ptr: - string.memset(ptr, 0, OpEntry.__sizeof__()) + if ptr: string.memset(ptr, 0, OpEntry.__sizeof__()) return ptr @@ -364,7 +397,7 @@ _op_head: rawptr[OpEntry] = None def _op_intern(pool: rawptr[memhub.MemManager], name: str, op_id: int): global _op_head - slen: t.CSizeT = string.strlen(name) + slen: sizet = string.strlen(name) entry: rawptr[OpEntry] = OpEntry(pool) if entry == None: return buf: str = pool.alloc(slen + 1) @@ -457,7 +490,7 @@ def new_token(pool: rawptr[memhub.MemManager], ttype: int, lineno: int, def token_set_str(pool: rawptr[memhub.MemManager], tok: rawptr[Token], - src: str, start: t.CSizeT, length: t.CSizeT): + src: str, start: sizet, length: sizet): """Copy text from src[start:start + length] to token.str_val Note: When length == 0, still allocate 1 byte for NUL, so that an empty string is distinguished from a NULL pointer. @@ -465,7 +498,7 @@ def token_set_str(pool: rawptr[memhub.MemManager], tok: rawptr[Token], if tok == None: return buf: str = pool.alloc(length + 1) if buf == None: return - i: t.CSizeT = 0 + i: sizet = 0 while i < length: buf[i] = src[start + i] i += 1 @@ -477,7 +510,7 @@ def token_set_str_literal(pool: rawptr[memhub.MemManager], tok: rawptr[Token], text: str): """Copy a C string to token.str_val""" if tok == None or text == None: return - slen: t.CSizeT = string.strlen(text) + slen: sizet = string.strlen(text) buf: str = pool.alloc(slen + 1) if buf == None: return string.memcpy(buf, text, slen + 1) diff --git a/atom.vp b/atom.vp index 6a9bcb6..364d365 100644 --- a/atom.vp +++ b/atom.vp @@ -1,16 +1,16 @@ 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 +define ATOMIC_RELAXED = 0 +define ATOMIC_CONSUME = 1 +define ATOMIC_ACQUIRE = 2 +define ATOMIC_RELEASE = 3 +define ATOMIC_ACQ_REL = 4 +define ATOMIC_SEQ_CST = 5 -def __atomic_test_and_set(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> bool: - result: t.CUInt8T = 1 +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 mov $0, al""", @@ -19,23 +19,23 @@ def __atomic_test_and_set(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> bool: return t.CBool(result) -def __atomic_clear(ptr: t.CUInt64T | t.CPtr, order: t.CInt): +def __atomic_clear(ptr: uint64*, order: int): 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): +def __atomic_thread_fence(order: int): c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) -def __atomic_signal_fence(order: t.CInt): +def __atomic_signal_fence(order: int): pass -def __atomic_always_lock_free(size: t.CSizeT, ptr: t.CPtr) -> t.CBool: - return t.CBool(1) +def __atomic_always_lock_free(size: sizet, ptr: rawptr) -> bool: + return True -def __atomic_is_lock_free(size: t.CSizeT, ptr: t.CPtr) -> t.CBool: - return t.CBool(1) +def __atomic_is_lock_free(size: sizet, ptr: rawptr) -> bool: + return True diff --git a/base64.vp b/base64.vp index 0dfc962..3ad8508 100644 --- a/base64.vp +++ b/base64.vp @@ -5,10 +5,10 @@ import t, c # Base64 Encoder & Decoder, pure bare-metal implementation # ============================================== # Base64 encoding lookup table -b64_tab: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +b64_tab: []char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" # Base64 反向解码表,映射字符到索引值 -b64_dec_tab: t.CArray[t.CInt8T, 80] = [ +b64_dec_tab: [80]int8 = [ 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, @@ -20,18 +20,18 @@ b64_dec_tab: t.CArray[t.CInt8T, 80] = [ # * @param s: Input binary data # * @param out: Output buffer for Base64 string # * @retval Length of encoded string -def b64encode(s: str, out: str) -> t.CSizeT: - _s = t.CUInt8T(s, t.CPtr) - length: t.CSizeT = len(s) - i: t.CSizeT = 0 - j: t.CSizeT = 0 - val: t.CUInt32T = 0 +def b64encode(s: str, out: str) -> sizet: + _s = uint8*(s) + length: sizet = len(s) + i: sizet = 0 + j: sizet = 0 + val: uint32 = 0 # Process input in groups of 3 bytes, produce 4 Base64 characters for i in range(0, length, 3): # Assemble 24-bit chunk - val = ((t.CUInt32T(_s[i + 0]) << 16 ) | - (t.CUInt32T(_s[i + 1]) << 8 if (i + 1 < length) else 0) | - (t.CUInt32T(_s[i + 2]) << 0 if (i + 2 < length) else 0)) + val = ((uint32(_s[i + 0]) << 16 ) | + (uint32(_s[i + 1]) << 8 if (i + 1 < length) else 0) | + (uint32(_s[i + 2]) << 0 if (i + 2 < length) else 0)) # Split into four 6-bit values for table lookup out[j + 0] = b64_tab[(val >> 18) & 0x3F] out[j + 1] = b64_tab[(val >> 12) & 0x3F] @@ -46,11 +46,11 @@ def b64encode(s: str, out: str) -> t.CSizeT: # * @param s: Base64 encoded string # * @param out: Output binary buffer # * @retval Length of decoded binary data -def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT: - length: t.CSizeT = len(s) - i: t.CSizeT = 0 - j: t.CSizeT = 0 - val: t.CUInt32T = 0 +def b64decode(s: str, out: uint8 | t.CPtr) -> sizet: + length: sizet = len(s) + i: sizet = 0 + j: sizet = 0 + val: uint32 = 0 c: t.CInt # Restore 3 bytes from every 4 Base64 characters for i in range(0, length, 4): @@ -63,11 +63,9 @@ def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT: 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 + 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) + if s[i+3] != '=': val |= (b64_dec_tab[c] & 0x3F) # Write recovered bytes out[j] = (val >> 16) & 0xFF j += 1 diff --git a/binascii.vp b/binascii.vp index 5cdd66d..9c84735 100644 --- a/binascii.vp +++ b/binascii.vp @@ -2,27 +2,27 @@ import t, c import stdlib -HEX_CHARS: t.CArray[t.CChar, None] = "0123456789abcdef" -HEX_VALS: t.CArray[t.CInt, 256] +HEX_CHARS: const []char = "0123456789abcdef" +HEX_VALS: [256]int -B64_CHARS: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" -B64_VALS: t.CArray[t.CInt, 256] +B64_CHARS: const []char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +B64_VALS: [256]int # HQX (BinHex 4.0) Alphabet — The standard 64-character table from RFC 1741, where the index corresponds to the 6-bit value (0..63). # Note: There must be exactly 64 elements (previously, 67 were given → compiler fail-fast # "Array initialization element count 67 exceeds array declared length 64"). This table is the authoritative source, # init_binascii builds HQX_VALS based on this alone, and this table must not be rewritten. -HQX_CHARS: t.CArray[t.CChar, 64] = [ +HQX_CHARS: [64]char = [ '!', chr(34), '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '0', '1', '2', '3', '4', '5', '6', '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', '[', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r' ] -HQX_VALS: t.CArray[t.CInt, 256] +HQX_VALS: [256]int -UU_CHARS: t.CArray[t.CChar, None] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +UU_CHARS: const []char = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" -CRC32_TABLE: t.CArray[t.CUnsignedInt, 256] = [ +CRC32_TABLE: [256]uint = [ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, @@ -57,7 +57,7 @@ CRC32_TABLE: t.CArray[t.CUnsignedInt, 256] = [ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ] -CRC_HQX_TABLE: t.CArray[t.CUnsignedShort, 256] = [ +CRC_HQX_TABLE: [256]ushort = [ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, @@ -93,90 +93,86 @@ CRC_HQX_TABLE: t.CArray[t.CUnsignedShort, 256] = [ ] 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 + HEX_VALS[int(HEX_CHARS[i])] = i + HEX_VALS[int(HEX_CHARS[i] - 32)] = i for i in range(64): - B64_VALS[t.CInt(B64_CHARS[i])] = i + B64_VALS[int(B64_CHARS[i])] = i # HQX_VALS 由标准 BinHex 字母表(见 HQX_CHARS 静态初值,RFC 1741)反查建立。 # 注意:此处【不得】再重写 HQX_CHARS——此前用 `chr(32 + i)` 覆盖 0..63, # 会把标准 BinHex 表整张冲掉,导致 b2a_hqx/a2b_hqx 与 RFC 1741 不兼容。 for i in range(64): - HQX_VALS[t.CUnsignedChar(HQX_CHARS[i])] = i + HQX_VALS[uchar(HQX_CHARS[i])] = i -def crc32(data: str, length: t.CInt, crc: t.CUnsignedInt) -> t.CUnsignedInt: - i: t.CInt - s: t.CUnsignedInt = crc ^ 0xFFFFFFFF +def crc32(data: str, length: int, crc: uint) -> uint: + s: uint = crc ^ 0xFFFFFFFF for i in range(length): - s = CRC32_TABLE[(s ^ t.CUnsignedChar(data[i])) & 0xFF] ^ (s >> 8) + s = CRC32_TABLE[(s ^ uchar(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 +def crc_hqx(data: str, length: int, crc: ushort) -> ushort: + s: ushort = crc for i in range(length): - s = CRC_HQX_TABLE[t.CUnsignedChar(s >> 8)] ^ (s << 1 | (data[i] & 0xFF)) + s = CRC_HQX_TABLE[uchar(s >> 8)] ^ (s << 1 | (data[i] & 0xFF)) return s -def hexlify(data: str, length: t.CInt) -> str: +def hexlify(data: str, length: int) -> str: if not data or length < 0: return None out: str = str(stdlib.malloc(length * 2 + 1)) if not out: return None - oi: t.CInt = 0 + oi: int = 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 + s: uchar = uchar(data[i]) + out[oi + 0] = HEX_CHARS[(s >> 4) & 0x0F] + out[oi + 1] = HEX_CHARS[(s >> 0) & 0x0F] + oi += 2 out[oi] = '\0' return out -def b2a_hex(data: str, length: t.CInt) -> str: +def b2a_hex(data: str, length: int) -> str: return hexlify(data, length) -def a2b_hex(hexstr: str, length: t.CInt) -> str: +def a2b_hex(hexstr: str, length: int) -> str: if not hexstr or length < 0 or length % 2 != 0: return None - out_len: t.CInt = length // 2 + out_len: int = length // 2 out: str = str(stdlib.malloc(out_len + 1)) if not out: return None - oi: t.CInt = 0 + oi: int = 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])] + hi: int = HEX_VALS[uchar(hexstr[i])] + lo: int = HEX_VALS[uchar(hexstr[i + 1])] if hi < 0 or lo < 0: stdlib.free(out) return None - out[oi] = t.CChar((hi << 4) | lo) + out[oi] = char((hi << 4) | lo) oi += 1 out[oi] = '\0' return out -def unhexlify(data: str, length: t.CInt) -> bytes: +def unhexlify(data: str, length: int) -> bytes: return a2b_hex(data, length) -def b2a_base64(data: str, length: t.CInt) -> str: +def b2a_base64(data: str, length: int) -> str: if not data or length < 0: return None - olen: t.CInt = (length // 3) * 4 + olen: int = (length // 3) * 4 if length % 3 != 0: olen += 4 olen += 1 out: str = str(stdlib.malloc(olen + 1)) if not out: return None - oi: t.CInt = 0 + oi: int = 0 for i in range(0, length, 3): - b0: t.CUnsignedChar = t.CUnsignedChar(data[i]) - b1: t.CUnsignedChar = 0 - b2: t.CUnsignedChar = 0 + b0: uchar = uchar(data[i]) + b1: uchar = 0 + b2: uchar = 0 if i + 1 < length: - b1 = t.CUnsignedChar(data[i + 1]) + b1 = uchar(data[i + 1]) if i + 2 < length: - b2 = t.CUnsignedChar(data[i + 2]) + b2 = uchar(data[i + 2]) out[oi] = B64_CHARS[(b0 >> 2) & 0x3F] oi += 1 out[oi] = B64_CHARS[((b0 & 0x03) << 4) | ((b1 >> 4) & 0x0F)] @@ -194,28 +190,28 @@ def b2a_base64(data: str, length: t.CInt) -> str: out[oi] = '\0' return out -def a2b_base64(data: str, length: t.CInt) -> str: +def a2b_base64(data: str, length: int) -> str: if not data or length < 4: return None - olen: t.CInt = (length // 4) * 3 + olen: int = (length // 4) * 3 if length >= 4 and data[length - 1] == '=': olen -= 1 if length >= 4 and data[length - 2] == '=': olen -= 1 out: str = str(stdlib.malloc(olen + 1)) if not out: return None - oi: t.CInt = 0 + oi: int = 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 + v0: int = 0 + v1: int = 0 + v2: int = 0 + v3: int = 0 + j: int for j in range(4): - c: t.CChar = data[i + j] + c: char = data[i + j] if c == '=': pass else: - k: t.CInt + k: int for k in range(64): if B64_CHARS[k] == c: if j == 0: v0 = k @@ -223,33 +219,33 @@ def a2b_base64(data: str, length: t.CInt) -> str: elif j == 2: v2 = k elif j == 3: v3 = k break - out[oi] = t.CChar((v0 << 2) | (v1 >> 4)) + out[oi] = char((v0 << 2) | (v1 >> 4)) oi += 1 if data[i + 2] != '=': - out[oi] = t.CChar(((v1 & 0x0F) << 4) | (v2 >> 2)) + out[oi] = char(((v1 & 0x0F) << 4) | (v2 >> 2)) oi += 1 if data[i + 3] != '=': - out[oi] = t.CChar(((v2 & 0x03) << 6) | v3) + out[oi] = char(((v2 & 0x03) << 6) | v3) oi += 1 out[oi] = '\0' return out -def b2a_uu(data: str, length: t.CInt) -> str: +def b2a_uu(data: str, length: int) -> str: if not data or length < 1 or length > 45: return None out: str = str(stdlib.malloc(length * 2 + 2)) if not out: return None - oi: t.CInt = 0 + oi: int = 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 + b0: uchar = uchar(data[i]) + b1: uchar = 0 + b2: uchar = 0 if i + 1 < length: - b1 = t.CUnsignedChar(data[i + 1]) + b1 = uchar(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) + b2 = uchar(data[i + 2]) + m: uint = (uint(b0) << 16) | (uint(b1) << 8) | uint(b2) out[oi] = UU_CHARS[(m >> 18) & 0x3F] oi += 1 out[oi] = UU_CHARS[(m >> 12) & 0x3F] @@ -265,87 +261,86 @@ def b2a_uu(data: str, length: t.CInt) -> str: 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 + length: int = int(data[0]) - 32 if length < 0 or length > 45: return None out: str = str(stdlib.malloc(length + 1)) if not out: return None - oi: t.CInt = 0 - i: t.CInt = 1 + oi: int = 0 + i: int = 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 + v0: int = data[i] - 32 + v1: int = data[i + 1] - 32 + v2: int = data[i + 2] - 32 + v3: int = 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) + m: uint = (uint(v0) << 18) | (uint(v1) << 12) | (uint(v2) << 6) | uint(v3) if oi < length: - out[oi] = t.CChar((m >> 16) & 0xFF) + out[oi] = char((m >> 16) & 0xFF) oi += 1 if oi < length: - out[oi] = t.CChar((m >> 8) & 0xFF) + out[oi] = char((m >> 8) & 0xFF) oi += 1 if oi < length: - out[oi] = t.CChar(m & 0xFF) + out[oi] = char(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]: +def b2a_hqx(data: str, length: int, crc: ushort = 0) -> tuple[str, ushort]: if not data or length != 3: return None, crc out: str = str(stdlib.malloc(5)) if not out: return None, crc # 3字节 → 4字节 HQX - m: t.CUnsignedInt = (t.CUnsignedChar(data[0]) << 16) | (t.CUnsignedChar(data[1]) << 8) | t.CUnsignedChar(data[2]) + m: uint = (uchar(data[0]) << 16) | (uchar(data[1]) << 8) | uchar(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 + s: ushort = crc for i in range(3): - byte: t.CUnsignedChar = t.CUnsignedChar(data[i]) + byte: uchar = uchar(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]: +def a2b_hqx(data: str, crc: ushort = 0) -> tuple[str, ushort]: if not data: return None, crc # 检查字符是否有效 for i in range(4): - cchar: t.CUnsignedChar = t.CUnsignedChar(data[i]) + cchar: uchar = uchar(data[i]) if HQX_VALS[cchar] < 0: return None, crc # 解码 - m: t.CUnsignedInt = 0 + m: uint = 0 for i in range(4): - m = (m << 6) | t.CUnsignedInt(HQX_VALS[t.CUnsignedChar(data[i])]) + m = (m << 6) | uint(HQX_VALS[uchar(data[i])]) out: str = str(stdlib.malloc(4)) if not out: return None, crc - out[0] = t.CChar((m >> 16) & 0xFF) - out[1] = t.CChar((m >> 8) & 0xFF) - out[2] = t.CChar(m & 0xFF) + out[0] = char((m >> 16) & 0xFF) + out[1] = char((m >> 8) & 0xFF) + out[2] = char(m & 0xFF) out[3] = '\0' # CRC 初始化 + 正确计算 - s: t.CUnsignedShort = crc + s: ushort = crc for i in range(3): - byte: t.CUnsignedChar = t.CUnsignedChar(out[i]) + byte: uchar = uchar(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 +def adler32(data: str, length: int, adler: uint) -> uint: + a: uint = adler & 0xFFFF + b: uint = (adler >> 16) & 0xFFFF for i in range(length): - a = (a + t.CUnsignedChar(data[i])) % 65521 + a = (a + uchar(data[i])) % 65521 b = (b + a) % 65521 return (b << 16) | a diff --git a/builtins.vp b/builtins.vp index 6de2682..bd8ad23 100644 --- a/builtins.vp +++ b/builtins.vp @@ -1,35 +1,18 @@ import stdint as __stdint import t -# ============================================================ -# 内置函数(Python 语义,自动与 builtins 关联,无需显式 import) -# ord: 字符 → ASCII 码(int) -# chr: ASCII 码 → 字符(t.CChar) -# min/max: 数值比较取小/大值(double 参数,int/float 实参经 -# coerce_to_type 无损提升;返回值由调用侧 coerce 到目标类型) -# ============================================================ -def ord(s: t.CChar) -> int: - return s +def ord(s: char) -> int: return int(s) +def chr(i: int) -> char: return char(i) -def chr(i: int) -> t.CChar: - return i - -def min(a: double, b: double) -> double: - if a < b: - return a - return b - -def max(a: double, b: double) -> double: - if a > b: - return a - return b +def min(a: double, b: double) -> double: return a if a < b else b +def max(a: double, b: double) -> double: return a if a > b else b # rawptr 已内置于编译器(TPC/TPV 双端),作为语法保留字,不可重定义: # rawptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T])。 -size_t: t.CTypedef = t.CSizeT -uzt: t.CTypedef = t.CSizeT sizet: t.CTypedef = t.CSizeT +size_t: t.CTypedef = sizet +uzt: t.CTypedef = sizet int8: t.CTypedef = t.CInt8T int16: t.CTypedef = t.CInt16T int32: t.CTypedef = t.CInt32T @@ -56,3 +39,22 @@ uintleast8: t.CTypedef = t.CUIntLeast8T uintleast16: t.CTypedef = t.CUIntLeast16T uintleast32: t.CTypedef = t.CUIntLeast32T uintleast64: t.CTypedef = t.CUIntLeast64T + +# C 基础类型名裸名别名(裸名家族,不随 import 注入;编译器最后匹配本文件兜底解析) +# 目标 x86_64-pc-windows-gnu(Windows/mingw-w64,LLP64): +# uchar = 8 位无符号(t.CUnsignedChar,固定 Size=8;C 的 unsigned char) +# short = 16 位有符号(t.CShort,固定 Size=16) +# ushort = 16 位无符号(t.CUnsignedShort,固定 Size=16) +# uint = u32,32 位无符号(等价 uint32/u32,底层 t.CUnsignedInt Size=32) +# long = 32 位有符号(t.CLong,Size 由 t.configure_platform 依 triple 置 32) +# ulong = 32 位无符号(t.CUnsignedLong,Size 由 t.configure_platform 依 triple 置 32) +# longlong = 64 位有符号(t.CLongLong,固定 Size=64) +# ulonglong = 64 位无符号(t.CUnsignedLongLong,固定 Size=64) +uchar: t.CTypedef = t.CUnsignedChar +short: t.CTypedef = t.CShort +ushort: t.CTypedef = t.CUnsignedShort +uint: t.CTypedef = t.CUnsignedInt +long: t.CTypedef = t.CLong +ulong: t.CTypedef = t.CUnsignedLong +longlong: t.CTypedef = t.CLongLong +ulonglong: t.CTypedef = t.CUnsignedLongLong diff --git a/coro.vp b/coro.vp index c34b2d4..9aaadd8 100644 --- a/coro.vp +++ b/coro.vp @@ -3,33 +3,32 @@ from stdint import * import stdlib -@t.NoVTable -class Coroutine: +novirtual class Coroutine: """协程帧句柄(M1:__ptr__ 持有 create_() 返回的帧指针)。 纯句柄语义:从不实例化/多态分派,编译器全拦截 coro.* 调用; 用户代码句柄统一用 t.CPtr。""" - __ptr__: t.CPtr + __ptr__: rawptr -def coro_resume(c: Coroutine) -> t.CInt: +def coro_resume(c: Coroutine) -> int: # M1 占位:实际由编译器将 coro.coro_run 内联翻译为 resume_ 循环, # 本函数不会被真正调用(仅保证模块可编译)。 return 0 -def coro_result(c: Coroutine) -> t.CInt: +def coro_result(c: Coroutine) -> int: # M1 占位:coro_run 内联翻译直接从帧 ret 槽取结果。 return 0 -def coro_run(c: Coroutine) -> t.CInt: +def coro_run(c: Coroutine) -> int: # M1 占位实现:编译器在调用点对 coro.coro_run 做内联翻译(resume 循环)。 - s: t.CInt = 0 + s: int = 0 while s == 0: s = coro_resume(c) return coro_result(c) -def coro_sleep(ms: t.CInt) -> t.CInt: +def coro_sleep(ms: int) -> int: # M3 占位:编译器将 await coro_sleep(ms) 内联翻译为帧 wake 槽挂起, # 本函数不会被真正调用(仅保证模块可编译)。 return 0 @@ -39,15 +38,15 @@ def coro_destroy(c: Coroutine): # M3 占位:编译器将 coro.coro_destroy(帧) 内联翻译为 free。 return -def coro_exception(c: Coroutine) -> t.CInt: +def coro_exception(c: Coroutine) -> int: # M4 占位:编译器将 coro.coro_exception(帧) 内联翻译为帧 exc 槽读取。 return 0 -def coro_gather(a: Coroutine) -> t.CInt: +def coro_gather(a: Coroutine) -> int: # M4 占位:编译器将 coro.coro_gather(帧...) 内联翻译为并发推进循环。 return 0 def coro_exception_msg(c: Coroutine) -> t.CPtr: # M7 占位:编译器将 coro.coro_exception_msg(帧) 内联翻译为帧 msg 槽读取。 # 注意:TPV(Viper)不支持裸 null,用 t.CPtr(0) 构造空指针(两编译器兼容)。 - return t.CPtr(0) + return None diff --git a/event.vp b/event.vp index 103d51b..85fe1be 100644 --- a/event.vp +++ b/event.vp @@ -4,7 +4,6 @@ from w32.win32base import * from w32.win32sync import CreateEventA, SetEvent, ResetEvent, WaitForSingleObject -@t.Object class Event: """Windows Event-based event object, supports manual-reset and auto-reset modes. diff --git a/fltk/__init__.vp b/fltk/__init__.vp index c521201..776c60a 100644 --- a/fltk/__init__.vp +++ b/fltk/__init__.vp @@ -56,8 +56,7 @@ from fltk._cfl_theme import * # ============================================================ # Fl — FLTK 全局静态类(事件循环 / 事件 / 颜色) # ============================================================ -@t.NoVTable -class Fl: +novirtual class Fl: """FLTK 全局函数集合(静态方法)""" @staticmethod @@ -290,8 +289,7 @@ class Fl: # ============================================================ # Fl_Widget — 控件基类包装 # ============================================================ -@t.NoVTable -class Fl_Widget: +novirtual class Fl_Widget: """FLTK 控件基类(不透明指针包装)""" _ptr: Fl_WidgetPtr @@ -412,8 +410,7 @@ class Fl_Widget: # ============================================================ # Fl_Window — 窗口包装 # ============================================================ -@t.NoVTable -class Fl_Window(Fl_Widget): +novirtual class Fl_Window(Fl_Widget): """FLTK 窗口""" def __init__(self, w: int, h: int, title: str = ""): @@ -471,8 +468,7 @@ class Fl_Window(Fl_Widget): # ============================================================ # Fl_Box — 静态文本/装饰框 # ============================================================ -@t.NoVTable -class Fl_Box(Fl_Widget): +novirtual class Fl_Box(Fl_Widget): """FLTK 文本框/装饰框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -482,8 +478,7 @@ class Fl_Box(Fl_Widget): # ============================================================ # Fl_Button — 按钮包装 # ============================================================ -@t.NoVTable -class Fl_Button(Fl_Widget): +novirtual class Fl_Button(Fl_Widget): """FLTK 按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -514,8 +509,7 @@ class Fl_Button(Fl_Widget): return Fl_Button_down_box(self._ptr) -@t.NoVTable -class Fl_Check_Button(Fl_Button): +novirtual class Fl_Check_Button(Fl_Button): """FLTK 复选框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -528,8 +522,7 @@ class Fl_Check_Button(Fl_Button): Fl_Check_Button_set_checked(self._ptr, checked) -@t.NoVTable -class Fl_Radio_Button(Fl_Button): +novirtual class Fl_Radio_Button(Fl_Button): """FLTK 单选按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -542,24 +535,21 @@ class Fl_Radio_Button(Fl_Button): Fl_Radio_Button_toggle(self._ptr, v) -@t.NoVTable -class Fl_Repeat_Button(Fl_Button): +novirtual class Fl_Repeat_Button(Fl_Button): """FLTK 重复触发按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Repeat_Button_new(x, y, w, h, label) -@t.NoVTable -class Fl_Return_Button(Fl_Button): +novirtual class Fl_Return_Button(Fl_Button): """FLTK 回车按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Return_Button_new(x, y, w, h, label) -@t.NoVTable -class Fl_Light_Button(Fl_Button): +novirtual class Fl_Light_Button(Fl_Button): """FLTK 指示灯按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -575,8 +565,7 @@ class Fl_Light_Button(Fl_Button): # ============================================================ # Fl_Input / Fl_Output — 文本输入输出 # ============================================================ -@t.NoVTable -class Fl_Input(Fl_Widget): +novirtual class Fl_Input(Fl_Widget): """FLTK 单行文本输入框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -601,8 +590,7 @@ class Fl_Input(Fl_Widget): return Fl_Input_readonly(self._ptr) -@t.NoVTable -class Fl_Output(Fl_Widget): +novirtual class Fl_Output(Fl_Widget): """FLTK 单行文本输出框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -615,14 +603,12 @@ class Fl_Output(Fl_Widget): return Fl_Output_set_value(self._ptr, text) -@t.NoVTable -class Fl_Int_Input(Fl_Input): +novirtual class Fl_Int_Input(Fl_Input): def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Int_Input_new(x, y, w, h, label) -@t.NoVTable -class Fl_Float_Input(Fl_Input): +novirtual class Fl_Float_Input(Fl_Input): def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Float_Input_new(x, y, w, h, label) @@ -630,8 +616,7 @@ class Fl_Float_Input(Fl_Input): # ============================================================ # Fl_Text_Buffer / Fl_Text_Display — 多行文本 # ============================================================ -@t.NoVTable -class Fl_Text_Buffer: +novirtual class Fl_Text_Buffer: """FLTK 文本缓冲""" _ptr: Fl_Text_BufferPtr @@ -667,8 +652,7 @@ class Fl_Text_Buffer: Fl_Text_Buffer_delete(self._ptr) -@t.NoVTable -class Fl_Text_Display(Fl_Widget): +novirtual class Fl_Text_Display(Fl_Widget): """FLTK 多行文本显示""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -693,8 +677,7 @@ class Fl_Text_Display(Fl_Widget): # ============================================================ # Fl_Group — 容器包装 # ============================================================ -@t.NoVTable -class Fl_Group(Fl_Widget): +novirtual class Fl_Group(Fl_Widget): """FLTK 控件组""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -725,8 +708,7 @@ class Fl_Group(Fl_Widget): Fl_Group_resizable(self._ptr, wid) -@t.NoVTable -class Fl_Scroll(Fl_Group): +novirtual class Fl_Scroll(Fl_Group): """FLTK 滚动容器""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -748,8 +730,7 @@ class Fl_Scroll(Fl_Group): return Fl_Scroll_yposition(self._ptr) -@t.NoVTable -class Fl_Tabs(Fl_Group): +novirtual class Fl_Tabs(Fl_Group): """FLTK 选项卡容器""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -765,8 +746,7 @@ class Fl_Tabs(Fl_Group): # ============================================================ # Fl_Slider / Fl_Value_Input / Fl_Value_Output — 数值控件 # ============================================================ -@t.NoVTable -class Fl_Slider(Fl_Widget): +novirtual class Fl_Slider(Fl_Widget): """FLTK 滑动条""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -800,8 +780,7 @@ class Fl_Slider(Fl_Widget): Fl_Slider_set_bounds(self._ptr, a, b) -@t.NoVTable -class Fl_Value_Input(Fl_Widget): +novirtual class Fl_Value_Input(Fl_Widget): """FLTK 数值输入框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -817,8 +796,7 @@ class Fl_Value_Input(Fl_Widget): Fl_Value_Input_set_bounds(self._ptr, a, b) -@t.NoVTable -class Fl_Value_Output(Fl_Widget): +novirtual class Fl_Value_Output(Fl_Widget): """FLTK 数值输出框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -831,8 +809,7 @@ class Fl_Value_Output(Fl_Widget): Fl_Value_Output_set_value(self._ptr, v) -@t.NoVTable -class Fl_Progress(Fl_Widget): +novirtual class Fl_Progress(Fl_Widget): """FLTK 进度条""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -854,8 +831,7 @@ class Fl_Progress(Fl_Widget): # ============================================================ # Fl_Choice — 下拉选择 # ============================================================ -@t.NoVTable -class Fl_Choice(Fl_Widget): +novirtual class Fl_Choice(Fl_Widget): """FLTK 下拉选择框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -877,8 +853,7 @@ class Fl_Choice(Fl_Widget): # ============================================================ # Fl_Menu_Bar — 菜单栏 # ============================================================ -@t.NoVTable -class Fl_Menu_Bar(Fl_Widget): +novirtual class Fl_Menu_Bar(Fl_Widget): """FLTK 菜单栏 add 走 cfltk 完整 6 参签名(name/shortcut/回调/数据/flags), @@ -898,8 +873,7 @@ class Fl_Menu_Bar(Fl_Widget): # ============================================================ # Fl_Native_File_Chooser — 系统文件对话框 # ============================================================ -@t.NoVTable -class Fl_Native_File_Chooser: +novirtual class Fl_Native_File_Chooser: """FLTK 原生文件选择对话框 构造需传对话框类型常量(如 Fl_Native_File_Chooser_BROWSE_FILE / @@ -970,40 +944,35 @@ def fltk_init(): # ============================================================ # 补充按钮类 # ============================================================ -@t.NoVTable -class Fl_Toggle_Button(Fl_Button): +novirtual class Fl_Toggle_Button(Fl_Button): """FLTK 切换按钮(按下保持)""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Toggle_Button_new(x, y, w, h, label) -@t.NoVTable -class Fl_Round_Button(Fl_Button): +novirtual class Fl_Round_Button(Fl_Button): """FLTK 圆形按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Round_Button_new(x, y, w, h, label) -@t.NoVTable -class Fl_Radio_Round_Button(Fl_Button): +novirtual class Fl_Radio_Round_Button(Fl_Button): """FLTK 圆形单选按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Radio_Round_Button_new(x, y, w, h, label) -@t.NoVTable -class Fl_Radio_Light_Button(Fl_Button): +novirtual class Fl_Radio_Light_Button(Fl_Button): """FLTK 指示灯单选按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Radio_Light_Button_new(x, y, w, h, label) -@t.NoVTable -class Fl_Shortcut_Button(Fl_Button): +novirtual class Fl_Shortcut_Button(Fl_Button): """FLTK 快捷键录入按钮""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1013,32 +982,28 @@ class Fl_Shortcut_Button(Fl_Button): # ============================================================ # 补充输入类 # ============================================================ -@t.NoVTable -class Fl_Multiline_Input(Fl_Input): +novirtual class Fl_Multiline_Input(Fl_Input): """FLTK 多行文本输入框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Multiline_Input_new(x, y, w, h, label) -@t.NoVTable -class Fl_Secret_Input(Fl_Input): +novirtual class Fl_Secret_Input(Fl_Input): """FLTK 密码输入框(显示为 *)""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Secret_Input_new(x, y, w, h, label) -@t.NoVTable -class Fl_File_Input(Fl_Input): +novirtual class Fl_File_Input(Fl_Input): """FLTK 文件路径输入框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_File_Input_new(x, y, w, h, label) -@t.NoVTable -class Fl_Multiline_Output(Fl_Output): +novirtual class Fl_Multiline_Output(Fl_Output): """FLTK 多行文本输出框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1048,16 +1013,14 @@ class Fl_Multiline_Output(Fl_Output): # ============================================================ # Fl_Nice_Slider / Fl_Spinner / Fl_Clock # ============================================================ -@t.NoVTable -class Fl_Nice_Slider(Fl_Slider): +novirtual class Fl_Nice_Slider(Fl_Slider): """FLTK 美观滑块""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Nice_Slider_new(x, y, w, h, label) -@t.NoVTable -class Fl_Spinner(Fl_Widget): +novirtual class Fl_Spinner(Fl_Widget): """FLTK 数字微调框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1088,8 +1051,7 @@ class Fl_Spinner(Fl_Widget): Fl_Spinner_set_step(self._ptr, v) -@t.NoVTable -class Fl_Clock(Fl_Widget): +novirtual class Fl_Clock(Fl_Widget): """FLTK 时钟(模拟表盘)""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1099,24 +1061,21 @@ class Fl_Clock(Fl_Widget): # ============================================================ # 补充容器类 # ============================================================ -@t.NoVTable -class Fl_Pack(Fl_Group): +novirtual class Fl_Pack(Fl_Group): """FLTK 自动布局容器(子控件按序排列)""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Pack_new(x, y, w, h, label) -@t.NoVTable -class Fl_Tile(Fl_Group): +novirtual class Fl_Tile(Fl_Group): """FLTK 可拖动分隔容器""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): self._ptr = Fl_Tile_new(x, y, w, h, label) -@t.NoVTable -class Fl_Flex(Fl_Group): +novirtual class Fl_Flex(Fl_Group): """FLTK 弹性布局容器""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1126,8 +1085,7 @@ class Fl_Flex(Fl_Group): # ============================================================ # Fl_Menu_Button — 弹出菜单按钮 # ============================================================ -@t.NoVTable -class Fl_Menu_Button(Fl_Widget): +novirtual class Fl_Menu_Button(Fl_Widget): """FLTK 弹出菜单按钮(右键/长按弹出)""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1140,8 +1098,7 @@ class Fl_Menu_Button(Fl_Widget): # ============================================================ # Fl_Browser — 列表浏览 # ============================================================ -@t.NoVTable -class Fl_Browser(Fl_Widget): +novirtual class Fl_Browser(Fl_Widget): """FLTK 列表浏览框""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1164,8 +1121,7 @@ class Fl_Browser(Fl_Widget): # ============================================================ # Fl_Tree — 树形控件 # ============================================================ -@t.NoVTable -class Fl_Tree(Fl_Widget): +novirtual class Fl_Tree(Fl_Widget): """FLTK 树形控件""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1182,8 +1138,7 @@ class Fl_Tree(Fl_Widget): # ============================================================ # Fl_Text_Editor / Fl_Terminal # ============================================================ -@t.NoVTable -class Fl_Text_Editor(Fl_Text_Display): +novirtual class Fl_Text_Editor(Fl_Text_Display): """FLTK 文本编辑器""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1198,8 +1153,7 @@ class Fl_Text_Editor(Fl_Text_Display): Fl_Text_Editor_overstrike(self._ptr, text) -@t.NoVTable -class Fl_Terminal(Fl_Widget): +novirtual class Fl_Terminal(Fl_Widget): """FLTK 终端模拟控件(ANSI 转义支持)""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1212,8 +1166,7 @@ class Fl_Terminal(Fl_Widget): # ============================================================ # Fl_File_Chooser — 文件选择对话框 # ============================================================ -@t.NoVTable -class Fl_File_Chooser: +novirtual class Fl_File_Chooser: """FLTK 文件选择对话框(cfltk 封装,非原生) new(directory, pattern, type, title);type 用 Fl_File_Chooser_* 常量 @@ -1277,8 +1230,7 @@ class Fl_File_Chooser: # ============================================================ # Fl_Help_Dialog — HTML 帮助对话框 # ============================================================ -@t.NoVTable -class Fl_Help_Dialog: +novirtual class Fl_Help_Dialog: """FLTK HTML 帮助对话框""" _ptr: Fl_Help_DialogPtr @@ -1316,8 +1268,7 @@ class Fl_Help_Dialog: # ============================================================ # Fl_Input_Choice — 输入+下拉组合 # ============================================================ -@t.NoVTable -class Fl_Input_Choice(Fl_Group): +novirtual class Fl_Input_Choice(Fl_Group): """FLTK 文本输入 + 下拉选择组合控件""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1334,8 +1285,7 @@ class Fl_Input_Choice(Fl_Group): # ============================================================ # Fl_Color_Chooser — 颜色选择 # ============================================================ -@t.NoVTable -class Fl_Color_Chooser(Fl_Group): +novirtual class Fl_Color_Chooser(Fl_Group): """FLTK 颜色选择器""" def __init__(self, x: int, y: int, w: int, h: int, label: str = ""): @@ -1352,8 +1302,7 @@ class Fl_Color_Chooser(Fl_Group): # ============================================================ # 图片类 # ============================================================ -@t.NoVTable -class Fl_PNG_Image: +novirtual class Fl_PNG_Image: """FLTK PNG 图片(从文件加载)""" _ptr: Fl_PNG_ImagePtr @@ -1362,8 +1311,7 @@ class Fl_PNG_Image: self._ptr = Fl_PNG_Image_new(filename) -@t.NoVTable -class Fl_JPEG_Image: +novirtual class Fl_JPEG_Image: """FLTK JPEG 图片""" _ptr: Fl_JPEG_ImagePtr @@ -1372,8 +1320,7 @@ class Fl_JPEG_Image: self._ptr = Fl_JPEG_Image_new(filename) -@t.NoVTable -class Fl_GIF_Image: +novirtual class Fl_GIF_Image: """FLTK GIF 图片""" _ptr: Fl_GIF_ImagePtr diff --git a/fltk/_cfl_browser.vp b/fltk/_cfl_browser.vp index 82cfdd3..d31e6b0 100644 --- a/fltk/_cfl_browser.vp +++ b/fltk/_cfl_browser.vp @@ -120,10 +120,10 @@ extern def Fl_Browser_topline(self: Fl_BrowserPtr, line: int) extern def Fl_Browser_is_topline(self: Fl_BrowserPtr) -> int extern def Fl_Browser_bottomline(self: Fl_BrowserPtr, line: int) extern def Fl_Browser_middleline(self: Fl_BrowserPtr, line: int) -extern def Fl_Browser_format_char(self: Fl_BrowserPtr) -> t.CChar -extern def Fl_Browser_set_format_char(self: Fl_BrowserPtr, c: t.CChar) -extern def Fl_Browser_column_char(self: Fl_BrowserPtr) -> t.CChar -extern def Fl_Browser_set_column_char(self: Fl_BrowserPtr, c: t.CChar) +extern def Fl_Browser_format_char(self: Fl_BrowserPtr) -> char +extern def Fl_Browser_set_format_char(self: Fl_BrowserPtr, c: char) +extern def Fl_Browser_column_char(self: Fl_BrowserPtr) -> char +extern def Fl_Browser_set_column_char(self: Fl_BrowserPtr, c: char) extern def Fl_Browser_column_widths(self: Fl_BrowserPtr) -> bytes extern def Fl_Browser_set_column_widths(self: Fl_BrowserPtr, arr: bytes) extern def Fl_Browser_displayed(self: Fl_BrowserPtr, line: int) -> int @@ -254,10 +254,10 @@ extern def Fl_Hold_Browser_topline(self: Fl_Hold_BrowserPtr, line: int) extern def Fl_Hold_Browser_is_topline(self: Fl_Hold_BrowserPtr) -> int extern def Fl_Hold_Browser_bottomline(self: Fl_Hold_BrowserPtr, line: int) extern def Fl_Hold_Browser_middleline(self: Fl_Hold_BrowserPtr, line: int) -extern def Fl_Hold_Browser_format_char(self: Fl_Hold_BrowserPtr) -> t.CChar -extern def Fl_Hold_Browser_set_format_char(self: Fl_Hold_BrowserPtr, c: t.CChar) -extern def Fl_Hold_Browser_column_char(self: Fl_Hold_BrowserPtr) -> t.CChar -extern def Fl_Hold_Browser_set_column_char(self: Fl_Hold_BrowserPtr, c: t.CChar) +extern def Fl_Hold_Browser_format_char(self: Fl_Hold_BrowserPtr) -> char +extern def Fl_Hold_Browser_set_format_char(self: Fl_Hold_BrowserPtr, c: char) +extern def Fl_Hold_Browser_column_char(self: Fl_Hold_BrowserPtr) -> char +extern def Fl_Hold_Browser_set_column_char(self: Fl_Hold_BrowserPtr, c: char) extern def Fl_Hold_Browser_column_widths(self: Fl_Hold_BrowserPtr) -> bytes extern def Fl_Hold_Browser_set_column_widths(self: Fl_Hold_BrowserPtr, arr: bytes) extern def Fl_Hold_Browser_displayed(self: Fl_Hold_BrowserPtr, line: int) -> int @@ -388,10 +388,10 @@ extern def Fl_Select_Browser_topline(self: Fl_Select_BrowserPtr, line: int) extern def Fl_Select_Browser_is_topline(self: Fl_Select_BrowserPtr) -> int extern def Fl_Select_Browser_bottomline(self: Fl_Select_BrowserPtr, line: int) extern def Fl_Select_Browser_middleline(self: Fl_Select_BrowserPtr, line: int) -extern def Fl_Select_Browser_format_char(self: Fl_Select_BrowserPtr) -> t.CChar -extern def Fl_Select_Browser_set_format_char(self: Fl_Select_BrowserPtr, c: t.CChar) -extern def Fl_Select_Browser_column_char(self: Fl_Select_BrowserPtr) -> t.CChar -extern def Fl_Select_Browser_set_column_char(self: Fl_Select_BrowserPtr, c: t.CChar) +extern def Fl_Select_Browser_format_char(self: Fl_Select_BrowserPtr) -> char +extern def Fl_Select_Browser_set_format_char(self: Fl_Select_BrowserPtr, c: char) +extern def Fl_Select_Browser_column_char(self: Fl_Select_BrowserPtr) -> char +extern def Fl_Select_Browser_set_column_char(self: Fl_Select_BrowserPtr, c: char) extern def Fl_Select_Browser_column_widths(self: Fl_Select_BrowserPtr) -> bytes extern def Fl_Select_Browser_set_column_widths(self: Fl_Select_BrowserPtr, arr: bytes) extern def Fl_Select_Browser_displayed(self: Fl_Select_BrowserPtr, line: int) -> int @@ -522,10 +522,10 @@ extern def Fl_Multi_Browser_topline(self: Fl_Multi_BrowserPtr, line: int) extern def Fl_Multi_Browser_is_topline(self: Fl_Multi_BrowserPtr) -> int extern def Fl_Multi_Browser_bottomline(self: Fl_Multi_BrowserPtr, line: int) extern def Fl_Multi_Browser_middleline(self: Fl_Multi_BrowserPtr, line: int) -extern def Fl_Multi_Browser_format_char(self: Fl_Multi_BrowserPtr) -> t.CChar -extern def Fl_Multi_Browser_set_format_char(self: Fl_Multi_BrowserPtr, c: t.CChar) -extern def Fl_Multi_Browser_column_char(self: Fl_Multi_BrowserPtr) -> t.CChar -extern def Fl_Multi_Browser_set_column_char(self: Fl_Multi_BrowserPtr, c: t.CChar) +extern def Fl_Multi_Browser_format_char(self: Fl_Multi_BrowserPtr) -> char +extern def Fl_Multi_Browser_set_format_char(self: Fl_Multi_BrowserPtr, c: char) +extern def Fl_Multi_Browser_column_char(self: Fl_Multi_BrowserPtr) -> char +extern def Fl_Multi_Browser_set_column_char(self: Fl_Multi_BrowserPtr, c: char) extern def Fl_Multi_Browser_column_widths(self: Fl_Multi_BrowserPtr) -> bytes extern def Fl_Multi_Browser_set_column_widths(self: Fl_Multi_BrowserPtr, arr: bytes) extern def Fl_Multi_Browser_displayed(self: Fl_Multi_BrowserPtr, line: int) -> int @@ -656,10 +656,10 @@ extern def Fl_File_Browser_topline(self: Fl_File_BrowserPtr, line: int) extern def Fl_File_Browser_is_topline(self: Fl_File_BrowserPtr) -> int extern def Fl_File_Browser_bottomline(self: Fl_File_BrowserPtr, line: int) extern def Fl_File_Browser_middleline(self: Fl_File_BrowserPtr, line: int) -extern def Fl_File_Browser_format_char(self: Fl_File_BrowserPtr) -> t.CChar -extern def Fl_File_Browser_set_format_char(self: Fl_File_BrowserPtr, c: t.CChar) -extern def Fl_File_Browser_column_char(self: Fl_File_BrowserPtr) -> t.CChar -extern def Fl_File_Browser_set_column_char(self: Fl_File_BrowserPtr, c: t.CChar) +extern def Fl_File_Browser_format_char(self: Fl_File_BrowserPtr) -> char +extern def Fl_File_Browser_set_format_char(self: Fl_File_BrowserPtr, c: char) +extern def Fl_File_Browser_column_char(self: Fl_File_BrowserPtr) -> char +extern def Fl_File_Browser_set_column_char(self: Fl_File_BrowserPtr, c: char) extern def Fl_File_Browser_column_widths(self: Fl_File_BrowserPtr) -> bytes extern def Fl_File_Browser_set_column_widths(self: Fl_File_BrowserPtr, arr: bytes) extern def Fl_File_Browser_displayed(self: Fl_File_BrowserPtr, line: int) -> int diff --git a/fltk/_cfl_draw.vp b/fltk/_cfl_draw.vp index cb2f6bc..9b8f8ce 100644 --- a/fltk/_cfl_draw.vp +++ b/fltk/_cfl_draw.vp @@ -97,7 +97,7 @@ extern def Fl_frame2(s: str, x: int, y: int, w: int, h: int) extern def Fl_draw_box(box_type: int, x: int, y: int, w: int, h: int, a5: t.CUInt32T) extern def Fl_draw_image(buf: bytes, X: int, Y: int, W: int, H: int, D: int, L: int) extern def Fl_draw_image_mono(buf: bytes, X: int, Y: int, W: int, H: int, D: int, L: int) -extern def Fl_can_do_alpha_blending() -> t.CChar +extern def Fl_can_do_alpha_blending() -> char extern def Fl_read_image(p: bytes, X: int, Y: int, W: int, H: int, alpha: int) -> bytes extern def Fl_capture_window_part(win: bytes, x: int, y: int, w: int, h: int) -> bytes extern def Fl_draw_pixmap(data: bytes, x: int, y: int, bg: int) -> int diff --git a/fltk/_cfl_input.vp b/fltk/_cfl_input.vp index 02d4c7a..c903110 100644 --- a/fltk/_cfl_input.vp +++ b/fltk/_cfl_input.vp @@ -107,7 +107,7 @@ extern def Fl_Input_set_mark(self: Fl_InputPtr, m: int) -> int extern def Fl_Input_mark(self: Fl_InputPtr) -> int extern def Fl_Input_replace(self: Fl_InputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Input_insert(self: Fl_InputPtr, t: str, l: int) -> int -extern def Fl_Input_append(self: Fl_InputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Input_append(self: Fl_InputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Input_copy(self: Fl_InputPtr, clipboard: int) -> int extern def Fl_Input_undo(self: Fl_InputPtr) -> int extern def Fl_Input_copy_cuts(self: Fl_InputPtr) -> int @@ -224,7 +224,7 @@ extern def Fl_Int_Input_set_mark(self: Fl_Int_InputPtr, m: int) -> int extern def Fl_Int_Input_mark(self: Fl_Int_InputPtr) -> int extern def Fl_Int_Input_replace(self: Fl_Int_InputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Int_Input_insert(self: Fl_Int_InputPtr, t: str, l: int) -> int -extern def Fl_Int_Input_append(self: Fl_Int_InputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Int_Input_append(self: Fl_Int_InputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Int_Input_copy(self: Fl_Int_InputPtr, clipboard: int) -> int extern def Fl_Int_Input_undo(self: Fl_Int_InputPtr) -> int extern def Fl_Int_Input_copy_cuts(self: Fl_Int_InputPtr) -> int @@ -341,7 +341,7 @@ extern def Fl_Float_Input_set_mark(self: Fl_Float_InputPtr, m: int) -> int extern def Fl_Float_Input_mark(self: Fl_Float_InputPtr) -> int extern def Fl_Float_Input_replace(self: Fl_Float_InputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Float_Input_insert(self: Fl_Float_InputPtr, t: str, l: int) -> int -extern def Fl_Float_Input_append(self: Fl_Float_InputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Float_Input_append(self: Fl_Float_InputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Float_Input_copy(self: Fl_Float_InputPtr, clipboard: int) -> int extern def Fl_Float_Input_undo(self: Fl_Float_InputPtr) -> int extern def Fl_Float_Input_copy_cuts(self: Fl_Float_InputPtr) -> int @@ -458,7 +458,7 @@ extern def Fl_Multiline_Input_set_mark(self: Fl_Multiline_InputPtr, m: int) -> i extern def Fl_Multiline_Input_mark(self: Fl_Multiline_InputPtr) -> int extern def Fl_Multiline_Input_replace(self: Fl_Multiline_InputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Multiline_Input_insert(self: Fl_Multiline_InputPtr, t: str, l: int) -> int -extern def Fl_Multiline_Input_append(self: Fl_Multiline_InputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Multiline_Input_append(self: Fl_Multiline_InputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Multiline_Input_copy(self: Fl_Multiline_InputPtr, clipboard: int) -> int extern def Fl_Multiline_Input_undo(self: Fl_Multiline_InputPtr) -> int extern def Fl_Multiline_Input_copy_cuts(self: Fl_Multiline_InputPtr) -> int @@ -575,7 +575,7 @@ extern def Fl_Secret_Input_set_mark(self: Fl_Secret_InputPtr, m: int) -> int extern def Fl_Secret_Input_mark(self: Fl_Secret_InputPtr) -> int extern def Fl_Secret_Input_replace(self: Fl_Secret_InputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Secret_Input_insert(self: Fl_Secret_InputPtr, t: str, l: int) -> int -extern def Fl_Secret_Input_append(self: Fl_Secret_InputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Secret_Input_append(self: Fl_Secret_InputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Secret_Input_copy(self: Fl_Secret_InputPtr, clipboard: int) -> int extern def Fl_Secret_Input_undo(self: Fl_Secret_InputPtr) -> int extern def Fl_Secret_Input_copy_cuts(self: Fl_Secret_InputPtr) -> int @@ -692,7 +692,7 @@ extern def Fl_File_Input_set_mark(self: Fl_File_InputPtr, m: int) -> int extern def Fl_File_Input_mark(self: Fl_File_InputPtr) -> int extern def Fl_File_Input_replace(self: Fl_File_InputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_File_Input_insert(self: Fl_File_InputPtr, t: str, l: int) -> int -extern def Fl_File_Input_append(self: Fl_File_InputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_File_Input_append(self: Fl_File_InputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_File_Input_copy(self: Fl_File_InputPtr, clipboard: int) -> int extern def Fl_File_Input_undo(self: Fl_File_InputPtr) -> int extern def Fl_File_Input_copy_cuts(self: Fl_File_InputPtr) -> int @@ -809,7 +809,7 @@ extern def Fl_Output_set_mark(self: Fl_OutputPtr, m: int) -> int extern def Fl_Output_mark(self: Fl_OutputPtr) -> int extern def Fl_Output_replace(self: Fl_OutputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Output_insert(self: Fl_OutputPtr, t: str, l: int) -> int -extern def Fl_Output_append(self: Fl_OutputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Output_append(self: Fl_OutputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Output_copy(self: Fl_OutputPtr, clipboard: int) -> int extern def Fl_Output_undo(self: Fl_OutputPtr) -> int extern def Fl_Output_copy_cuts(self: Fl_OutputPtr) -> int @@ -926,7 +926,7 @@ extern def Fl_Multiline_Output_set_mark(self: Fl_Multiline_OutputPtr, m: int) -> extern def Fl_Multiline_Output_mark(self: Fl_Multiline_OutputPtr) -> int extern def Fl_Multiline_Output_replace(self: Fl_Multiline_OutputPtr, b: int, e: int, text: str, ilen: int) -> int extern def Fl_Multiline_Output_insert(self: Fl_Multiline_OutputPtr, t: str, l: int) -> int -extern def Fl_Multiline_Output_append(self: Fl_Multiline_OutputPtr, t: str, l: int, keep_selection: t.CChar) -> int +extern def Fl_Multiline_Output_append(self: Fl_Multiline_OutputPtr, t: str, l: int, keep_selection: char) -> int extern def Fl_Multiline_Output_copy(self: Fl_Multiline_OutputPtr, clipboard: int) -> int extern def Fl_Multiline_Output_undo(self: Fl_Multiline_OutputPtr) -> int extern def Fl_Multiline_Output_copy_cuts(self: Fl_Multiline_OutputPtr) -> int diff --git a/fltk/_cfl_prefs.vp b/fltk/_cfl_prefs.vp index eb68ccf..7112436 100644 --- a/fltk/_cfl_prefs.vp +++ b/fltk/_cfl_prefs.vp @@ -11,7 +11,7 @@ from fltk._types import * extern def Fl_Preferences_set_file_access(flags: t.CUInt32T) extern def Fl_Preferences_file_access() -> t.CUInt32T -extern def Fl_Preferences_remove(id_: bytes) -> t.CChar +extern def Fl_Preferences_remove(id_: bytes) -> char extern def Fl_Preferences_new(root: int, vendor: str, application: str) -> Fl_PreferencesPtr extern def Fl_Preferences_from_path(path: str, vendor: str, application: str) -> Fl_PreferencesPtr extern def Fl_Preferences_from_parent_group(parent: Fl_PreferencesPtr, group: str) -> Fl_PreferencesPtr @@ -20,32 +20,32 @@ extern def Fl_Preferences_copy(a0: Fl_PreferencesPtr) -> Fl_PreferencesPtr extern def Fl_Preferences_delete(a0: Fl_PreferencesPtr) extern def Fl_Preferences_from_id(id: bytes) -> Fl_PreferencesPtr extern def Fl_Preferences_filename(prefs: Fl_PreferencesPtr, buffer: str, buffer_size: t.CUInt32T) -> int -extern def Fl_Preferences_get_userdata_path(prefs: Fl_PreferencesPtr, path: str, pathlen: int) -> t.CChar +extern def Fl_Preferences_get_userdata_path(prefs: Fl_PreferencesPtr, path: str, pathlen: int) -> char extern def Fl_Preferences_id(prefs: Fl_PreferencesPtr) -> bytes extern def Fl_Preferences_name(prefs: Fl_PreferencesPtr) -> str extern def Fl_Preferences_path(prefs: Fl_PreferencesPtr) -> str extern def Fl_Preferences_groups(prefs: Fl_PreferencesPtr) -> int extern def Fl_Preferences_group(prefs: Fl_PreferencesPtr, num_group: int) -> str -extern def Fl_Preferences_group_exists(prefs: Fl_PreferencesPtr, key: str) -> t.CChar -extern def Fl_Preferences_delete_group(prefs: Fl_PreferencesPtr, group: str) -> t.CChar -extern def Fl_Preferences_delete_all_groups(prefs: Fl_PreferencesPtr) -> t.CChar +extern def Fl_Preferences_group_exists(prefs: Fl_PreferencesPtr, key: str) -> char +extern def Fl_Preferences_delete_group(prefs: Fl_PreferencesPtr, group: str) -> char +extern def Fl_Preferences_delete_all_groups(prefs: Fl_PreferencesPtr) -> char extern def Fl_Preferences_entries(prefs: Fl_PreferencesPtr) -> int extern def Fl_Preferences_entry(prefs: Fl_PreferencesPtr, index: int) -> str -extern def Fl_Preferences_entry_exists(prefs: Fl_PreferencesPtr, key: str) -> t.CChar -extern def Fl_Preferences_delete_entry(prefs: Fl_PreferencesPtr, entry: str) -> t.CChar -extern def Fl_Preferences_delete_all_entries(prefs: Fl_PreferencesPtr) -> t.CChar -extern def Fl_Preferences_clear(prefs: Fl_PreferencesPtr) -> t.CChar -extern def Fl_Preferences_seti(prefs: Fl_PreferencesPtr, entry: str, value: int) -> t.CChar -extern def Fl_Preferences_setf(prefs: Fl_PreferencesPtr, entry: str, value: t.CFloat) -> t.CChar -extern def Fl_Preferences_setfp(prefs: Fl_PreferencesPtr, entry: str, value: t.CFloat, precision: int) -> t.CChar -extern def Fl_Preferences_setd(prefs: Fl_PreferencesPtr, entry: str, value: t.CDouble) -> t.CChar -extern def Fl_Preferences_setdp(prefs: Fl_PreferencesPtr, entry: str, value: t.CDouble, precision: int) -> t.CChar -extern def Fl_Preferences_sets(prefs: Fl_PreferencesPtr, entry: str, value: str) -> t.CChar -extern def Fl_Preferences_setv(prefs: Fl_PreferencesPtr, entry: str, value: bytes, size: int) -> t.CChar -extern def Fl_Preferences_geti(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: int) -> t.CChar -extern def Fl_Preferences_getf(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: t.CFloat) -> t.CChar -extern def Fl_Preferences_getd(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: t.CDouble) -> t.CChar -extern def Fl_Preferences_gets(prefs: Fl_PreferencesPtr, entry: str, value: str, defaultValue: str, maxSize: int) -> t.CChar -extern def Fl_Preferences_getv(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: bytes, defaultSize: int, maxSize: int) -> t.CChar -extern def Fl_Preferences_getv2(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: bytes, defaultSize: int, size: bytes) -> t.CChar +extern def Fl_Preferences_entry_exists(prefs: Fl_PreferencesPtr, key: str) -> char +extern def Fl_Preferences_delete_entry(prefs: Fl_PreferencesPtr, entry: str) -> char +extern def Fl_Preferences_delete_all_entries(prefs: Fl_PreferencesPtr) -> char +extern def Fl_Preferences_clear(prefs: Fl_PreferencesPtr) -> char +extern def Fl_Preferences_seti(prefs: Fl_PreferencesPtr, entry: str, value: int) -> char +extern def Fl_Preferences_setf(prefs: Fl_PreferencesPtr, entry: str, value: t.CFloat) -> char +extern def Fl_Preferences_setfp(prefs: Fl_PreferencesPtr, entry: str, value: t.CFloat, precision: int) -> char +extern def Fl_Preferences_setd(prefs: Fl_PreferencesPtr, entry: str, value: t.CDouble) -> char +extern def Fl_Preferences_setdp(prefs: Fl_PreferencesPtr, entry: str, value: t.CDouble, precision: int) -> char +extern def Fl_Preferences_sets(prefs: Fl_PreferencesPtr, entry: str, value: str) -> char +extern def Fl_Preferences_setv(prefs: Fl_PreferencesPtr, entry: str, value: bytes, size: int) -> char +extern def Fl_Preferences_geti(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: int) -> char +extern def Fl_Preferences_getf(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: t.CFloat) -> char +extern def Fl_Preferences_getd(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: t.CDouble) -> char +extern def Fl_Preferences_gets(prefs: Fl_PreferencesPtr, entry: str, value: str, defaultValue: str, maxSize: int) -> char +extern def Fl_Preferences_getv(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: bytes, defaultSize: int, maxSize: int) -> char +extern def Fl_Preferences_getv2(prefs: Fl_PreferencesPtr, entry: str, value: bytes, defaultValue: bytes, defaultSize: int, size: bytes) -> char extern def Fl_Preferences_size(prefs: Fl_PreferencesPtr, entry: str) -> int diff --git a/fltk/_cfl_term.vp b/fltk/_cfl_term.vp index 42a763f..4dad868 100644 --- a/fltk/_cfl_term.vp +++ b/fltk/_cfl_term.vp @@ -144,8 +144,8 @@ extern def Fl_Terminal_clear_cur_line(self: Fl_TerminalPtr) extern def Fl_Terminal_clear_line(self: Fl_TerminalPtr, drow: int) extern def Fl_Terminal_clear_sod(self: Fl_TerminalPtr) extern def Fl_Terminal_clear_sol(self: Fl_TerminalPtr) -extern def Fl_Terminal_insert_char(self: Fl_TerminalPtr, c: t.CChar, rep: int) -extern def Fl_Terminal_insert_char_eol(self: Fl_TerminalPtr, c: t.CChar, drow: int, dcol: int, rep: int) +extern def Fl_Terminal_insert_char(self: Fl_TerminalPtr, c: char, rep: int) +extern def Fl_Terminal_insert_char_eol(self: Fl_TerminalPtr, c: char, drow: int, dcol: int, rep: int) extern def Fl_Terminal_insert_rows(self: Fl_TerminalPtr, count: int) extern def Fl_Terminal_delete_chars(self: Fl_TerminalPtr, drow: int, dcol: int, count: int) extern def Fl_Terminal_delete_cur_chars(self: Fl_TerminalPtr, count: int) @@ -171,10 +171,10 @@ extern def Fl_Terminal_margin_top(self: Fl_TerminalPtr) -> int extern def Fl_Terminal_set_margin_top(self: Fl_TerminalPtr, set: int) extern def Fl_Terminal_output_translate(self: Fl_TerminalPtr) -> bytes extern def Fl_Terminal_set_output_translate(self: Fl_TerminalPtr, set: bytes) -> bytes -extern def Fl_Terminal_print_char(self: Fl_TerminalPtr, c: t.CChar) +extern def Fl_Terminal_print_char(self: Fl_TerminalPtr, c: char) extern def Fl_Terminal_print_char_utf8(self: Fl_TerminalPtr, txt: str, len_: int) extern def Fl_Terminal_printf(self: Fl_TerminalPtr, fmt: str, a2: bytes) -> bytes -extern def Fl_Terminal_plot_char(self: Fl_TerminalPtr, c: t.CChar, row: int, col: int) +extern def Fl_Terminal_plot_char(self: Fl_TerminalPtr, c: char, row: int, col: int) extern def Fl_Terminal_plot_char_utf8(self: Fl_TerminalPtr, txt: str, len_: int, row: int, col: int) extern def Fl_Terminal_redraw_rate(self: Fl_TerminalPtr) -> t.CFloat extern def Fl_Terminal_set_redraw_rate(self: Fl_TerminalPtr, set: t.CFloat) @@ -224,7 +224,7 @@ extern def Fl_Terminal_Utf8Char_attr_fgcolor(self: Fl_Terminal_Utf8CharPtr, grp: extern def Fl_Terminal_Utf8Char_attrib(self: Fl_Terminal_Utf8CharPtr) -> bytes extern def Fl_Terminal_Utf8Char_bgcolor(self: Fl_Terminal_Utf8CharPtr) -> bytes extern def Fl_Terminal_Utf8Char_fgcolor(self: Fl_Terminal_Utf8CharPtr) -> bytes -extern def Fl_Terminal_Utf8Char_is_char(self: Fl_Terminal_Utf8CharPtr, c: t.CChar) -> bytes +extern def Fl_Terminal_Utf8Char_is_char(self: Fl_Terminal_Utf8CharPtr, c: char) -> bytes extern def Fl_Terminal_Utf8Char_length(self: Fl_Terminal_Utf8CharPtr) -> bytes extern def Fl_Terminal_Utf8Char_max_utf8(self: Fl_Terminal_Utf8CharPtr) -> int extern def Fl_Terminal_Utf8Char_pwidth(self: Fl_Terminal_Utf8CharPtr) -> t.CDouble diff --git a/fltk/_cfl_text.vp b/fltk/_cfl_text.vp index 6e19f49..66d44d6 100644 --- a/fltk/_cfl_text.vp +++ b/fltk/_cfl_text.vp @@ -508,7 +508,7 @@ extern def Fl_Text_Buffer_insert(self: Fl_Text_BufferPtr, pos: int, text: str) extern def Fl_Text_Buffer_replace(self: Fl_Text_BufferPtr, start: int, end: int, text: str) extern def Fl_Text_Buffer_copy(self: Fl_Text_BufferPtr, fromBuf: Fl_Text_BufferPtr, fromStart: int, fromEnd: int, toPos: int) extern def Fl_Text_Buffer_undo(self: Fl_Text_BufferPtr, cp: bytes) -> int -extern def Fl_Text_Buffer_canUndo(self: Fl_Text_BufferPtr, flag: t.CChar) +extern def Fl_Text_Buffer_canUndo(self: Fl_Text_BufferPtr, flag: char) extern def Fl_Text_Buffer_can_undo(self: Fl_Text_BufferPtr) -> int extern def Fl_Text_Buffer_load_file(self: Fl_Text_BufferPtr, file: str) -> int extern def Fl_Text_Buffer_save_file(self: Fl_Text_BufferPtr, file: str) -> int diff --git a/fltk/_cfl_tree.vp b/fltk/_cfl_tree.vp index 21cacb8..98b88f5 100644 --- a/fltk/_cfl_tree.vp +++ b/fltk/_cfl_tree.vp @@ -279,11 +279,11 @@ extern def Fl_Tree_Item_deselect(self: Fl_Tree_ItemPtr) extern def Fl_Tree_Item_deselect_all(self: Fl_Tree_ItemPtr) -> int extern def Fl_Tree_Item_is_root(self: Fl_Tree_ItemPtr) -> int extern def Fl_Tree_Item_is_visible(self: Fl_Tree_ItemPtr) -> int -extern def Fl_Tree_Item_is_active(self: Fl_Tree_ItemPtr) -> t.CChar -extern def Fl_Tree_Item_is_activated(self: Fl_Tree_ItemPtr) -> t.CChar +extern def Fl_Tree_Item_is_active(self: Fl_Tree_ItemPtr) -> char +extern def Fl_Tree_Item_is_activated(self: Fl_Tree_ItemPtr) -> char extern def Fl_Tree_Item_deactivate(self: Fl_Tree_ItemPtr) extern def Fl_Tree_Item_activate(self: Fl_Tree_ItemPtr, val: int) -extern def Fl_Tree_Item_is_selected(self: Fl_Tree_ItemPtr) -> t.CChar +extern def Fl_Tree_Item_is_selected(self: Fl_Tree_ItemPtr) -> char extern def Fl_Tree_Item_Array_total(self: Fl_Tree_Item_ArrayPtr) -> int extern def Fl_Tree_Item_Array_swap(self: Fl_Tree_Item_ArrayPtr, ax: int, bx: int) extern def Fl_Tree_Item_Array_move(self: Fl_Tree_Item_ArrayPtr, to: int, from_: int) -> int diff --git a/fltk/_cfl_valuator.vp b/fltk/_cfl_valuator.vp index 6908da4..5a4bd7b 100644 --- a/fltk/_cfl_valuator.vp +++ b/fltk/_cfl_valuator.vp @@ -1905,8 +1905,8 @@ extern def Fl_Value_Input_set_text_font(self: Fl_Value_InputPtr, f: int) extern def Fl_Value_Input_text_font(self: Fl_Value_InputPtr) -> int extern def Fl_Value_Input_set_text_size(self: Fl_Value_InputPtr, s: int) extern def Fl_Value_Input_text_size(self: Fl_Value_InputPtr) -> int -extern def Fl_Value_Input_set_soft(self: Fl_Value_InputPtr, val: t.CChar) -extern def Fl_Value_Input_soft(self: Fl_Value_InputPtr) -> t.CChar +extern def Fl_Value_Input_set_soft(self: Fl_Value_InputPtr, val: char) +extern def Fl_Value_Input_soft(self: Fl_Value_InputPtr) -> char extern def Fl_Value_Output_set_text_color(self: Fl_Value_OutputPtr, c: t.CUInt32T) extern def Fl_Value_Output_text_color(self: Fl_Value_OutputPtr) -> t.CUInt32T extern def Fl_Value_Output_set_text_font(self: Fl_Value_OutputPtr, f: int) diff --git a/fltk/_cfl_window.vp b/fltk/_cfl_window.vp index 61d7017..9b1eeae 100644 --- a/fltk/_cfl_window.vp +++ b/fltk/_cfl_window.vp @@ -1088,7 +1088,7 @@ extern def Fl_gc() -> bytes extern def Fl_cairo_gc() -> bytes extern def Fl_Window_show_with_args(w: Fl_WindowPtr, argc: int, argv: bytes) extern def Fl_Window_allow_expand_outside_parent(self: Fl_WindowPtr) -extern def Fl_Window_os_id(self: Fl_WindowPtr) -> t.CSizeT +extern def Fl_Window_os_id(self: Fl_WindowPtr) -> sizet extern def Fl_Double_Window_flush(w: Fl_Double_WindowPtr) extern def Fl_Overlay_Window_draw_overlay(self: Fl_Overlay_WindowPtr, cb: bytes, data: bytes) extern def Fl_Overlay_Window_redraw_overlay(self: Fl_Overlay_WindowPtr) @@ -1096,10 +1096,10 @@ extern def Fl_Overlay_Window_can_do_overlay(self: Fl_Overlay_WindowPtr) -> int extern def Fl_gl_start() extern def Fl_gl_finish() extern def Fl_Gl_Window_flush(self: Fl_Gl_WindowPtr) -extern def Fl_Gl_Window_valid(self: Fl_Gl_WindowPtr) -> t.CChar -extern def Fl_Gl_Window_set_valid(self: Fl_Gl_WindowPtr, v: t.CChar) -extern def Fl_Gl_Window_context_valid(self: Fl_Gl_WindowPtr) -> t.CChar -extern def Fl_Gl_Window_set_context_valid(self: Fl_Gl_WindowPtr, v: t.CChar) +extern def Fl_Gl_Window_valid(self: Fl_Gl_WindowPtr) -> char +extern def Fl_Gl_Window_set_valid(self: Fl_Gl_WindowPtr, v: char) +extern def Fl_Gl_Window_context_valid(self: Fl_Gl_WindowPtr) -> char +extern def Fl_Gl_Window_set_context_valid(self: Fl_Gl_WindowPtr, v: char) extern def Fl_Gl_Window_can_do(self: Fl_Gl_WindowPtr) -> int extern def Fl_Gl_Window_context(self: Fl_Gl_WindowPtr) -> bytes extern def Fl_Gl_Window_set_context(self: Fl_Gl_WindowPtr, ctx: bytes, destroy_flag: int) @@ -1118,10 +1118,10 @@ extern def Fl_Gl_Window_mode(self: Fl_Gl_WindowPtr) -> int extern def Fl_Gl_Window_set_mode(self: Fl_Gl_WindowPtr, mode: int) extern def Fl_Gl_Window_get_proc_address(self: Fl_Gl_WindowPtr, s: str) -> bytes extern def Fl_Glut_Window_flush(self: Fl_Glut_WindowPtr) -extern def Fl_Glut_Window_valid(self: Fl_Glut_WindowPtr) -> t.CChar -extern def Fl_Glut_Window_set_valid(self: Fl_Glut_WindowPtr, v: t.CChar) -extern def Fl_Glut_Window_context_valid(self: Fl_Glut_WindowPtr) -> t.CChar -extern def Fl_Glut_Window_set_context_valid(self: Fl_Glut_WindowPtr, v: t.CChar) +extern def Fl_Glut_Window_valid(self: Fl_Glut_WindowPtr) -> char +extern def Fl_Glut_Window_set_valid(self: Fl_Glut_WindowPtr, v: char) +extern def Fl_Glut_Window_context_valid(self: Fl_Glut_WindowPtr) -> char +extern def Fl_Glut_Window_set_context_valid(self: Fl_Glut_WindowPtr, v: char) extern def Fl_Glut_Window_can_do(self: Fl_Glut_WindowPtr) -> int extern def Fl_Glut_Window_context(self: Fl_Glut_WindowPtr) -> bytes extern def Fl_Glut_Window_set_context(self: Fl_Glut_WindowPtr, ctx: bytes, destroy_flag: int) diff --git a/gzip.vp b/gzip.vp index c79ee67..ea76b16 100644 --- a/gzip.vp +++ b/gzip.vp @@ -9,7 +9,7 @@ # gz: rawptr[gzip.GzipFile] = gzip.GzipFile("train-images-idx3-ubyte.gz") # if gz is None or gz.ok == 0: ... # buf: bytes = gz.read_all() # 内部 malloc, read_all 返回即解压完成 -# n: t.CSizeT = gz.dst_len # 原始长度(由对象持有, close 时释放) +# n: sizet = gz.dst_len # 原始长度(由对象持有, close 时释放) # gz.close() # # 覆盖 stored/fixed/dynamic 三种 deflate 块; 不解 CRC。 @@ -25,13 +25,13 @@ from stdint import * # GzipFile # ============================================================ class GzipFile: - ok: t.CInt # 1 = 可正常使用 - err: t.CInt # 错误码(0 无, <0 出错) - src: BYTEPTR # 整个 .gz 文件的内存副本(构造时读入, close 释放) - src_len: t.CSizeT - dst: BYTEPTR # 解压输出缓冲(read_all 生成, close 释放) - dst_len: t.CSizeT # 解压结果长度 - _need_close_src: t.CInt # 是否持有 src(读失败时为 0) + ok: int # 1 = 可正常使用 + err: int # 错误码(0 无, <0 出错) + src: bytes # 整个 .gz 文件的内存副本(构造时读入, close 释放) + src_len: sizet + dst: bytes # 解压输出缓冲(read_all 生成, close 释放) + dst_len: sizet # 解压结果长度 + _need_close_src: int # 是否持有 src(读失败时为 0) def __init__(self, path: str): self.ok = 0 @@ -44,30 +44,30 @@ class GzipFile: if path is None: self.err = -1 return - f: rawptr[fileio.File] = fileio.File(path, fileio.MODE.R) + f: fileio.File = fileio.File(path, fileio.MODE.R) if f.closed: self.err = -2 # 打不开文件 return - sz: LONGLONG = f.size() + sz: longlong = f.size() if sz < 18: f.close() self.err = -3 # 文件过小 return - self.src_len = t.CSizeT(sz) + self.src_len = sizet(sz) # read_all 契约: 最多读 max_count-1 字节并补 NUL; 故按 src_len+1 申请与请求 - buf: BYTEPTR = stdlib.malloc(self.src_len + 1) + buf: bytes = stdlib.malloc(self.src_len + 1) if buf is None: f.close() self.err = -4 return got: LONG = f.read_all(buf, ULONG(self.src_len + 1)) f.close() - if got <= 0 or t.CSizeT(got) != self.src_len: + if got <= 0 or sizet(got) != self.src_len: stdlib.free(buf) self.err = -5 # 读取失败或被截断 return # gzip 魔数校验 - ub: t.CUnsignedChar | t.CPtr = buf + ub: uchar*= buf if ub[0] != 0x1F or ub[1] != 0x8B or ub[2] != 8: stdlib.free(buf) self.err = -6 @@ -76,14 +76,14 @@ class GzipFile: self._need_close_src = 1 self.ok = 1 - def read_all(self) -> BYTEPTR: + def read_all(self) -> bytes: """解压整个成员。返回内部持有的输出缓冲(或 None); 长度见 self.dst_len。""" if self.ok == 0 or self.src is None: return None if self.dst is not None: return self.dst # 已解压过 - want: t.CUInt32T = gzip_isize(self.src, self.src_len) - cap: t.CSizeT = t.CSizeT(want) + want: uint32 = gzip_isize(self.src, self.src_len) + cap: sizet = sizet(want) if cap == 0: cap = self.src_len * 64 # 无 ISIZE 时保守初值 if cap < 1024: @@ -101,17 +101,17 @@ class GzipFile: stdlib.free(out) out = None if cap >= 1073741824: - self.err = t.CInt(n) + self.err = int(n) return None cap = cap * 2 continue break if n <= 0: stdlib.free(out) - self.err = t.CInt(n) # n 为负错误码, 原样保存 + self.err = int(n) # n 为负错误码, 原样保存 return None self.dst = out - self.dst_len = t.CSizeT(n) + self.dst_len = sizet(n) return out def close(self): @@ -126,74 +126,31 @@ class GzipFile: self._need_close_src = 0 self.ok = 0 - -# ============================================================ -# 公共访问器(跨模块读字段用函数, 避免 stub 字段访问陷阱) -# ============================================================ -def gzip_open(path: str) -> GzipFile | t.CPtr: - return GzipFile(path) - - -def gzip_ok(gz: GzipFile | t.CPtr) -> t.CInt: - if gz is None: - return 0 - return gz.ok - - -def gzip_err(gz: GzipFile | t.CPtr) -> t.CInt: - if gz is None: - return -1 - return gz.err - - -def gzip_dst_len(gz: GzipFile | t.CPtr) -> t.CSizeT: - if gz is None: - return 0 - return gz.dst_len - - -def gzip_read(gz: GzipFile | t.CPtr) -> BYTEPTR: - if gz is None: - return None - return gz.read_all() - - -def gzip_close(gz: GzipFile | t.CPtr): - if gz is not None: - gz.close() - - -def gzip_decode_bytes(src: t.CPtr, src_len: t.CSizeT, - dst: t.CPtr, dst_cap: t.CSizeT) -> LONG: - """原始缓冲到缓冲的解压(不读文件), 供下载流程直接使用""" - return _gzip_decode(src, src_len, dst, dst_cap) - - # ============================================================ # 位流状态(模块级, 单线程; 每次 _gzip_decode 重置) # ============================================================ -_g_bits: t.CUInt64T = 0 -_g_bitcnt: t.CInt = 0 -_g_pos: t.CSizeT = 0 +_g_bits: uint64 = 0 +_g_bitcnt: int = 0 +_g_pos: sizet = 0 _g_src: t.CPtr = None -_g_src_len: t.CSizeT = 0 +_g_src_len: sizet = 0 -def gzip_isize(src: t.CPtr, src_len: t.CSizeT) -> t.CUInt32T: +def gzip_isize(src: t.CPtr, src_len: sizet) -> uint32: """gzip 尾部 ISIZE(小端 u32), 即原始长度提示""" if src is None or src_len < 4: return 0 - ub: t.CUnsignedChar | t.CPtr = src - p: t.CSizeT = src_len - 4 + ub: uchar* = src + p: sizet = src_len - 4 # 小端 u32 拼装(64 位中间量后收窄) - v64: t.CUInt64T = t.CUInt64T(ub[p]) \ - + t.CUInt64T(ub[p + 1]) * 256 \ - + t.CUInt64T(ub[p + 2]) * 65536 \ - + t.CUInt64T(ub[p + 3]) * 16777216 - return t.CUInt32T(v64) + v64: uint64 = uint64(ub[p]) \ + + uint64(ub[p + 1]) * 256 \ + + uint64(ub[p + 2]) * 65536 \ + + uint64(ub[p + 3]) * 16777216 + return uint32(v64) -def _reset(src: t.CPtr, src_len: t.CSizeT): +def _reset(src: t.CPtr, src_len: sizet): global _g_bits, _g_bitcnt, _g_pos, _g_src, _g_src_len _g_bits = 0 _g_bitcnt = 0 @@ -202,29 +159,29 @@ def _reset(src: t.CPtr, src_len: t.CSizeT): _g_src_len = src_len -def _fill(n: t.CInt) -> t.CInt: +def _fill(n: int) -> int: global _g_bits, _g_bitcnt, _g_pos, _g_src, _g_src_len - sb: t.CUnsignedChar | t.CPtr = _g_src + sb: uchar* = _g_src while _g_bitcnt < n: if _g_pos >= _g_src_len: return -1 - _g_bits = _g_bits | (t.CUInt64T(sb[_g_pos]) << _g_bitcnt) + _g_bits = _g_bits | (uint64(sb[_g_pos]) << _g_bitcnt) _g_pos += 1 _g_bitcnt += 8 return 0 -def _bits(n: t.CInt) -> t.CInt: +def _bits(n: int) -> int: global _g_bits, _g_bitcnt if _fill(n) != 0: return -1 - v: t.CUInt64T = _g_bits & ((t.CUInt64T(1) << n) - 1) + v: uint64 = _g_bits & ((uint64(1) << n) - 1) _g_bits = _g_bits >> n _g_bitcnt -= n - return t.CInt(v) + return int(v) -def _byte() -> t.CInt: +def _byte() -> int: return _bits(8) @@ -234,49 +191,49 @@ def _align(): _g_bitcnt = 0 -def _decode(count: t.CInt | t.CPtr, first: t.CInt | t.CPtr, - off: t.CInt | t.CPtr, sorted: t.CInt | t.CPtr) -> t.CInt: - code: t.CInt = 0 - ln: t.CInt = 1 +def _decode(count: int | t.CPtr, first: int | t.CPtr, + off: int | t.CPtr, sorted: int | t.CPtr) -> int: + code: int = 0 + ln: int = 1 while ln <= 15: - b: t.CInt = _bits(1) + b: int = _bits(1) if b < 0: return -1 code = (code << 1) | b if count[ln] != 0: - d: t.CInt = code - first[ln] + d: int = code - first[ln] if d >= 0 and d < count[ln]: return sorted[off[ln] + d] ln += 1 return -1 -def _build(first: t.CInt | t.CPtr, off: t.CInt | t.CPtr, - count: t.CInt | t.CPtr) -> t.CInt: - anylen: t.CInt = 0 - l1: t.CInt = 1 +def _build(first: int | t.CPtr, off: int | t.CPtr, + count: int | t.CPtr) -> int: + anylen: int = 0 + l1: int = 1 while l1 <= 15: if count[l1] != 0: anylen = 1 l1 += 1 if anylen == 0: return -1 - left: t.CInt = 1 - l2: t.CInt = 1 + left: int = 1 + l2: int = 1 while l2 <= 15: left = left << 1 if count[l2] > left: return -1 left = left - count[l2] l2 += 1 - code: t.CInt = 0 - l3: t.CInt = 1 + code: int = 0 + l3: int = 1 while l3 <= 15: code = (code + count[l3 - 1]) << 1 first[l3] = code l3 += 1 - offsum: t.CInt = 0 - l4: t.CInt = 1 + offsum: int = 0 + l4: int = 1 while l4 <= 15: off[l4] = offsum offsum += count[l4] @@ -284,22 +241,22 @@ def _build(first: t.CInt | t.CPtr, off: t.CInt | t.CPtr, return 0 -def _collect(len_arr: t.CInt | t.CPtr, cnt: t.CInt | t.CPtr, - sorted_arr: t.CInt | t.CPtr, nsym: t.CInt, - pos: t.CInt | t.CPtr): +def _collect(len_arr: int | t.CPtr, cnt: int | t.CPtr, + sorted_arr: int | t.CPtr, nsym: int, + pos: int | t.CPtr): string.memset(cnt, 0, 17 * 4) - s1: t.CInt = 0 + s1: int = 0 while s1 < nsym: if len_arr[s1] != 0: cnt[len_arr[s1]] += 1 s1 += 1 - run: t.CInt = 0 - l5: t.CInt = 1 + run: int = 0 + l5: int = 1 while l5 <= 15: pos[l5] = run run += cnt[l5] l5 += 1 - s2: t.CInt = 0 + s2: int = 0 while s2 < nsym: if len_arr[s2] != 0: sorted_arr[pos[len_arr[s2]]] = s2 @@ -307,7 +264,7 @@ def _collect(len_arr: t.CInt | t.CPtr, cnt: t.CInt | t.CPtr, s2 += 1 -def _len_extra(code: t.CInt) -> t.CInt: +def _len_extra(code: int) -> int: if code == 285: return 0 if code >= 281: @@ -323,7 +280,7 @@ def _len_extra(code: t.CInt) -> t.CInt: return 0 -def _len_base(code: t.CInt) -> t.CInt: +def _len_base(code: int) -> int: if code == 285: return 258 if code >= 281: @@ -339,41 +296,41 @@ def _len_base(code: t.CInt) -> t.CInt: return 3 + (code - 257) -def _dist_extra(code: t.CInt) -> t.CInt: +def _dist_extra(code: int) -> int: if code < 4: return 0 return (code - 4) // 2 + 1 -def _dist_base(code: t.CInt) -> t.CInt: +def _dist_base(code: int) -> int: if code < 4: return code + 1 - e: t.CInt = (code - 4) // 2 + 1 - f: t.CInt = (1 << (e + 1)) + 1 + e: int = (code - 4) // 2 + 1 + f: int = (1 << (e + 1)) + 1 if code % 2 == 0: return f return f + (1 << e) -def _cl_order_set(arr: t.CInt | t.CPtr, idx: t.CInt, val: t.CInt): +def _cl_order_set(arr: int | t.CPtr, idx: int, val: int): arr[idx] = val # ============================================================ # 核心解压(模块级私有) # ============================================================ -def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, - dst: t.CPtr, dst_cap: t.CSizeT) -> LONG: +def _gzip_decode(src: t.CPtr, src_len: sizet, + dst: t.CPtr, dst_cap: sizet) -> LONG: if src is None or dst is None or src_len < 18 or dst_cap == 0: return -1 - ub: t.CUnsignedChar | t.CPtr = src + ub: uchar* = src if ub[0] != 0x1F or ub[1] != 0x8B or ub[2] != 8: return -2 _reset(src, src_len) - flg: t.CInt = t.CInt(ub[3]) - hdr_len: t.CSizeT = 10 + flg: int = int(ub[3]) + hdr_len: sizet = 10 if flg & 0x04 != 0: - xlen: t.CSizeT = t.CSizeT(ub[hdr_len]) | (t.CSizeT(ub[hdr_len + 1]) << 8) + xlen: sizet = sizet(ub[hdr_len]) | (sizet(ub[hdr_len + 1]) << 8) hdr_len += 2 + xlen if flg & 0x08 != 0: while hdr_len < src_len and ub[hdr_len] != 0: @@ -390,26 +347,26 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, global _g_pos _g_pos = hdr_len - dout: t.CUnsignedChar | t.CPtr = dst - wpos: t.CSizeT = 0 + dout: uchar* = dst + wpos: sizet = 0 - lit_len: t.CInt | t.CPtr = stdlib.malloc(288 * 4) - lit_cnt: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - lit_first: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - lit_off: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - lit_sorted: t.CInt | t.CPtr = stdlib.malloc(288 * 4) - dst_len: t.CInt | t.CPtr = stdlib.malloc(32 * 4) - dst_cnt: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - dst_first: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - dst_off: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - dst_sorted: t.CInt | t.CPtr = stdlib.malloc(32 * 4) - cl_len: t.CInt | t.CPtr = stdlib.malloc(19 * 4) - cl_order: t.CInt | t.CPtr = stdlib.malloc(19 * 4) - cl_cnt: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - cl_first: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - cl_off: t.CInt | t.CPtr = stdlib.malloc(17 * 4) - cl_sorted: t.CInt | t.CPtr = stdlib.malloc(19 * 4) - pos_tmp: t.CInt | t.CPtr = stdlib.malloc(17 * 4) + lit_len: int | t.CPtr = stdlib.malloc(288 * 4) + lit_cnt: int | t.CPtr = stdlib.malloc(17 * 4) + lit_first: int | t.CPtr = stdlib.malloc(17 * 4) + lit_off: int | t.CPtr = stdlib.malloc(17 * 4) + lit_sorted: int | t.CPtr = stdlib.malloc(288 * 4) + dst_len: int | t.CPtr = stdlib.malloc(32 * 4) + dst_cnt: int | t.CPtr = stdlib.malloc(17 * 4) + dst_first: int | t.CPtr = stdlib.malloc(17 * 4) + dst_off: int | t.CPtr = stdlib.malloc(17 * 4) + dst_sorted: int | t.CPtr = stdlib.malloc(32 * 4) + cl_len: int | t.CPtr = stdlib.malloc(19 * 4) + cl_order: int | t.CPtr = stdlib.malloc(19 * 4) + cl_cnt: int | t.CPtr = stdlib.malloc(17 * 4) + cl_first: int | t.CPtr = stdlib.malloc(17 * 4) + cl_off: int | t.CPtr = stdlib.malloc(17 * 4) + cl_sorted: int | t.CPtr = stdlib.malloc(19 * 4) + pos_tmp: int | t.CPtr = stdlib.malloc(17 * 4) if lit_len is None or lit_cnt is None or lit_first is None \ or lit_off is None or lit_sorted is None or dst_len is None \ or dst_cnt is None or dst_first is None or dst_off is None \ @@ -457,29 +414,29 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, _cl_order_set(cl_order, 17, 1) _cl_order_set(cl_order, 18, 15) - err: t.CInt = 0 - final: t.CInt = 0 + err: int = 0 + final: int = 0 while final == 0 and err == 0: - bfinal: t.CInt = _bits(1) - btype: t.CInt = _bits(2) + bfinal: int = _bits(1) + btype: int = _bits(2) if bfinal < 0 or btype < 0: err = -5 break final = bfinal if btype == 0: _align() - slen: t.CInt = _bits(16) - snlen: t.CInt = _bits(16) + slen: int = _bits(16) + snlen: int = _bits(16) if slen < 0 or snlen < 0: err = -6 break if (slen ^ snlen) != 0xFFFF: err = -7 break - i: t.CSizeT = 0 - while i < t.CSizeT(slen): - ch: t.CInt = _byte() + i: sizet = 0 + while i < sizet(slen): + ch: int = _byte() if ch < 0: err = -8 break @@ -493,7 +450,7 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, break elif btype == 1: string.memset(lit_cnt, 0, 17 * 4) - j: t.CInt = 0 + j: int = 0 while j < 144: lit_len[j] = 8 j += 1 @@ -511,16 +468,16 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, err = -10 break else: - hlit: t.CInt = _bits(5) + 257 - hdist: t.CInt = _bits(5) + 1 - hclen: t.CInt = _bits(4) + 4 + hlit: int = _bits(5) + 257 + hdist: int = _bits(5) + 1 + hclen: int = _bits(4) + 4 if hlit < 0 or hdist < 0 or hclen < 0: err = -11 break string.memset(cl_len, 0, 19 * 4) - k: t.CInt = 0 + k: int = 0 while k < hclen: - vv: t.CInt = _bits(3) + vv: int = _bits(3) if vv < 0: err = -12 break @@ -534,9 +491,9 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, break string.memset(lit_len, 0, 288 * 4) string.memset(dst_len, 0, 32 * 4) - sym_i: t.CInt = 0 + sym_i: int = 0 while sym_i < hlit + hdist: - sym: t.CInt = _decode(cl_cnt, cl_first, cl_off, cl_sorted) + sym: int = _decode(cl_cnt, cl_first, cl_off, cl_sorted) if sym < 0: err = -14 break @@ -547,14 +504,14 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, dst_len[sym_i - hlit] = sym sym_i += 1 elif sym == 16: - prev: t.CInt = 0 + prev: int = 0 if sym_i > 0: if sym_i - 1 < hlit: prev = lit_len[sym_i - 1] else: prev = dst_len[sym_i - hlit - 1] - rp: t.CInt = _bits(2) + 3 - r2: t.CInt = 0 + rp: int = _bits(2) + 3 + r2: int = 0 while r2 < rp and sym_i < hlit + hdist: if sym_i < hlit: lit_len[sym_i] = prev @@ -563,8 +520,8 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, sym_i += 1 r2 += 1 elif sym == 17: - rp2: t.CInt = _bits(3) + 3 - r3: t.CInt = 0 + rp2: int = _bits(3) + 3 + r3: int = 0 while r3 < rp2 and sym_i < hlit + hdist: if sym_i < hlit: lit_len[sym_i] = 0 @@ -573,8 +530,8 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, sym_i += 1 r3 += 1 else: - rp3: t.CInt = _bits(7) + 11 - r4: t.CInt = 0 + rp3: int = _bits(7) + 11 + r4: int = 0 while r4 < rp3 and sym_i < hlit + hdist: if sym_i < hlit: lit_len[sym_i] = 0 @@ -595,9 +552,9 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, if err != 0: break - run: t.CInt = 1 + run: int = 1 while run == 1 and err == 0: - sym: t.CInt = _decode(lit_cnt, lit_first, lit_off, lit_sorted) + sym: int = _decode(lit_cnt, lit_first, lit_off, lit_sorted) if sym < 0: err = -17 break @@ -610,26 +567,26 @@ def _gzip_decode(src: t.CPtr, src_len: t.CSizeT, elif sym == 256: run = 0 else: - le: t.CInt = _len_extra(sym) - ev: t.CInt = _bits(le) + le: int = _len_extra(sym) + ev: int = _bits(le) if ev < 0: err = -19 break - length: t.CSizeT = t.CSizeT(_len_base(sym) + ev) - ds: t.CInt = _decode(dst_cnt, dst_first, dst_off, dst_sorted) + length: sizet = sizet(_len_base(sym) + ev) + ds: int = _decode(dst_cnt, dst_first, dst_off, dst_sorted) if ds < 0: err = -20 break - de: t.CInt = _dist_extra(ds) - dv: t.CInt = _bits(de) + de: int = _dist_extra(ds) + dv: int = _bits(de) if dv < 0: err = -21 break - dist: t.CSizeT = t.CSizeT(_dist_base(ds) + dv) + dist: sizet = sizet(_dist_base(ds) + dv) if dist == 0 or dist > wpos: err = -22 break - ci: t.CSizeT = 0 + ci: sizet = 0 while ci < length: if wpos >= dst_cap: err = -23 diff --git a/hashlib/__md5.vp b/hashlib/__md5.vp index 745fa20..cdf1216 100644 --- a/hashlib/__md5.vp +++ b/hashlib/__md5.vp @@ -5,16 +5,16 @@ import t, c # ============================================== # MD5 hash algorithm # ============================================== -MD5_BLOCK_LEN: t.CDefine = 64 # Group block size -MD5_DIGEST_LEN: t.CDefine = 16 # Digest output length +define MD5_BLOCK_LEN = 64 # Group block size +define MD5_DIGEST_LEN = 16 # Digest output length # MD5 four-round nonlinear functions -def md5_F(x: uint32, y: uint32, z: uint32) -> uint32: return (x & y) | (~x & z) -def md5_G(x: uint32, y: uint32, z: uint32) -> uint32: return (x & z) | (y & ~z) -def md5_H(x: uint32, y: uint32, z: uint32) -> uint32: return x ^ y ^ z -def md5_I(x: uint32, y: uint32, z: uint32) -> uint32: return y ^ (x | ~z) +define md5_F(x: uint32, y: uint32, z: uint32) -> uint32: return (x & y) | (~x & z) +define md5_G(x: uint32, y: uint32, z: uint32) -> uint32: return (x & z) | (y & ~z) +define md5_H(x: uint32, y: uint32, z: uint32) -> uint32: return x ^ y ^ z +define md5_I(x: uint32, y: uint32, z: uint32) -> uint32: return y ^ (x | ~z) # Circular left shift -def md5_rotl(x: uint32, n: int) -> uint32: return (x << n) | (x >> (32 - n)) +define md5_rotl(x: uint32, n: int) -> uint32: return (x << n) | (x >> (32 - n)) # MD5 constant table md5_T: t.CArray[uint32, 64] = [ @@ -35,21 +35,18 @@ md5_S: t.CArray[int, 64] = [ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 ] -# MD5 context structure -# ============================================================ -@t.Object + +# MD5 Context class md5: - state: t.CArray[uint32, 4] # 4 32-bit state registers - count: uint64 # processed bits + state: t.CArray[uint32, 4] = [ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ] # 4 32-bit state registers + count: uint64 = 0 # processed bits buf: t.CArray[uint8, MD5_BLOCK_LEN] # Group buffer # Initialize MD5 context def __init__(self): string.memset(self.buf, 0, MD5_BLOCK_LEN) - self.state[0] = 0x67452301 - self.state[1] = 0xefcdab89 - self.state[2] = 0x98badcfe - self.state[3] = 0x10325476 - self.count = 0 # MD5 single-group compression transform def transform(self, block: rawptr[uint8]): a: uint32 = self.state[0] @@ -89,11 +86,11 @@ class md5: # Batch input data def update(self, s: str): data: rawptr[uint8] = uint8(s, t.CPtr) - length: t.CSizeT = len(s) - idx: t.CSizeT = self.count % MD5_BLOCK_LEN + length: sizet = len(s) + idx: sizet = self.count % MD5_BLOCK_LEN self.count += length if idx > 0: - left: t.CSizeT = MD5_BLOCK_LEN - idx + left: sizet = MD5_BLOCK_LEN - idx if length >= left: string.memcpy(self.buf + idx, data, left) self.transform(self.buf) @@ -108,7 +105,7 @@ class md5: string.memcpy(self.buf + idx, data, length) # End calculation, output 16-byte digest def final(self, out: t.CArray[uint8, MD5_DIGEST_LEN]): - idx: t.CSizeT = self.count % MD5_BLOCK_LEN + idx: sizet = self.count % MD5_BLOCK_LEN # Pad 0x80 end self.buf[idx] = 0x80 idx += 1 diff --git a/hashlib/__sha1.vp b/hashlib/__sha1.vp index 18dce48..7b60a02 100644 --- a/hashlib/__sha1.vp +++ b/hashlib/__sha1.vp @@ -6,29 +6,26 @@ import t, c # ============================================== # SHA1 Hash Algorithm # ============================================== -SHA1_BLOCK_LEN: t.CDefine = 64 -SHA1_DIGEST_LEN: t.CDefine = 20 +define SHA1_BLOCK_LEN = 64 +define SHA1_DIGEST_LEN = 20 -def sha1_rotl(x: uint32, n: int) -> uint32: return (x << n) | (x >> (32 - n)) +define sha1_rotl(x: uint32, n: int) -> uint32: return (x << n) | (x >> (32 - n)) # 3-round logical functions -def sha1_f1(b: uint32, c: uint32, d: uint32) -> uint32: return (b & c) | (~b & d) -def sha1_f2(b: uint32, c: uint32, d: uint32) -> uint32: return b ^ c ^ d -def sha1_f3(b: uint32, c: uint32, d: uint32) -> uint32: return (b & c) | (b & d) | (c & d) +define sha1_f1(b: uint32, c: uint32, d: uint32) -> uint32: return (b & c) | (~b & d) +define sha1_f2(b: uint32, c: uint32, d: uint32) -> uint32: return b ^ c ^ d +define sha1_f3(b: uint32, c: uint32, d: uint32) -> uint32: return (b & c) | (b & d) | (c & d) # SHA1 Context -@t.Object class sha1: - state: t.CArray[uint32, 5] - count: uint64 + state: t.CArray[uint32, 5] = [ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ] # 5 32-bit state registers + count: uint64 = 0 # processed bits buf: t.CArray[uint8, SHA1_BLOCK_LEN] def __init__(self): string.memset(self.buf, 0, SHA1_BLOCK_LEN) - self.state[0] = 0x67452301 - self.state[1] = 0xefcdab89 - self.state[2] = 0x98badcfe - self.state[3] = 0x10325476 - self.state[4] = 0xc3d2e1f0 - self.count = 0 # Single-group compression transform def transform(self, block: rawptr[uint8]): w: t.CArray[uint32, 80] @@ -81,11 +78,11 @@ class sha1: self.state[4] += e def update(self, s: str): data: rawptr[uint8] = uint8(s, t.CPtr) - length: t.CSizeT = len(s) - idx: t.CSizeT = self.count % SHA1_BLOCK_LEN + length: sizet = len(s) + idx: sizet = self.count % SHA1_BLOCK_LEN self.count += length if idx > 0: - left: t.CSizeT = SHA1_BLOCK_LEN - idx + left: sizet = SHA1_BLOCK_LEN - idx if length >= left: string.memcpy(self.buf + idx, data, left) self.transform(self.buf) @@ -99,7 +96,7 @@ class sha1: if length > 0: string.memcpy(self.buf + idx, data, length) def final(self, out: t.CArray[uint8, SHA1_DIGEST_LEN]): - idx: t.CSizeT = self.count % SHA1_BLOCK_LEN + idx: sizet = self.count % SHA1_BLOCK_LEN self.buf[idx] = 0x80 idx += 1 if idx > SHA1_BLOCK_LEN - 8: diff --git a/hashlib/__sha256.vp b/hashlib/__sha256.vp index e7cc2c9..1666e79 100644 --- a/hashlib/__sha256.vp +++ b/hashlib/__sha256.vp @@ -5,8 +5,8 @@ import t, c # ============================================== # SHA256 Hash Algorithm # ============================================== -SHA256_BLOCK_LEN: t.CDefine = 64 -SHA256_DIGEST_LEN: t.CDefine = 32 +define SHA256_BLOCK_LEN = 64 +define SHA256_DIGEST_LEN = 32 # SHA256 Constants K sha256_K: t.CArray[uint32, 64] = [ @@ -21,30 +21,25 @@ sha256_K: t.CArray[uint32, 64] = [ ] # SHA256 Auxiliary Functions -def s0(x: uint32) -> uint32: return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ ((x >> 3)) -def s1(x: uint32) -> uint32: return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ ((x >> 10)) -def S0(x: uint32) -> uint32: return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) -def S1(x: uint32) -> uint32: return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) -def Ch(x: uint32, y: uint32, z: uint32) -> uint32: return (x & y) ^ (~x & z) -def Maj(x: uint32, y: uint32, z: uint32) -> uint32: return (x & y) ^ (x & z) ^ (y & z) +define s0(x: uint32) -> uint32: return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ ((x >> 3)) +define s1(x: uint32) -> uint32: return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ ((x >> 10)) +define S0(x: uint32) -> uint32: return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) +define S1(x: uint32) -> uint32: return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) +define Ch(x: uint32, y: uint32, z: uint32) -> uint32: return (x & y) ^ (~x & z) +define Maj(x: uint32, y: uint32, z: uint32) -> uint32: return (x & y) ^ (x & z) ^ (y & z) # SHA256 Context -@t.Object class sha256: - state: t.CArray[uint32, 8] - count: uint64 + state: array[uint32, 8] = [ + 0x6a09e667, 0xbb67ae85, + 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19 + ] # 8 32-bit state registers + count: uint64 = 0 # processed bits buf: t.CArray[uint8, SHA256_BLOCK_LEN] def __init__(self): string.memset(self, 0, sha256.__sizeof__()) - self.state[0] = 0x6a09e667 - self.state[1] = 0xbb67ae85 - self.state[2] = 0x3c6ef372 - self.state[3] = 0xa54ff53a - self.state[4] = 0x510e527f - self.state[5] = 0x9b05688c - self.state[6] = 0x1f83d9ab - self.state[7] = 0x5be0cd19 - self.count = 0 # string.memset(self.buf, 0, SHA256_BLOCK_LEN) # SHA256 single-group compression transform def transform(self, block: rawptr[uint8]): @@ -86,11 +81,11 @@ class sha256: self.state[7] += h def update(self, s: str): data: rawptr[uint8] = uint8(s, t.CPtr) - length: t.CSizeT = len(s) - idx: t.CSizeT = self.count % SHA256_BLOCK_LEN + length: sizet = len(s) + idx: sizet = self.count % SHA256_BLOCK_LEN self.count += length if idx > 0: - left: t.CSizeT = SHA256_BLOCK_LEN - idx + left: sizet = SHA256_BLOCK_LEN - idx if length >= left: string.memcpy(self.buf + idx, data, left) self.transform(self.buf) @@ -104,7 +99,7 @@ class sha256: if length > 0: string.memcpy(self.buf + idx, data, length) def final(self, out: t.CArray[uint8, SHA256_DIGEST_LEN]): - idx: t.CSizeT = self.count % SHA256_BLOCK_LEN + idx: sizet = self.count % SHA256_BLOCK_LEN self.buf[idx] = 0x80 idx += 1 if idx > SHA256_BLOCK_LEN - 8: diff --git a/hashlib/__sha512.vp b/hashlib/__sha512.vp index 36a3716..880a357 100644 --- a/hashlib/__sha512.vp +++ b/hashlib/__sha512.vp @@ -5,17 +5,17 @@ import string # ============================================== # SHA512 Hash Algorithm # ============================================== -SHA512_BLOCK_LEN: t.CDefine = 128 -SHA512_DIGEST_LEN: t.CDefine = 64 +define SHA512_BLOCK_LEN = 128 +define SHA512_DIGEST_LEN = 64 -def sha512_ror(x: uint64, n: int) -> uint64: return (x >> n) | (x << (64 - n)) -def sha512_shr(x: uint64, n: int) -> uint64: return x >> n -def sha512_Ch (x: uint64, y: uint64, z: uint64) -> uint64: return (x & y) ^ (~x & z) -def sha512_Maj(x: uint64, y: uint64, z: uint64) -> uint64: return (x & y) ^ (x & z) ^ (y & z) -def sha512_BigSigma0(x: uint64) -> uint64: return sha512_ror(x, 28) ^ sha512_ror(x, 34) ^ sha512_ror(x, 39) -def sha512_BigSigma1(x: uint64) -> uint64: return sha512_ror(x, 14) ^ sha512_ror(x, 18) ^ sha512_ror(x, 41) -def sha512_Sigma0(x: uint64) -> uint64: return sha512_ror(x, 1) ^ sha512_ror(x, 8) ^ sha512_shr(x, 7) -def sha512_Sigma1(x: uint64) -> uint64: return sha512_ror(x, 19) ^ sha512_ror(x, 61) ^ sha512_shr(x, 6) +define sha512_ror(x: uint64, n: int) -> uint64: return (x >> n) | (x << (64 - n)) +define sha512_shr(x: uint64, n: int) -> uint64: return x >> n +define sha512_Ch (x: uint64, y: uint64, z: uint64) -> uint64: return (x & y) ^ (~x & z) +define sha512_Maj(x: uint64, y: uint64, z: uint64) -> uint64: return (x & y) ^ (x & z) ^ (y & z) +define sha512_BigSigma0(x: uint64) -> uint64: return sha512_ror(x, 28) ^ sha512_ror(x, 34) ^ sha512_ror(x, 39) +define sha512_BigSigma1(x: uint64) -> uint64: return sha512_ror(x, 14) ^ sha512_ror(x, 18) ^ sha512_ror(x, 41) +define sha512_Sigma0(x: uint64) -> uint64: return sha512_ror(x, 1) ^ sha512_ror(x, 8) ^ sha512_shr(x, 7) +define sha512_Sigma1(x: uint64) -> uint64: return sha512_ror(x, 19) ^ sha512_ror(x, 61) ^ sha512_shr(x, 6) sha512_K: t.CArray[uint64, 80] = [ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, @@ -40,21 +40,18 @@ sha512_K: t.CArray[uint64, 80] = [ 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 ] -@t.Object +# SHA512 Context class sha512: - state: t.CArray[uint64, 8] - count: t.CArray[uint64, 2] + state: t.CArray[uint64, 8] = [ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 + ] + count: t.CArray[uint64, 2] = [0, 0] buf: t.CArray[uint8, SHA512_BLOCK_LEN] def __init__(self): string.memset(self, 0, sha512.__sizeof__()) - self.state[0] = 0x6a09e667f3bcc908 - self.state[1] = 0xbb67ae8584caa73b - self.state[2] = 0x3c6ef372fe94f82b - self.state[3] = 0xa54ff53a5f1d36f1 - self.state[4] = 0x510e527fade682d1 - self.state[5] = 0x9b05688c2b3e6c1f - self.state[6] = 0x1f83d9abfb41bd6b - self.state[7] = 0x5be0cd19137e2179 def transform(self, block: t.CArray[uint8, SHA512_BLOCK_LEN]): w: t.CArray[uint64, 80] a: uint64 @@ -103,13 +100,13 @@ class sha512: self.state[7] += h def update(self, s: str): data: rawptr[uint8] = uint8(s, t.CPtr) - length: t.CSizeT = len(s) + length: sizet = len(s) idx: uint32 = uint32(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 + left: sizet = SHA512_BLOCK_LEN - idx if length >= left: string.memcpy(self.buf + idx, data, left) self.transform(self.buf) diff --git a/hashtable.vp b/hashtable.vp index 3decf0e..6b486ae 100644 --- a/hashtable.vp +++ b/hashtable.vp @@ -45,20 +45,20 @@ class HashTable: ht: HashTable = HashTable(mb) ht.set_int("x", 42) p: t.CPtr = ht["x"] - v: int = c.Deref(p) + v: int = c.Deref((int | t.CPtr)(p)) # int 值按 i32 存,读回须给 int* 视图 """ __slots__: t.CPtr # Base address of slot array - __count__: t.CSizeT = 0 # Number of occupied entries - __capacity__: t.CSizeT = 16 # Total slot count (power of two) - __tombstones__: t.CSizeT = 0 # Tombstone entry count - __mbuddy__: rawptr[memhub.MemBuddy] - __iter_index__: t.CSizeT = 0 + __count__: sizet = 0 # Number of occupied entries + __capacity__: sizet = 16 # Total slot count (power of two) + __tombstones__: sizet = 0 # Tombstone entry count + __mbuddy__: memhub.MemBuddy* + __iter_index__: sizet = 0 - def __new__(self, mb: rawptr[memhub.MemBuddy]) -> t.CPtr: + def __new__(self, mb: memhub.MemBuddy*) -> t.CPtr: # Heap-allocate HashTable object (6 fields × 8 bytes = 48 bytes) return mb.alloc(48) - def __init__(self, mb: rawptr[memhub.MemBuddy]): + def __init__(self, mb: memhub.MemBuddy*): self.__mbuddy__ = mb self.__capacity__ = _HT_INIT_CAP self.__count__ = 0 @@ -67,17 +67,17 @@ class HashTable: # Initialize all slots to empty (hash = 0) string.memset(self.__slots__, 0, self.__capacity__ * _HT_SLOT_SIZE) - def _slot_hash(self, idx: t.CSizeT) -> t.CUInt64T: + def _slot_hash(self, idx: sizet) -> t.CUInt64T: """Read hash value from target slot.""" ptr: t.CUInt64T | t.CPtr = t.CPtr(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) return ptr[0] - def _slot_key(self, idx: t.CSizeT) -> str: + def _slot_key(self, idx: sizet) -> str: """Read key pointer from target slot.""" ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 8) return ptr[0] - def _slot_value(self, idx: t.CSizeT) -> t.CPtr: + def _slot_value(self, idx: sizet) -> t.CPtr: """Read value pointer from target slot.""" # value 槽存的是指针,注解须为「指针的指针」:X|t.CPtr 的合并规则是 Ptr(resolve(X)), # 故 t.CUInt64T|t.CPtr|t.CPtr = Ptr(Ptr(i64)) = i64**,取下标得 i64*(指针), @@ -86,7 +86,7 @@ class HashTable: ptr: t.CUInt64T | t.CPtr | t.CPtr = 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): + def _set_slot(self, idx: sizet, h: t.CUInt64T, key: str, val: t.CPtr): """Assign three fields of the target slot.""" h_ptr: t.CUInt64T | t.CPtr = t.CPtr(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) h_ptr[0] = h @@ -96,15 +96,15 @@ class HashTable: v_ptr: t.CUInt64T | t.CPtr | t.CPtr = 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: + def _find_slot(self, key: str, h: t.CUInt64T) -> sizet: """Locate slot index for key insertion or lookup. Returns: Index of matching key if found; otherwise returns index of first usable empty/tombstone slot. """ - mask: t.CSizeT = self.__capacity__ - 1 - idx: t.CSizeT = t.CSizeT(h) & mask - first_tombstone: t.CSizeT = self.__capacity__ - i: t.CSizeT = 0 + mask: sizet = self.__capacity__ - 1 + idx: sizet = sizet(h) & mask + first_tombstone: sizet = self.__capacity__ + i: sizet = 0 while i < self.__capacity__: sh: t.CUInt64T = self._slot_hash(idx) if sh == _HT_EMPTY: @@ -125,10 +125,10 @@ class HashTable: return first_tombstone return self.__capacity__ - def _resize(self, new_cap: t.CSizeT): + def _resize(self, new_cap: sizet): """Resize table and rehash all entries.""" old_slots: t.CPtr = self.__slots__ - old_cap: t.CSizeT = self.__capacity__ + old_cap: sizet = self.__capacity__ new_slots: t.CPtr = self.__mbuddy__.alloc(new_cap * _HT_SLOT_SIZE) if new_slots == None: return @@ -137,7 +137,7 @@ class HashTable: self.__capacity__ = new_cap self.__count__ = 0 self.__tombstones__ = 0 - i: t.CSizeT = 0 + i: sizet = 0 while i < old_cap: old_h_ptr: t.CUInt64T | t.CPtr = t.CPtr(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE) h: t.CUInt64T = old_h_ptr[0] @@ -147,7 +147,7 @@ class HashTable: old_v_ptr: t.CUInt64T | t.CPtr | t.CPtr = 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) + idx: sizet = self._find_slot(k, h) self._set_slot(idx, h, k, v) self.__count__ += 1 i += 1 @@ -155,7 +155,7 @@ class HashTable: def __setitem__(self, key: str, val: t.CNeedPtr): """Insert or update key-value pair. val automatically decays to pointer (t.CNeedPtr: no conversion if already pointer).""" h: t.CUInt64T = _fnv1a_hash(key) - idx: t.CSizeT = self._find_slot(key, h) + idx: sizet = self._find_slot(key, h) if idx >= self.__capacity__: return sh: t.CUInt64T = self._slot_hash(idx) @@ -165,7 +165,7 @@ class HashTable: self._set_slot(idx, h, key, val) self.__count__ += 1 # Resize when load factor > 0.75 - load: t.CSizeT = self.__count__ + self.__tombstones__ + load: sizet = self.__count__ + self.__tombstones__ if load * 4 >= self.__capacity__ * 3: self._resize(self.__capacity__ * 2) else: @@ -174,7 +174,7 @@ class HashTable: def __getitem__(self, key: str) -> t.CPtr: """Lookup key and return value pointer. Returns None if key not found.""" h: t.CUInt64T = _fnv1a_hash(key) - idx: t.CSizeT = self._find_slot(key, h) + idx: sizet = self._find_slot(key, h) if idx >= self.__capacity__: return None sh: t.CUInt64T = self._slot_hash(idx) @@ -186,7 +186,7 @@ class HashTable: def __contains__(self, key: str) -> t.CInt: """Check whether key exists in table.""" h: t.CUInt64T = _fnv1a_hash(key) - idx: t.CSizeT = self._find_slot(key, h) + idx: sizet = self._find_slot(key, h) if idx >= self.__capacity__: return 0 sh: t.CUInt64T = self._slot_hash(idx) @@ -197,7 +197,7 @@ class HashTable: def __delitem__(self, key: str) -> t.CInt: """Delete entry by key. Return 1 on success, 0 if key not present.""" h: t.CUInt64T = _fnv1a_hash(key) - idx: t.CSizeT = self._find_slot(key, h) + idx: sizet = self._find_slot(key, h) if idx >= self.__capacity__: return 0 sh: t.CUInt64T = self._slot_hash(idx) @@ -209,7 +209,7 @@ class HashTable: self.__tombstones__ += 1 return 1 - def __len__(self) -> t.CSizeT: + def __len__(self) -> sizet: return self.__count__ def __iter__(self) -> HashTable | t.CPtr: @@ -218,7 +218,7 @@ class HashTable: def __next__(self) -> str: while self.__iter_index__ < self.__capacity__: - idx: t.CSizeT = self.__iter_index__ + idx: sizet = self.__iter_index__ self.__iter_index__ = idx + 1 sh: t.CUInt64T = self._slot_hash(idx) if sh != _HT_EMPTY and sh != _HT_TOMBSTONE: @@ -228,7 +228,7 @@ class HashTable: def get(self, key: str, default: t.CPtr) -> t.CPtr: """Return value pointer; return default pointer if key not found.""" h: t.CUInt64T = _fnv1a_hash(key) - idx: t.CSizeT = self._find_slot(key, h) + idx: sizet = self._find_slot(key, h) if idx >= self.__capacity__: return default sh: t.CUInt64T = self._slot_hash(idx) diff --git a/json/__init__.vp b/json/__init__.vp index 42f02d9..834a17b 100644 --- a/json/__init__.vp +++ b/json/__init__.vp @@ -29,7 +29,7 @@ class JsonValue: next: 'JsonValue' | t.CPtr key: str child: 'JsonValue' | t.CPtr - child_count: t.CSizeT + child_count: sizet def __new__(self, pool: rawptr[memhub.MemManager]): """从 mpool 分配 JsonValue 结构体内存并零初始化""" @@ -74,7 +74,7 @@ class JsonValue: def as_string(self) -> str: return self.str_val - def __len__(self) -> t.CSizeT: + def __len__(self) -> sizet: return self.child_count def __getitem__(self, key: str) -> 'JsonValue' | t.CPtr: @@ -109,19 +109,19 @@ class JsonValue: return cur = cur.next # key 不存在,追加新子节点 - klen: t.CSizeT = string.strlen(key) + klen: sizet = string.strlen(key) kbuf: str = 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: + def get_item(self, index: sizet) -> 'JsonValue' | t.CPtr: """按索引取数组元素:v.get_item(0)""" if self.vtype != JSON_ARRAY and self.vtype != JSON_OBJECT: return None cur: rawptr[JsonValue] = self.child - i: t.CSizeT = 0 + i: sizet = 0 while cur != None: if i == index: return cur @@ -129,7 +129,7 @@ class JsonValue: i += 1 return None - def _pool_alloc(self, size: t.CSizeT) -> str: + def _pool_alloc(self, size: sizet) -> str: """内部方法:从当前对象的 mpool 分配内存(预留,暂返回 None)""" return None @@ -180,7 +180,7 @@ def string_val(pool: rawptr[memhub.MemManager], val: str) -> rawptr[JsonValue]: if v == None: return None v.vtype = JSON_STRING if val != None: - slen: t.CSizeT = string.strlen(val) + slen: sizet = string.strlen(val) buf: str = pool.alloc(slen + 1) if buf != None: string.memcpy(buf, val, slen + 1) @@ -222,7 +222,7 @@ def object_set(pool: rawptr[memhub.MemManager], obj: rawptr[JsonValue], key: str cur.child_count = val.child_count return cur = cur.next - klen: t.CSizeT = string.strlen(key) + klen: sizet = string.strlen(key) kbuf: str = pool.alloc(klen + 1) if kbuf != None: string.memcpy(kbuf, key, klen + 1) diff --git a/json/__parser.vp b/json/__parser.vp index 4bc2bad..6715d0c 100644 --- a/json/__parser.vp +++ b/json/__parser.vp @@ -11,56 +11,50 @@ from . import ( class ParseState: src: str - pos: t.CSizeT - len: t.CSizeT + pos: sizet = 0 + len: sizet = 0 pool: rawptr[memhub.MemManager] def __init__(self, src: str, pool: rawptr[memhub.MemManager]): self.src = src - self.pos = 0 self.len = string.strlen(src) if src != None else 0 self.pool = pool -def _peek(s: rawptr[ParseState]) -> t.CChar: - if s.pos >= s.len: - return '\0' +def _peek(s: rawptr[ParseState]) -> char: + if s.pos >= s.len: return '\0' return s.src[s.pos] -def _advance(s: rawptr[ParseState]) -> t.CChar: - if s.pos >= s.len: - return '\0' - ch: t.CChar = s.src[s.pos] +def _advance(s: rawptr[ParseState]) -> char: + if s.pos >= s.len: return '\0' + ch: char = s.src[s.pos] s.pos += 1 return ch def _skip_whitespace(s: rawptr[ParseState]): while s.pos < s.len: - ch: t.CChar = s.src[s.pos] + ch: char = s.src[s.pos] if ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r': s.pos += 1 else: break -def _expect(s: rawptr[ParseState], ch: t.CChar) -> bool: +def _expect(s: rawptr[ParseState], ch: char) -> bool: _skip_whitespace(s) - if s.pos >= s.len: - return False - if s.src[s.pos] != ch: - return False + if s.pos >= s.len: return False + if s.src[s.pos] != ch: return False s.pos += 1 return True def _parse_string(s: rawptr[ParseState]) -> str: - if _peek(s) != '"': - return None + if _peek(s) != '"': return None _advance(s) - start: t.CSizeT = s.pos - slen: t.CSizeT = 0 + start: sizet = s.pos + slen: sizet = 0 while s.pos < s.len: - ch: t.CChar = s.src[s.pos] + ch: char = s.src[s.pos] if ch == '"': break if ch == '\\': @@ -74,16 +68,16 @@ def _parse_string(s: rawptr[ParseState]) -> str: return None s.pos = start - di: t.CSizeT = 0 + di: sizet = 0 while s.pos < s.len: - ch: t.CChar = s.src[s.pos] + ch: char = 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] + esc: char = s.src[s.pos] if esc == 'n': buf[di] = '\n' elif esc == 't': @@ -112,13 +106,13 @@ def _parse_string(s: rawptr[ParseState]) -> str: def _parse_number(s: rawptr[ParseState]) -> rawptr[JsonValue]: _skip_whitespace(s) is_float: bool = False - start: t.CSizeT = s.pos + start: sizet = 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] + ch: char = s.src[s.pos] if ch >= '0' and ch <= '9': s.pos += 1 else: @@ -128,7 +122,7 @@ def _parse_number(s: rawptr[ParseState]) -> rawptr[JsonValue]: is_float = True s.pos += 1 while s.pos < s.len: - ch: t.CChar = s.src[s.pos] + ch: char = s.src[s.pos] if ch >= '0' and ch <= '9': s.pos += 1 else: @@ -140,18 +134,18 @@ def _parse_number(s: rawptr[ParseState]) -> rawptr[JsonValue]: 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] + ch: char = s.src[s.pos] if ch >= '0' and ch <= '9': s.pos += 1 else: break - num_len: t.CSizeT = s.pos - start + num_len: sizet = s.pos - start buf: str = s.pool.alloc(num_len + 1) if buf == None: return null(s.pool) - i: t.CSizeT = 0 + i: sizet = 0 while i < num_len: buf[i] = s.src[start + i] i += 1 @@ -170,7 +164,7 @@ def _parse_value(s: rawptr[ParseState]) -> rawptr[JsonValue]: if s.pos >= s.len: return null(s.pool) - ch: t.CChar = _peek(s) + ch: char = _peek(s) if ch == '"': sv: str = _parse_string(s) @@ -214,6 +208,11 @@ def _parse_array(s: rawptr[ParseState]) -> rawptr[JsonValue]: return null(s.pool) arr: rawptr[JsonValue] = array(s.pool) + # 池耗尽 ⇒ array() 返回 None(JsonValue.__new__/null 的既有约定:分配失败返回 None)。 + # 若继续走到 arr._append_child(...) 就是空指针解引用 ⇒ 这里向上返回 None + # (与 json.parse 可能返回 None 的约定一致,调用方本就必须判 None)。 + if arr == None: + return null(s.pool) _skip_whitespace(s) if s.pos < s.len and _peek(s) == ']': @@ -221,6 +220,10 @@ def _parse_array(s: rawptr[ParseState]) -> rawptr[JsonValue]: return arr item: rawptr[JsonValue] = _parse_value(s) + # item == None ⟺ _parse_value 内部某处分配失败(_parse_value 对语法错误返回的是 + # 合法的 JSON_NULL 节点,只有池耗尽才是 None)⇒ 向上返回 None,不追加半条。 + if item == None: + return null(s.pool) arr._append_child(item) while True: @@ -231,6 +234,8 @@ def _parse_array(s: rawptr[ParseState]) -> rawptr[JsonValue]: break _advance(s) item = _parse_value(s) + if item == None: + return null(s.pool) arr._append_child(item) _expect(s, ']') @@ -242,6 +247,9 @@ def _parse_object(s: rawptr[ParseState]) -> rawptr[JsonValue]: return null(s.pool) obj: rawptr[JsonValue] = object(s.pool) + # 同 _parse_array:池耗尽时 obj 为 None,不能对 None 调 _append_child。 + if obj == None: + return null(s.pool) _skip_whitespace(s) if s.pos < s.len and _peek(s) == '}': @@ -253,7 +261,7 @@ def _parse_object(s: rawptr[ParseState]) -> rawptr[JsonValue]: _expect(s, ':') val: rawptr[JsonValue] = _parse_value(s) if key != None and val != None: - klen: t.CSizeT = string.strlen(key) + klen: sizet = string.strlen(key) kbuf: str = s.pool.alloc(klen + 1) if kbuf != None: string.memcpy(kbuf, key, klen + 1) @@ -272,7 +280,7 @@ def _parse_object(s: rawptr[ParseState]) -> rawptr[JsonValue]: _expect(s, ':') val = _parse_value(s) if key != None and val != None: - klen2: t.CSizeT = string.strlen(key) + klen2: sizet = string.strlen(key) kbuf2: str = s.pool.alloc(klen2 + 1) if kbuf2 != None: string.memcpy(kbuf2, key, klen2 + 1) diff --git a/json/__writer.vp b/json/__writer.vp index 5870268..f5c5ef5 100644 --- a/json/__writer.vp +++ b/json/__writer.vp @@ -1,119 +1,163 @@ -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: str, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT: - buf[pos] = ch - return pos + 1 - -def _write_str(buf: str, pos: t.CSizeT, s: str) -> 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: str, pos: t.CSizeT, s: str) -> 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: str, pos: t.CSizeT, val: rawptr[JsonValue], pool: rawptr[memhub.MemManager]) -> 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: str = 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: str = 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: rawptr[JsonValue] = 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: rawptr[JsonValue] = 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: rawptr[memhub.MemManager], val: rawptr[JsonValue], pretty: bool) -> str: - """将 JsonValue 序列化为 JSON 字符串""" - buf: str = pool.alloc(4096) - if buf == None: - return None - end_pos: t.CSizeT = _write_value(buf, 0, val, pool) - buf[end_pos] = '\0' - return buf +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, +) + + +# ============================================================ +# 容量约定(cap 只由调用方显式传入,签名里没有默认值) +# write —— 三参入口,固定用 WRITE_CAP_DEFAULT(4096)作容量。 +# write_cap —— 四参入口,容量由调用方显式传入。 +# cap = 输出缓冲总字节数(含结尾 NUL)。所有写入先判容量: +# 写 n 字节要求 pos + n <= cap - 1(末位留给 write 收尾的 '\0')。 +# 放不下时不写,并把 pos 置为"溢出标志" cap——此后任何写入都以 +# `pos >= cap` 短路返回,最终 write 判 `end_pos >= cap` 返回 None。 +# 即:内容超出容量时既不写穿缓冲,也不再继续写(绝不越界)。 +# cap 的合法区间是 [WRITE_CAP_MIN, WRITE_CAP_MAX]:越界一律返回 None, +# 非法容量不进入 pool.alloc(不会按可疑值去申请内存)。 +# ============================================================ +WRITE_CAP_MIN: t.CDefine = 64 # 下限:最短 JSON 文档(如 {"id":""})含结尾 NUL 也在 64 字节内 +WRITE_CAP_MAX: t.CDefine = 67108864 # 上限:64 MiB,不小于调用方可能申请的最大输出缓冲 +WRITE_CAP_DEFAULT: t.CDefine = 4096 # write 三参入口的固定容量(与旧实现 pool.alloc(4096) 一致) + +def _write_char(buf: str, pos: sizet, cap: sizet, ch: char) -> sizet: + if pos + 1 >= cap: + if pos >= cap: + return pos # 已带溢出标志:原样返回,不再写 + return cap # 留不出结尾 NUL 位 ⇒ 置溢出标志 + buf[pos] = ch + return pos + 1 + +def _write_str(buf: str, pos: sizet, cap: sizet, s: str) -> sizet: + if s == None: return pos + if pos >= cap: + return pos # 已带溢出标志:不再写 + slen: sizet = string.strlen(s) + if pos + slen >= cap: + return cap # 留不出结尾 NUL 位 ⇒ 置溢出标志 + string.memcpy(char(t.CUInt64T(buf) + pos, t.CPtr), s, slen) + return pos + slen + +def _write_string_escaped(buf: str, pos: sizet, cap: sizet, s: str) -> sizet: + if s == None: + pos = _write_str(buf, pos, cap, "null") + return pos + pos = _write_char(buf, pos, cap, '"') + if pos >= cap: + return pos # 已溢出:不再写 + i: sizet = 0 + slen: sizet = string.strlen(s) + while i < slen: + if pos >= cap: + return pos # 已溢出:提前收敛,不做无意义的逐字符空转 + ch: char = s[i] + if ch == '"': + pos = _write_str(buf, pos, cap, "\\\"") + elif ch == '\\': + pos = _write_str(buf, pos, cap, "\\\\") + elif ch == '\n': + pos = _write_str(buf, pos, cap, "\\n") + elif ch == '\r': + pos = _write_str(buf, pos, cap, "\\r") + elif ch == '\t': + pos = _write_str(buf, pos, cap, "\\t") + else: + pos = _write_char(buf, pos, cap, ch) + i += 1 + pos = _write_char(buf, pos, cap, '"') + return pos + + +def _write_value(buf: str, pos: sizet, cap: sizet, val: rawptr[JsonValue], + pool: rawptr[memhub.MemManager]) -> sizet: + if pos >= cap: + return pos # 已溢出:不再写(递归在此收敛) + if val == None: + pos = _write_str(buf, pos, cap, "null") + return pos + + if val.vtype == JSON_NULL: + pos = _write_str(buf, pos, cap, "null") + + elif val.vtype == JSON_BOOL: + if val.bool_val != 0: + pos = _write_str(buf, pos, cap, "true") + else: + pos = _write_str(buf, pos, cap, "false") + + elif val.vtype == JSON_INT: + tmp: str = pool.alloc(32) + if tmp != None: + snprintf(tmp, 32, "%lld", val.int_val) + pos = _write_str(buf, pos, cap, tmp) + + elif val.vtype == JSON_FLOAT: + tmp2: str = pool.alloc(32) + if tmp2 != None: + snprintf(tmp2, 32, "%.6g", val.float_val) + pos = _write_str(buf, pos, cap, tmp2) + + elif val.vtype == JSON_STRING: + pos = _write_string_escaped(buf, pos, cap, val.str_val) + + elif val.vtype == JSON_ARRAY: + if val.child == None: + pos = _write_str(buf, pos, cap, "[]") + return pos + pos = _write_char(buf, pos, cap, '[') + cur: rawptr[JsonValue] = val.child + first: bool = True + while cur != None: + if pos >= cap: + return pos # 已溢出:停止遍历,不再写 + if not first: + pos = _write_char(buf, pos, cap, ',') + pos = _write_value(buf, pos, cap, cur, pool) + first = False + cur = cur.next + pos = _write_char(buf, pos, cap, ']') + + elif val.vtype == JSON_OBJECT: + if val.child == None: + pos = _write_str(buf, pos, cap, "{}") + return pos + pos = _write_char(buf, pos, cap, '{') + cur2: rawptr[JsonValue] = val.child + first2: bool = True + while cur2 != None: + if pos >= cap: + return pos # 已溢出:停止遍历,不再写 + if not first2: + pos = _write_char(buf, pos, cap, ',') + pos = _write_string_escaped(buf, pos, cap, cur2.key) + pos = _write_char(buf, pos, cap, ':') + pos = _write_value(buf, pos, cap, cur2, pool) + first2 = False + cur2 = cur2.next + pos = _write_char(buf, pos, cap, '}') + + return pos + + +# 序列化为 JSON 字符串。cap = 输出缓冲容量(字节,含结尾 NUL),缺省 4096 +# (与旧实现 pool.alloc(4096) 一致 ⇒ 既有 3 参调用点行为不变)。 +# 内容放不下时返回 None(旧实现无边界判断,会写穿池块)。 +def write(pool: rawptr[memhub.MemManager], val: rawptr[JsonValue], pretty: bool, + cap: sizet = 4096) -> str: + """将 JsonValue 序列化为 JSON 字符串""" + if cap < 2: + return None # 连结尾 NUL 都放不下 + buf: str = pool.alloc(cap) + if buf == None: + return None + end_pos: sizet = _write_value(buf, 0, cap, val, pool) + if end_pos >= cap: + return None # 溢出标志:内容超出容量 + buf[end_pos] = '\0' + return buf + \ No newline at end of file diff --git a/linkedlist.vp b/linkedlist.vp index 770a6ee..5841e97 100644 --- a/linkedlist.vp +++ b/linkedlist.vp @@ -1,9 +1,5 @@ -import t, c -from stdint import * - - # ============================================================ -# LinkedNode: Non-polymorphic base class (@t.NoVTable) +# LinkedNode: Non-polymorphic base class novirtual # # Subclasses inheriting from this class gain standard linked list and tree capabilities: # - Bidirectional sibling links (next/prev) → O(1) removal @@ -17,22 +13,21 @@ from stdint import * # # Usage: # class MyNode(LinkedNode): -# value: t.CInt +# value: int # root: MyNode = MyNode() # child: MyNode = MyNode() # root.append(child) # OOP invocation, self = root # child.detach() # Remove self from sibling chain # ============================================================ -@t.NoVTable -class LinkedNode: - next: "LinkedNode" | t.CPtr # Next sibling node - prev: "LinkedNode" | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) - child: "LinkedNode" | t.CPtr # First child node - last_child: "LinkedNode" | t.CPtr # Last child node (O(1) append) - parent: "LinkedNode" | t.CPtr # Parent node - child_count: t.CSizeT # Number of child nodes +novirtual class LinkedNode: + next: LinkedNode* # Next sibling node + prev: LinkedNode* # Previous sibling node (doubly linked list, O(1) removal) + child: LinkedNode* # First child node + last_child: LinkedNode* # Last child node (O(1) append) + parent: LinkedNode* # Parent node + child_count: sizet # Number of child nodes - def append(self, node: "LinkedNode" | t.CPtr): + def append(self, node: LinkedNode*): """Append node as the last child of self (O(1)). If node is already attached to any list, the caller shall invoke node.detach() prior to append. @@ -41,96 +36,73 @@ class LinkedNode: 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 + 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): + def prepend(self, node: LinkedNode*): """Insert node as the first child of self (O(1)).""" if self is None or node is None: return node.parent = self node.prev = None node.next = self.child - if self.child is not None: - self.child.prev = node - else: - self.last_child = node + 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): + def insert_before(self, node: LinkedNode*, new_node: LinkedNode*): """Insert new_node before node (O(1)). node must be a direct child of self.""" if self is None or node is None or new_node is None: return new_node.parent = self new_node.prev = node.prev new_node.next = node - if node.prev is not None: - node.prev.next = new_node - else: - self.child = new_node + 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): + def insert_after(self, node: LinkedNode*, new_node: LinkedNode*): """Insert new_node after node (O(1)). node must be a direct child of self.""" if self is None or node is None or new_node is None: return new_node.parent = self new_node.prev = node new_node.next = node.next - if node.next is not None: - node.next.prev = new_node - else: - self.last_child = new_node + 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): + def remove_child(self, node: LinkedNode*): """Remove node from self's child linked list (O(1)). The node must be a direct child of self.""" - if self is None or node is None: - return + if self is None or node is None: return # Patch prev.next - if node.prev is not None: - node.prev.next = node.next - else: - self.child = node.next + if node.prev is not None: node.prev.next = node.next + else: self.child = node.next # Patch next.prev - if node.next is not None: - node.next.prev = node.prev - else: - self.last_child = node.prev + if node.next is not None: node.next.prev = node.prev + else: self.last_child = node.prev # Clear sibling and parent links of node node.next = None node.prev = None node.parent = None - if self.child_count > 0: - self.child_count -= 1 + if self.child_count > 0: self.child_count -= 1 def detach(self): """Detach self from its sibling linked list (O(1)). After invocation, self.next/self.prev/self.parent are cleared. The child chain remains untouched. """ - if self is None: - return + if self is None: return # Patch prev.next - if self.prev is not None: - self.prev.next = self.next - elif self.parent is not None: - self.parent.child = self.next + if self.prev is not None: self.prev.next = self.next + elif self.parent is not None: self.parent.child = self.next # Patch next.prev - if self.next is not None: - self.next.prev = self.prev - elif self.parent is not None: - self.parent.last_child = self.prev + if self.next is not None: self.next.prev = self.prev + elif self.parent is not None: self.parent.last_child = self.prev # Decrement parent child counter - if self.parent is not None: - if self.parent.child_count > 0: - self.parent.child_count -= 1 + if self.parent is not None and self.parent.child_count > 0: self.parent.child_count -= 1 # Clear links of self self.next = None self.prev = None @@ -143,8 +115,7 @@ class LinkedNode: (the parent field of child nodes still points to self). For full isolation, the caller shall invoke self.remove_child on each child beforehand. """ - if self is None: - return + if self is None: return # First detach from sibling list self.detach() # Then break parent-child links @@ -152,56 +123,52 @@ class LinkedNode: self.last_child = None self.child_count = 0 - def has_children(self) -> t.CInt: + def has_children(self) -> int: """Return 1 if child nodes exist, otherwise return 0.""" - if self is None: - return 0 - if self.child is not None: - return 1 + 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: + def child_at(self, index: sizet) -> LinkedNode*: """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" - if self is None: - return None - cur: "LinkedNode" | t.CPtr = self.child - i: t.CSizeT = 0 + if self is None: return None + cur: LinkedNode* = self.child + i: sizet = 0 while cur is not None: - if i == index: - return cur + if i == index: return cur i += 1 cur = cur.next return None - def count_children(self) -> t.CSizeT: + def count_children(self) -> sizet: """Count children by traversal (O(n)), used to validate child_count.""" if self is None: return 0 - n: t.CSizeT = 0 - cur: "LinkedNode" | t.CPtr = self.child + n: sizet = 0 + cur: LinkedNode* = self.child while cur is not None: n += 1 cur = cur.next return n - def first_sibling(self) -> "LinkedNode" | t.CPtr: + def first_sibling(self) -> LinkedNode*: """Return the head node of sibling linked list (traverse backward via prev pointers).""" if self is None: return None - cur: "LinkedNode" | t.CPtr = self + cur: LinkedNode* = self while cur.prev is not None: cur = cur.prev return cur - def last_sibling(self) -> "LinkedNode" | t.CPtr: + def last_sibling(self) -> LinkedNode*: """Return the tail node of sibling linked list (traverse forward via next pointers).""" if self is None: return None - cur: "LinkedNode" | t.CPtr = self + cur: LinkedNode* = self while cur.next is not None: cur = cur.next return cur # ============================================================ -# SListNode: Singly linked list node (@t.NoVTable) +# SListNode: Singly linked list node novirtual # # Lightweight singly linked list with only Next pointer. No prev/parent/child. # Suitable for queues, stacks and simple linked structures @@ -209,74 +176,65 @@ class LinkedNode: # O(1) append requires caller to maintain tail pointer (append_after). # O(n) append works with head pointer only (append). # ============================================================ -@t.NoVTable -class SListNode: - Next: "SListNode" | t.CPtr # Next node +novirtual class SListNode: + Next: SListNode* # Next node - def append(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + def append(self, node: SListNode*) -> SListNode*: """Append node to the end of the linked list (O(n)). Return self (head). If self is None, the caller shall adopt node directly as the new head. """ - if self is None: - return node - if node is None: - return self + if self is None: return node + if node is None: return self node.Next = None - cur: "SListNode" | t.CPtr = self + cur: SListNode* = 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: + def append_after(self, node: SListNode*) -> SListNode*: """Insert node immediately after self (O(1)). Return new tail (node). Caller must maintain the head pointer manually. Return node as head if self is None. """ - if node is None: - return self + if node is None: return self node.Next = None - if self is not None: - self.Next = node + if self is not None: self.Next = node return node - def count(self) -> t.CSizeT: + def count(self) -> sizet: """Calculate list length via full traversal (O(n)).""" - if self is None: - return 0 - n: t.CSizeT = 0 - cur: "SListNode" | t.CPtr = self + if self is None: return 0 + n: sizet = 0 + cur: SListNode* = self while cur is not None: n += 1 cur = cur.Next return n - def at(self, index: t.CSizeT) -> "SListNode" | t.CPtr: + def at(self, index: sizet) -> SListNode*: """Return node at zero-based index (O(n)). Return None if index out of bounds.""" - if self is None: - return None - cur: "SListNode" | t.CPtr = self - i: t.CSizeT = 0 + if self is None: return None + cur: SListNode* = self + i: sizet = 0 while cur is not None: - if i == index: - return cur + if i == index: return cur i += 1 cur = cur.Next return None - def remove(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + def remove(self, node: SListNode*) -> SListNode*: """Remove node from list (O(n)). Return updated head. The Next pointer of node will be cleared. If node is the original head, return head.Next. """ - if self is None or node is None: - return self + if self is None or node is None: return self if self is node: - new_head: "SListNode" | t.CPtr = self.Next + new_head: SListNode* = self.Next self.Next = None return new_head - cur: "SListNode" | t.CPtr = self + cur: SListNode* = self while cur.Next is not None: if cur.Next is node: cur.Next = node.Next @@ -287,43 +245,41 @@ class SListNode: # ============================================================ -# GSListNode[T]: Generic singly linked list node (@t.NoVTable + PEP 695 generics) +# GSListNode[T]: Generic singly linked list node (novirtual + PEP 695 generics) # -# Unlike SListNode (non-generic, Next: SListNode|t.CPtr), the Next field of GSListNode[T] -# is typed as T|t.CPtr. After specialization it becomes a concrete node type directly, +# Unlike SListNode (non-generic, Next: SListNode*), the Next field of GSListNode[T] +# is typed as T*. After specialization it becomes a concrete node type directly, # eliminating downcasts. # # Recursive generic usage pattern (subclass inherits from self-specialized variant): # class GNode(GSListNode[GNode]): -# value: t.CInt -# # At this point GNode.Next: GNode|t.CPtr (strongly typed, no casting required) +# value: int +# # At this point GNode.Next: GNode* (strongly typed, no casting required) # # Technical validation targets: # 1. Recursive generics: class GNode(GSListNode[GNode]) -# 2. Combination of @t.NoVTable attribute with generics +# 2. Combination of novirtual attribute with generics # 3. Generic class used as field type: list: GSList[GNode] # 4. Inheritance of generic methods (GSList[T].append available after specialization) # ============================================================ -@t.NoVTable -class GSListNode[T]: - Next: T | t.CPtr +novirtual class GSListNode[T]: + Next: T* # ============================================================ -# GSList[T]: Generic singly linked list container (@t.NoVTable + PEP 695 generics) +# GSList[T]: Generic singly linked list container (novirtual + PEP 695 generics) # # Holds Head, Tail and Count. Provides O(1) append and O(n) indexed access. # Node type T must inherit from GSListNode[T] (to acquire the Next field). # # Usage: -# list: GSList[GNode] | t.CPtr = GSList[GNode]() +# list: GSList[GNode]* = GSList[GNode]() # list.append(node) # Method invocation, not free function # ============================================================ -@t.NoVTable -class GSList[T]: - Head: T | t.CPtr - Tail: T | t.CPtr - Count: t.CSizeT +novirtual class GSList[T]: + Head: T* + Tail: T* + Count: sizet def __init__(self): self.Head = None @@ -342,16 +298,16 @@ class GSList[T]: self.Tail = node self.Count += 1 - def count(self) -> t.CSizeT: + def count(self) -> sizet: """Return node count (O(1)).""" return self.Count - def at(self, index: t.CSizeT) -> T | t.CPtr: + def at(self, index: sizet) -> T*: """Return node at zero-based index (O(n)). Return None if index out of bounds.""" if self.Head is None: return None - cur: T | t.CPtr = self.Head - i: t.CSizeT = 0 + cur: T* = self.Head + i: sizet = 0 while cur is not None: if i == index: return cur @@ -361,39 +317,37 @@ class GSList[T]: # ============================================================ -# GTreeNode[T]: Generic tree node (@t.NoVTable + PEP 695 generics) +# GTreeNode[T]: Generic tree node (novirtual + PEP 695 generics) # -# Type-safe variant of LinkedNode. All pointer fields are typed T|t.CPtr. +# Type-safe variant of LinkedNode. All pointer fields are typed T*. # Capabilities provided: # - Bidirectional sibling linked list (Next/Prev) → O(1) removal # - Parent-child tree structure (Child/LastChild/Parent) → O(1) child appending # - Child counter (Count) # # Recursive generic usage pattern (subclass inherits self-specialized variant): -# @t.CVTable -# class AST(GTreeNode[AST]): -# def kind(self) -> t.CInt: +# virtual class AST(GTreeNode[AST]): +# def kind(self) -> int: # return 0 -# # At this point AST.Next/Prev/Child/LastChild/Parent are all AST|t.CPtr (strongly typed) +# # At this point AST.Next/Prev/Child/LastChild/Parent are all AST* (strongly typed) # # Fields are flattened and embedded into subclasses with no vtable overhead # (equivalent to non-polymorphic inheritance in C++). -# If a subclass is marked @t.CVTable, it receives its own vtable (at offset 0), +# If a subclass is marked virtual, it receives its own vtable (at offset 0), # and GTreeNode fields are laid out after the vtable. # # OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers # (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. # ============================================================ -@t.NoVTable -class GTreeNode[T]: - Next: T | t.CPtr # Next sibling node - Prev: T | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) - Child: T | t.CPtr # First child node - LastChild: T | t.CPtr # Last child node (O(1) append) - Parent: T | t.CPtr # Parent node - Count: t.CSizeT # Number of child nodes +novirtual class GTreeNode[T]: + Next: T* # Next sibling node + Prev: T* # Previous sibling node (doubly linked list, O(1) removal) + Child: T* # First child node + LastChild: T* # Last child node (O(1) append) + Parent: T* # Parent node + Count: sizet # Number of child nodes - def append(self, node: T | t.CPtr): + def append(self, node: T*): """Append node as the last child of self (O(1)). If node is already attached to any list, the caller shall invoke node.detach() prior to append. @@ -403,24 +357,20 @@ class GTreeNode[T]: node.Parent = self node.Next = None node.Prev = self.LastChild - if self.Child is None: - self.Child = node - else: - self.LastChild.Next = node + 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): + def prepend(self, node: T*): """Insert node as the first child of self (O(1)).""" if self is None or node is None: return node.Parent = self node.Prev = None node.Next = self.Child - if self.Child is not None: - self.Child.Prev = node - else: - self.LastChild = node + if self.Child is not None: self.Child.Prev = node + else: self.LastChild = node self.Child = node self.Count += 1 @@ -429,50 +379,38 @@ class GTreeNode[T]: After invocation, self.Next/self.Prev/self.Parent are cleared. The child chain remains untouched. """ - if self is None: - return - if self.Prev is not None: - self.Prev.Next = self.Next - elif self.Parent is not None: - self.Parent.Child = self.Next - if self.Next is not None: - self.Next.Prev = self.Prev - elif self.Parent is not None: - self.Parent.LastChild = self.Prev - if self.Parent is not None: - if self.Parent.Count > 0: - self.Parent.Count -= 1 + 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 and self.Parent.Count > 0: self.Parent.Count -= 1 self.Next = None self.Prev = None self.Parent = None - def has_children(self) -> t.CInt: + def has_children(self) -> int: """Return 1 if child nodes exist, otherwise return 0.""" - if self is None: - return 0 - if self.Child is not None: - return 1 + 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: + def child_at(self, index: sizet) -> T*: """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" - if self is None: - return None - cur: T | t.CPtr = self.Child - i: t.CSizeT = 0 + if self is None: return None + cur: T* = self.Child + i: sizet = 0 while cur is not None: - if i == index: - return cur + if i == index: return cur i += 1 cur = cur.Next return None - def count_children(self) -> t.CSizeT: + def count_children(self) -> sizet: """Count children by traversal (O(n)), used to validate Count field.""" - if self is None: - return 0 - n: t.CSizeT = 0 - cur: T | t.CPtr = self.Child + if self is None: return 0 + n: sizet = 0 + cur: T* = self.Child while cur is not None: n += 1 cur = cur.Next diff --git a/llvmlite/__builder.vp b/llvmlite/__builder.vp index a295a58..5100386 100644 --- a/llvmlite/__builder.vp +++ b/llvmlite/__builder.vp @@ -28,9 +28,8 @@ from .__function import Function, BasicBlock, block_append_text, block_set_termi # 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=32 保持一致 # (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。 # ============================================================ -@t.NoVTable -class IRBuilder: - Pool: rawptr[memhub.MemBuddy] # 内存池 +novirtual class IRBuilder: + Pool: memhub.MemBuddy* # 内存池 Func: rawptr[Function] # 所属函数 CurBlock: rawptr[BasicBlock] # 当前插入点 Counter: int # SSA 名计数器 @@ -40,7 +39,7 @@ class IRBuilder: # ============================================================ def _alloc_ssa_name(self) -> str: """分配一个 SSA 名字符串 "%N" 并递增计数器""" - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool buf: str = pool.alloc(16) if buf is None: return None viperlib.snprintf(buf, 16, "%%%d", self.Counter) @@ -54,7 +53,7 @@ class IRBuilder: 注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节, 必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。 """ - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool buf: str = pool.alloc(512) if buf is None: return None buf[0] = '\0' @@ -91,7 +90,7 @@ class IRBuilder: lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: """二元运算通用实现""" if self is None or lhs is None or rhs is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(lhs.Ty) line: str = pool.alloc(256) @@ -139,7 +138,7 @@ class IRBuilder: 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 """ if self is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(ty) line: str = pool.alloc(128) @@ -164,7 +163,7 @@ class IRBuilder: align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 """ if self is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(ty) line: str = pool.alloc(128) @@ -188,7 +187,7 @@ class IRBuilder: 导致的支配性违规(Instruction does not dominate all uses)。 """ if self is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool func: rawptr[Function] = self.Func if func is None or func.Blocks is None: return self.build_alloca(ty) @@ -217,29 +216,46 @@ class IRBuilder: def build_load(self, ty: rawptr[LLVMType], - ptr: rawptr[Value]) -> rawptr[Value]: - """%N = load , """ + ptr: rawptr[Value], + is_volatile: int = 0) -> rawptr[Value]: + """%N = load [volatile ], + + is_volatile=0(默认)逐字输出既有形态;=1 时在 load 后插入 volatile + 限定符(`%N = load volatile i32, i32* %p`),供自旋锁等必须禁止 + 优化器提升/合并重复访问的场景使用。 + """ if self is None or ptr is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(ty) ptr_ty_s: str = self._type_str(ptr.Ty) line: str = pool.alloc(256) if line is None: return None - viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) + if is_volatile != 0: + viperlib.snprintf(line, 256, "%s = load volatile %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) + else: + viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) self._emit(line) return SSAValue(pool, ty, name) - def build_store(self, val: rawptr[Value], ptr: rawptr[Value]): - """store , """ + def build_store(self, val: rawptr[Value], ptr: rawptr[Value], + is_volatile: int = 0): + """store [volatile ] , + + is_volatile=0(默认)逐字输出既有形态;=1 时在 store 后插入 volatile + 限定符(`store volatile i32 %v, i32* %p`)。 + """ if self is None or val is None or ptr is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool val_ty_s: str = self._type_str(val.Ty) ptr_ty_s: str = self._type_str(ptr.Ty) line: str = pool.alloc(256) if line is None: return - viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) + if is_volatile != 0: + viperlib.snprintf(line, 256, "store volatile %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) + else: + viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) self._emit(line) @@ -360,7 +376,7 @@ class IRBuilder: def build_fneg(self, val: rawptr[Value]) -> rawptr[Value]: """%N = fneg """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(val.Ty) line: str = pool.alloc(128) @@ -380,7 +396,7 @@ class IRBuilder: 返回类型为 i1 的 SSA 值 """ if self is None or lhs is None or rhs is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(lhs.Ty) pred_s: str = _icmp_pred_str(pred) @@ -404,7 +420,7 @@ class IRBuilder: 返回类型为 i1 的 SSA 值 """ if self is None or lhs is None or rhs is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(lhs.Ty) pred_s: str = _fcmp_pred_str(pred) @@ -427,7 +443,7 @@ class IRBuilder: def build_br(self, target: rawptr[BasicBlock]): """br label %""" if self is None or target is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool line: str = pool.alloc(64) if line is None: return viperlib.snprintf(line, 64, "br label %%%s", target.Name) @@ -439,7 +455,7 @@ class IRBuilder: then_blk: rawptr[BasicBlock], else_blk: rawptr[BasicBlock]): """br i1 , label %, label %""" if self is None or cond is None or then_blk is None or else_blk is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool line: str = pool.alloc(128) if line is None: return viperlib.snprintf(line, 128, "br i1 %s, label %%%s, label %%%s", @@ -451,7 +467,7 @@ class IRBuilder: def build_ret(self, val: rawptr[Value]): """ret """ if self is None or val is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool ty_s: str = self._type_str(val.Ty) line: str = pool.alloc(128) if line is None: return @@ -463,7 +479,7 @@ class IRBuilder: def build_ret_void(self): """ret void""" if self is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool line: str = pool.alloc(16) if line is None: return string.strcpy(line, "ret void") @@ -485,7 +501,7 @@ class IRBuilder: is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 """ if self is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool # 判断返回类型是否为 void is_void: int = 0 @@ -570,7 +586,7 @@ class IRBuilder: 间接调用:callee_val 是函数指针 SSA 值。 """ if self is None or callee_val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool is_void: int = 0 match ret_ty: @@ -623,7 +639,7 @@ class IRBuilder: """%N = bitcast to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -641,7 +657,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = sext to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -656,7 +672,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = trunc to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -671,7 +687,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = zext to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -686,7 +702,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = ptrtoint to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -701,7 +717,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = inttoptr to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -719,7 +735,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = fpext to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -734,7 +750,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = fptrunc to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -749,7 +765,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = fptosi to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -764,7 +780,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = sitofp to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -779,7 +795,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = fptoui to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -794,7 +810,7 @@ class IRBuilder: to_ty: rawptr[LLVMType]) -> rawptr[Value]: """%N = uitofp to """ if self is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() from_ty_s: str = self._type_str(val.Ty) to_ty_s: str = self._type_str(to_ty) @@ -818,7 +834,7 @@ class IRBuilder: # 直接 GEP 会导致 llc 编译失败 if _is_ptr_type(ptr.Ty) == 0: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() elem_ty_s: str = self._type_str(elem_ty) ptr_ty_s: str = self._type_str(ptr.Ty) @@ -848,7 +864,7 @@ class IRBuilder: 结果类型是 elem_ty* """ if self is None or ptr is None or idx is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() array_ty_s: str = self._type_str(array_ty) ptr_ty_s: str = self._type_str(ptr.Ty) @@ -878,7 +894,7 @@ class IRBuilder: 结果类型是 field_ty* """ if self is None or ptr is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() struct_ty_s: str = self._type_str(struct_ty) ptr_ty_s: str = self._type_str(ptr.Ty) @@ -913,7 +929,7 @@ class IRBuilder: incoming_head 是 PhiIncoming 链表头,count 是入边数量。 """ if self is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(ty) @@ -959,7 +975,7 @@ class IRBuilder: cases_head: rawptr[SwitchCase], case_count: int): """switch , label % [, label % ...]""" if self is None or val is None or default_blk is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool ty_s: str = self._type_str(val.Ty) # 构建主体: switch , label %default @@ -1000,7 +1016,7 @@ class IRBuilder: true_val: rawptr[Value], false_val: rawptr[Value]) -> rawptr[Value]: """%N = select i1 , , """ if self is None or cond is None or true_val is None or false_val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ty_s: str = self._type_str(true_val.Ty) line: str = pool.alloc(256) @@ -1017,7 +1033,7 @@ class IRBuilder: def build_unreachable(self): """unreachable""" if self is None: return - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool line: str = pool.alloc(16) if line is None: return string.strcpy(line, "unreachable") @@ -1033,7 +1049,7 @@ class IRBuilder: order: int) -> rawptr[Value]: """%N = atomicrmw , """ if self is None or ptr is None or val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ptr_ty_s: str = self._type_str(ptr.Ty) val_ty_s: str = self._type_str(val.Ty) @@ -1055,7 +1071,7 @@ class IRBuilder: 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) """ if self is None or ptr is None or cmp_val is None or new_val is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() ptr_ty_s: str = self._type_str(ptr.Ty) cmp_ty_s: str = self._type_str(cmp_val.Ty) @@ -1081,7 +1097,7 @@ class IRBuilder: """%N = va_arg , """ if self is None or va_list_ptr is None or arg_ty is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool name: str = self._alloc_ssa_name() va_list_ty_s: str = self._type_str(va_list_ptr.Ty) arg_ty_s: str = self._type_str(arg_ty) @@ -1106,7 +1122,7 @@ class IRBuilder: 简化的内联汇编调用,无参数版本。 """ if self is None: return None - pool: rawptr[memhub.MemBuddy] = self.Pool + pool: memhub.MemBuddy* = self.Pool # 判断返回类型是否为 void is_void: int = 0 @@ -1151,7 +1167,7 @@ class IRBuilder: # IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) = 32 字节 BUILDER_SIZE: t.CDefine = 32 -def new_builder(pool: rawptr[memhub.MemBuddy], func: rawptr[Function]) -> rawptr[IRBuilder]: +def new_builder(pool: memhub.MemBuddy*, func: rawptr[Function]) -> rawptr[IRBuilder]: """创建 IRBuilder,关联到函数 func""" ptr: rawptr[IRBuilder] = pool.alloc(BUILDER_SIZE) if ptr is None: return None @@ -1245,14 +1261,16 @@ def build_alloca_at_entry(builder: rawptr[IRBuilder], ty: rawptr[LLVMType]) -> r def build_load(builder: rawptr[IRBuilder], ty: rawptr[LLVMType], - ptr: rawptr[Value]) -> rawptr[Value]: - """%N = load , """ - return builder.build_load(ty, ptr) + ptr: rawptr[Value], + is_volatile: int = 0) -> rawptr[Value]: + """%N = load [volatile ], """ + return builder.build_load(ty, ptr, is_volatile) -def build_store(builder: rawptr[IRBuilder], val: rawptr[Value], ptr: rawptr[Value]): - """store , """ - builder.build_store(val, ptr) +def build_store(builder: rawptr[IRBuilder], val: rawptr[Value], ptr: rawptr[Value], + is_volatile: int = 0): + """store [volatile ] , """ + builder.build_store(val, ptr, is_volatile) # ============================================================ @@ -1651,8 +1669,7 @@ def build_gep_struct(builder: rawptr[IRBuilder], struct_ty: rawptr[LLVMType], # # 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 # ============================================================ -@t.NoVTable -class PhiIncoming(GSListNode[PhiIncoming]): +novirtual class PhiIncoming(GSListNode[PhiIncoming]): Val: rawptr[Value] Block: rawptr[BasicBlock] @@ -1660,7 +1677,7 @@ class PhiIncoming(GSListNode[PhiIncoming]): # PhiIncoming 硬编码大小: Next(8) + Val(8) + Block(8) = 24 字节 PHIINC_SIZE: t.CDefine = 24 -def new_phi_incoming(pool: rawptr[memhub.MemBuddy], +def new_phi_incoming(pool: memhub.MemBuddy*, val: rawptr[Value], block: rawptr[BasicBlock]) -> rawptr[PhiIncoming]: ptr: rawptr[PhiIncoming] = pool.alloc(PHIINC_SIZE) if ptr is None: return None @@ -1687,8 +1704,7 @@ def build_phi(builder: rawptr[IRBuilder], ty: rawptr[LLVMType], # # 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 # ============================================================ -@t.NoVTable -class SwitchCase(GSListNode[SwitchCase]): +novirtual class SwitchCase(GSListNode[SwitchCase]): CaseVal: rawptr[Value] Block: rawptr[BasicBlock] @@ -1696,7 +1712,7 @@ class SwitchCase(GSListNode[SwitchCase]): # SwitchCase 硬编码大小: Next(8) + CaseVal(8) + Block(8) = 24 字节 SWCASE_SIZE: t.CDefine = 24 -def new_switch_case(pool: rawptr[memhub.MemBuddy], +def new_switch_case(pool: memhub.MemBuddy*, case_val: rawptr[Value], block: rawptr[BasicBlock]) -> rawptr[SwitchCase]: ptr: rawptr[SwitchCase] = pool.alloc(SWCASE_SIZE) if ptr is None: return None @@ -1831,13 +1847,13 @@ def build_inline_asm(builder: rawptr[IRBuilder], ret_ty: rawptr[LLVMType], # 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 # 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 _g_last_dst: t.CUInt64T = 0 -_g_last_pos: t.CSizeT = 0 +_g_last_pos: sizet = 0 -def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): +def _append_cstr(dst: str, dst_size: sizet, src: str): """将 C 字符串 src 追加到 dst 末尾""" global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = 0 + dlen: sizet = 0 if _g_last_dst == t.CUInt64T(dst): dlen = _g_last_pos # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 @@ -1857,10 +1873,10 @@ def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: return - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen if remain <= 0: return - i: t.CSizeT = 0 + i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 diff --git a/llvmlite/__function.vp b/llvmlite/__function.vp index 6b1016a..7902a7d 100644 --- a/llvmlite/__function.vp +++ b/llvmlite/__function.vp @@ -30,10 +30,9 @@ G_PeepEnable: bool = True # 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位, # 所有字段访问读取垃圾值(见续 XV 会话根因分析)。 # ============================================================ -@t.NoVTable -class Line(GSListNode[Line]): +novirtual class Line(GSListNode[Line]): Buf: str # 行文本(NUL 结尾) - Len: t.CSizeT # 文本长度(不含 NUL) + Len: sizet # 文本长度(不含 NUL) # ============================================================ @@ -45,8 +44,7 @@ class Line(GSListNode[Line]): # # 注意: 必须加 @t.NoVTable(理由同 Line)。 # ============================================================ -@t.NoVTable -class BasicBlock(GSListNode[BasicBlock]): +novirtual class BasicBlock(GSListNode[BasicBlock]): Name: str # 块名(如 "entry"/"if.then") Lines: rawptr[GSList[Line]] # 指令行链表容器(Head/Tail/Count) IsTerminated: int # 1=已有终止指令(br/ret) @@ -60,8 +58,7 @@ class BasicBlock(GSListNode[BasicBlock]): # # 注意: 必须加 @t.NoVTable(理由同 Line)。 # ============================================================ -@t.NoVTable -class Param(GSListNode[Param]): +novirtual class Param(GSListNode[Param]): Ty: rawptr[LLVMType] # 参数类型 Name: str # 参数名(如 "%0"/"%a") Attrs: str # 参数属性文本(None=无属性) @@ -77,8 +74,7 @@ class Param(GSListNode[Param]): # # 注意: 必须加 @t.NoVTable(理由同 Line)。 # ============================================================ -@t.NoVTable -class Function(GSListNode[Function]): +novirtual class Function(GSListNode[Function]): Name: str # 函数名 RetTy: rawptr[LLVMType] # 返回类型 Params: rawptr[GSList[Param]] # 参数链表容器 @@ -88,7 +84,7 @@ class Function(GSListNode[Function]): Attrs: str # 函数属性文本(None=无属性) AttrGroup: str # 字符串属性组内容(如 '"section"=".text.startup"',None=无) AttrGroupId: int # 属性组编号(>0 时函数行输出 #N,模块尾输出 attributes #N) - NameLen: t.CSizeT # 函数名长度(创建时一次算好,恒等于 strlen(Name);追加在末尾,既有字段偏移不变) + NameLen: sizet # 函数名长度(创建时一次算好,恒等于 strlen(Name);追加在末尾,既有字段偏移不变) # ============================================================ @@ -97,13 +93,13 @@ class Function(GSListNode[Function]): # Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节 LINE_SIZE: t.CDefine = 24 -def new_line(pool: rawptr[memhub.MemBuddy], text: str) -> rawptr[Line]: +def new_line(pool: memhub.MemBuddy*, text: str) -> rawptr[Line]: """创建一个指令行,复制 text 到新分配的缓冲区""" ptr: rawptr[Line] = 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) + slen: sizet = string.strlen(text) buf: str = pool.alloc(slen + 1) if buf is not None: string.strcpy(buf, text) @@ -112,7 +108,7 @@ def new_line(pool: rawptr[memhub.MemBuddy], text: str) -> rawptr[Line]: return ptr -def _new_gslist(pool: rawptr[memhub.MemBuddy], list_size: t.CSizeT) -> t.CPtr: +def _new_gslist(pool: memhub.MemBuddy*, list_size: sizet) -> t.CPtr: """从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)""" gsl: t.CPtr = pool.alloc(list_size) if gsl is None: return None @@ -123,7 +119,7 @@ def _new_gslist(pool: rawptr[memhub.MemBuddy], list_size: t.CSizeT) -> t.CPtr: # BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节 BLOCK_SIZE: t.CDefine = 32 -def new_basic_block(pool: rawptr[memhub.MemBuddy], name: str) -> rawptr[BasicBlock]: +def new_basic_block(pool: memhub.MemBuddy*, name: str) -> rawptr[BasicBlock]: """创建一个基本块""" ptr: rawptr[BasicBlock] = pool.alloc(BLOCK_SIZE) if ptr is None: return None @@ -137,7 +133,7 @@ def new_basic_block(pool: rawptr[memhub.MemBuddy], name: str) -> rawptr[BasicBlo # Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节 PARAM_SIZE: t.CDefine = 32 -def new_param(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], +def new_param(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], name: str) -> rawptr[Param]: """创建一个函数参数""" ptr: rawptr[Param] = pool.alloc(PARAM_SIZE) @@ -152,7 +148,7 @@ def new_param(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], # Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) + AttrGroup(8) + AttrGroupId(8) + NameLen(8) = 80 字节 FUNC_SIZE: t.CDefine = 80 -def new_function(pool: rawptr[memhub.MemBuddy], name: str, +def new_function(pool: memhub.MemBuddy*, name: str, ret_ty: rawptr[LLVMType]) -> rawptr[Function]: """创建一个函数""" ptr: rawptr[Function] = pool.alloc(FUNC_SIZE) @@ -262,7 +258,7 @@ def block_get_terminated(block: rawptr[BasicBlock]) -> int: return block.IsTerminated -def block_append_text(pool: rawptr[memhub.MemBuddy], block: rawptr[BasicBlock], +def block_append_text(pool: memhub.MemBuddy*, block: rawptr[BasicBlock], text: str): """创建指令行并追加到基本块""" if block is None or text is None: return @@ -271,7 +267,7 @@ def block_append_text(pool: rawptr[memhub.MemBuddy], block: rawptr[BasicBlock], block_append_line(block, line) -def block_insert_text_before_terminator(pool: rawptr[memhub.MemBuddy], +def block_insert_text_before_terminator(pool: memhub.MemBuddy*, block: rawptr[BasicBlock], text: str): """创建指令行并插入到基本块终止指令之前 @@ -362,13 +358,13 @@ def _ll_name_needs_quote(name: str) -> int: """ if name is None: return 0 - c0: t.CChar = name[0] + c0: char = name[0] if c0 >= '0' and c0 <= '9': return 1 - name_len: t.CSizeT = string.strlen(name) - i: t.CSizeT = 0 + name_len: sizet = string.strlen(name) + i: sizet = 0 while i < name_len: - ch: t.CChar = name[i] + ch: char = name[i] # 合法字符:a-z, A-Z, 0-9, -, $, ., _ if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or (ch >= '0' and ch <= '9') or ch == '-' or ch == '$' or @@ -402,10 +398,10 @@ def _ll_name_needs_quote(name: str) -> int: # ============================================================ # 判定字符是否为十进制数字 -def _is_digit_ch(ch: t.CChar) -> int: +def _is_digit_ch(ch: char) -> int: """判断字符是否是 '0'-'9' - ch 是值类型 (t.CChar = i8),TPC 已修复值类型 is None 处理: + ch 是值类型 (char = i8),TPC 已修复值类型 is None 处理: 值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。 """ if ch is None: @@ -473,7 +469,7 @@ def _find_max_ssa_number(func: rawptr[Function]) -> int: return max_n blocks: rawptr[GSList[BasicBlock]] = func.Blocks blk: rawptr[BasicBlock] = blocks.Head - blk_steps: t.CSizeT = 0 + blk_steps: sizet = 0 while blk is not None: blk_steps += 1 if blk_steps > IR_DUMP_CHAIN_LIMIT: @@ -482,7 +478,7 @@ def _find_max_ssa_number(func: rawptr[Function]) -> int: if blk.Lines is not None: lines: rawptr[GSList[Line]] = blk.Lines line: rawptr[Line] = lines.Head - line_steps: t.CSizeT = 0 + line_steps: sizet = 0 while line is not None: line_steps += 1 if line_steps > IR_DUMP_CHAIN_LIMIT: @@ -519,7 +515,7 @@ def _assign_new_numbers(text: str, def _replace_ssa_numbers(text: str, - pool: rawptr[memhub.MemBuddy], + pool: memhub.MemBuddy*, map_arr: str, max_n: int) -> str: """构建新文本,将 %N 替换为映射后的新编号 @@ -527,9 +523,9 @@ def _replace_ssa_numbers(text: str, 逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。 返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。 """ - src_len: t.CSizeT = string.strlen(text) + src_len: sizet = string.strlen(text) # 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64 - new_size: t.CSizeT = src_len * 2 + 64 + new_size: sizet = src_len * 2 + 64 new_buf: str = pool.alloc(new_size) if new_buf is None: return None @@ -539,7 +535,7 @@ def _replace_ssa_numbers(text: str, new_buf[0] = '\0' return new_buf - dst_idx: t.CSizeT = 0 + dst_idx: sizet = 0 src_p: str = text while src_p is not None and src_p[0] != '\0': if dst_idx + 16 >= new_size: @@ -560,7 +556,7 @@ def _replace_ssa_numbers(text: str, # 写入新编号 num_buf[0] = '\0' viperlib.snprintf(num_buf, 16, "%d", new_num) - k: t.CSizeT = 0 + k: sizet = 0 while num_buf[k] != '\0' and dst_idx + 1 < new_size: new_buf[dst_idx] = num_buf[k] dst_idx += 1 @@ -579,7 +575,7 @@ def _replace_ssa_numbers(text: str, return new_buf -def RenumberSSA(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): +def RenumberSSA(func: rawptr[Function], pool: memhub.MemBuddy*): """重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增 在 FunctionPrint 序列化函数体之前调用。 @@ -601,7 +597,7 @@ def RenumberSSA(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): # 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。 # 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。 # 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。 - map_bytes: t.CSizeT = (max_n + 1) * 4 # int = 4 字节 + map_bytes: sizet = (max_n + 1) * 4 # int = 4 字节 map_arr: str = pool.alloc(map_bytes) if map_arr is None: return @@ -611,7 +607,7 @@ def RenumberSSA(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): next_new: int = 0 blocks: rawptr[GSList[BasicBlock]] = func.Blocks blk: rawptr[BasicBlock] = blocks.Head - blk_steps: t.CSizeT = 0 + blk_steps: sizet = 0 while blk is not None: blk_steps += 1 if blk_steps > IR_DUMP_CHAIN_LIMIT: @@ -620,7 +616,7 @@ def RenumberSSA(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): if blk.Lines is not None: lines: rawptr[GSList[Line]] = blk.Lines line: rawptr[Line] = lines.Head - line_steps: t.CSizeT = 0 + line_steps: sizet = 0 while line is not None: line_steps += 1 if line_steps > IR_DUMP_CHAIN_LIMIT: @@ -683,7 +679,7 @@ def RenumberSSA(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): def _peep_is_startwith(s: str, pfx: str) -> int: if s is None or pfx is None: return 0 - pl: t.CSizeT = string.strlen(pfx) + pl: sizet = string.strlen(pfx) if pl == 0: return 1 if string.strlen(s) < pl: @@ -691,9 +687,9 @@ def _peep_is_startwith(s: str, pfx: str) -> int: return 1 if string.strncmp(s, pfx, pl) == 0 else 0 -def _peep_replace_token(pool: rawptr[memhub.MemBuddy], +def _peep_replace_token(pool: memhub.MemBuddy*, line_buf: str, tok: str, repl: str, - tlen: t.CSizeT, rlen: t.CSizeT) -> str: + tlen: sizet, rlen: sizet) -> str: """将 line_buf 中独立记号 % 替换为 repl,返回新缓冲(无变化返回原指针) tlen/rlen = strlen(tok)/strlen(repl):由调用方在行循环外预先求好(同一 @@ -709,7 +705,7 @@ def _peep_replace_token(pool: rawptr[memhub.MemBuddy], # 位置 strncmp 必先遇到 line_buf 的 NUL 而与 tok 的非 NUL 字节不等,故原 # 上界 i+tlen<=ln 从未排除任一可能命中,去掉后命中判定不变。 hit: int = 0 - i: t.CSizeT = 0 + i: sizet = 0 while line_buf[i] != '\0': if line_buf[i] == '%' and line_buf[i + 1] == tok[0] \ and string.strncmp(line_buf + i + 1, tok, tlen) == 0: @@ -724,15 +720,15 @@ def _peep_replace_token(pool: rawptr[memhub.MemBuddy], i += 1 if hit == 0: return line_buf - ln: t.CSizeT = string.strlen(line_buf) + ln: sizet = string.strlen(line_buf) # 缓冲大小上界:单行最多 ⌊ln/2⌋ 次替换,每次去掉 ≥2 字节(%+名)换入 rlen 字节; # 最坏输出 ≤ ln + (ln/2)·rlen + NUL。ln + 1 + rlen·(ln+1) 恒覆盖该上界, # 避免 K≥2 且替换串更长时把新缓冲写穿(随机内存破坏)。 out: str = pool.alloc(ln + 1 + rlen * (ln + 1)) if out is None: return line_buf - op: t.CSizeT = 0 - oq: t.CSizeT = 0 + op: sizet = 0 + oq: sizet = 0 i = 0 while i < ln: if line_buf[i] == '%' and i + 1 + tlen <= ln \ @@ -744,7 +740,7 @@ def _peep_replace_token(pool: rawptr[memhub.MemBuddy], if (cc2 >= 48 and cc2 <= 57) or (cc2 >= 65 and cc2 <= 90) or (cc2 >= 97 and cc2 <= 122) or cc2 == 95: nxt2 = 1 if nxt2 == 0: - j: t.CSizeT = 0 + j: sizet = 0 while j < rlen: out[oq] = repl[j] oq += 1 @@ -758,7 +754,7 @@ def _peep_replace_token(pool: rawptr[memhub.MemBuddy], return out -def _peep_last_ref_eq(sb: str, a_name: str, nl: t.CSizeT) -> int: +def _peep_last_ref_eq(sb: str, a_name: str, nl: sizet) -> int: """行内最后一个 '%name' 记号是否等于 a_name(store/load 的指针操作数在行尾) nl = strlen(a_name):由调用方在 alloca 槽全量行扫描外预先求好(a_name 在 @@ -783,14 +779,14 @@ def _peep_last_ref_eq(sb: str, a_name: str, nl: t.CSizeT) -> int: return 0 -def _peep_alloc_name(eb: str, pool: rawptr[memhub.MemBuddy]) -> str: +def _peep_alloc_name(eb: str, pool: memhub.MemBuddy*) -> str: """从 '%name = alloca ...' 提取 name(不含 %),失败返回 None""" if eb is None or eb[0] != '%': return None eqpos: str = string.strstr(eb, " = alloca ") if eqpos is None: return None - nlen: t.CSizeT = t.CSizeT(t.CUInt64T(eqpos) - t.CUInt64T(eb)) - 1 + nlen: sizet = sizet(t.CUInt64T(eqpos) - t.CUInt64T(eb)) - 1 if nlen == 0: return None nm: str = pool.alloc(nlen + 1) @@ -801,7 +797,7 @@ def _peep_alloc_name(eb: str, pool: rawptr[memhub.MemBuddy]) -> str: return nm -def _peep_is_alloc_of(eb: str, a_name: str, nl: t.CSizeT) -> int: +def _peep_is_alloc_of(eb: str, a_name: str, nl: sizet) -> int: """判断 eb 是否为 a_name 的 alloca 定义行,等价于对 _peep_alloc_name(eb) 与 a_name 做 strcmp 是否为 0(不再分配名字缓冲)。 @@ -827,7 +823,7 @@ def _peep_is_alloc_of(eb: str, a_name: str, nl: t.CSizeT) -> int: return 0 -def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): +def _peephole_opt(func: rawptr[Function], pool: memhub.MemBuddy*): """文本层本地窥孔:T1 ret zeroinitializer;T2 入口槽 store→load 转发""" if func is None or func.Blocks is None or pool is None: return @@ -850,7 +846,7 @@ def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): if line1.Buf is not None: zi: str = string.strstr(line1.Buf, " zeroinitializer") if zi is not None and _peep_is_startwith(line1.Buf, "ret ") != 0: - ty_len: t.CSizeT = t.CSizeT(t.CUInt64T(zi) - t.CUInt64T(line1.Buf)) - 4 + ty_len: sizet = sizet(t.CUInt64T(zi) - t.CUInt64T(line1.Buf)) - 4 if ty_len > 0: ty_buf: str = pool.alloc(ty_len + 1) if ty_buf is not None: @@ -887,7 +883,7 @@ def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): a_name: str = _peep_alloc_name(eb, pool) if a_name is not None: # a_name 在本槽的全量行扫描中不变,strlen 只求一次(原每行各求一次) - a_name_len: t.CSizeT = string.strlen(a_name) + a_name_len: sizet = string.strlen(a_name) st_val: str = None st_ok: int = 0 st_count: int = 0 @@ -918,7 +914,7 @@ def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): if st_count == 1: vcomma: str = string.strstr(sb + 6, ", ") if vcomma is not None: - vlen: t.CSizeT = t.CSizeT(t.CUInt64T(vcomma) - t.CUInt64T(sb + 6)) + vlen: sizet = sizet(t.CUInt64T(vcomma) - t.CUInt64T(sb + 6)) if vlen > 0: vbuf: str = pool.alloc(vlen + 1) if vbuf is not None: @@ -933,7 +929,7 @@ def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): elif string.strstr(sb, " = load ") is not None: ls: str = string.strstr(sb, "%") if ls is not None and load_cnt < 64: - lname_len: t.CSizeT = t.CSizeT( + lname_len: sizet = sizet( t.CUInt64T(string.strstr(sb, " = load ")) - t.CUInt64T(ls)) lname: str = pool.alloc(lname_len + 1) if lname is not None: @@ -981,14 +977,14 @@ def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): if safe_val is not None: # 第二遍:替换 load 名引用 # safe_val 在本槽替换阶段不变,strlen 只求一次(原每行各求一次) - safe_len: t.CSizeT = string.strlen(safe_val) + safe_len: sizet = string.strlen(safe_val) li2: int = 0 while li2 < load_cnt: slotsp: str | t.CPtr = t.CPtr(t.CUInt64T(load_ltoks) + li2 * 8) ltok: str = slotsp[0] if ltok is not None: # ltok 在该 load 名的全函数行扫描中不变,strlen 只求一次 - ltok_len: t.CSizeT = string.strlen(ltok) + ltok_len: sizet = string.strlen(ltok) blk_r = blk while blk_r is not None: lr: rawptr[Line] = None @@ -1032,7 +1028,7 @@ def _peephole_opt(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): _peep_noop_bitcast(func, pool) -def _peep_noop_bitcast(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): +def _peep_noop_bitcast(func: rawptr[Function], pool: memhub.MemBuddy*): """T3: 消除 no-op bitcast(bitcast %x to ,两侧类型相同)。 生成端(虚调用/联合位宽转换)会产生同类型恒等 bitcast(如 @@ -1056,7 +1052,7 @@ def _peep_noop_bitcast(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): if ln.Buf is not None: eqpos: str = string.strstr(ln.Buf, " = bitcast ") if eqpos is not None: - nlen: t.CSizeT = t.CSizeT(t.CUInt64T(eqpos) - t.CUInt64T(ln.Buf)) - 1 + nlen: sizet = sizet(t.CUInt64T(eqpos) - t.CUInt64T(ln.Buf)) - 1 nm_buf: str = None src_buf: str = None if nlen > 0: @@ -1065,11 +1061,11 @@ def _peep_noop_bitcast(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): tpos: str = string.strstr(after, " to ") if sp1 is not None and tpos is not None \ and t.CUInt64T(sp1) < t.CUInt64T(tpos): - tyA_len: t.CSizeT = t.CSizeT(t.CUInt64T(sp1) - t.CUInt64T(after)) + tyA_len: sizet = sizet(t.CUInt64T(sp1) - t.CUInt64T(after)) src_st: str = sp1 + 1 - src_len: t.CSizeT = t.CSizeT(t.CUInt64T(tpos) - t.CUInt64T(src_st)) + src_len: sizet = sizet(t.CUInt64T(tpos) - t.CUInt64T(src_st)) tyB: str = tpos + 4 - tyB_len: t.CSizeT = string.strlen(tyB) + tyB_len: sizet = string.strlen(tyB) if src_len > 0 and string.strchr(tyB, ' ') is None \ and t.CUInt64T(string.strchr(src_st, ' ')) == t.CUInt64T(tpos) \ and tyA_len == tyB_len \ @@ -1087,8 +1083,8 @@ def _peep_noop_bitcast(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): return # 全函数把 %nm 的引用替换为源操作数 # nm_buf/src_buf 在全函数行扫描中不变,strlen 只求一次(原每行各求一次) - nm_buf_len: t.CSizeT = string.strlen(nm_buf) - src_buf_len: t.CSizeT = string.strlen(src_buf) + nm_buf_len: sizet = string.strlen(nm_buf) + src_buf_len: sizet = string.strlen(src_buf) blk_r: rawptr[BasicBlock] = func.Blocks.Head while blk_r is not None: if blk_r.Lines is not None: @@ -1119,8 +1115,8 @@ def _peep_noop_bitcast(func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): # # } # ============================================================ -def FunctionPrint(buf: str, size: t.CSizeT, - func: rawptr[Function], pool: rawptr[memhub.MemBuddy]): +def FunctionPrint(buf: str, size: sizet, + func: rawptr[Function], pool: memhub.MemBuddy*): """将函数 func 序列化为 IR 文本写入 buf""" if func is None or buf is None or size == 0: return @@ -1168,7 +1164,7 @@ def FunctionPrint(buf: str, size: t.CSizeT, if params is not None: cur = params.Head first: int = 1 - cur_steps: t.CSizeT = 0 + cur_steps: sizet = 0 while cur is not None: cur_steps += 1 if cur_steps > IR_DUMP_CHAIN_LIMIT: @@ -1229,7 +1225,7 @@ def FunctionPrint(buf: str, size: t.CSizeT, blk: rawptr[BasicBlock] = None if blocks is not None: blk = blocks.Head - blk_steps: t.CSizeT = 0 + blk_steps: sizet = 0 while blk is not None: blk_steps += 1 if blk_steps > IR_DUMP_CHAIN_LIMIT: @@ -1245,7 +1241,7 @@ def FunctionPrint(buf: str, size: t.CSizeT, lines: rawptr[GSList[Line]] = blk.Lines line = lines.Head has_lines: int = 0 - line_steps: t.CSizeT = 0 + line_steps: sizet = 0 while line is not None: line_steps += 1 if line_steps > IR_DUMP_CHAIN_LIMIT: @@ -1272,8 +1268,8 @@ def FunctionPrint(buf: str, size: t.CSizeT, _append_attr_group_def(buf, size, pool, func) -def _append_attr_group_def(buf: str, size: t.CSizeT, - pool: rawptr[memhub.MemBuddy], +def _append_attr_group_def(buf: str, size: sizet, + pool: memhub.MemBuddy*, func: rawptr[Function]): """输出字符串属性组定义: attributes #N = { "section"="..." }""" if func is None or func.AttrGroup is None or func.AttrGroupId <= 0: @@ -1293,13 +1289,13 @@ def _append_attr_group_def(buf: str, size: t.CSizeT, # 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 # 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 _g_last_dst: t.CUInt64T = 0 -_g_last_pos: t.CSizeT = 0 +_g_last_pos: sizet = 0 -def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): +def _append_cstr(dst: str, dst_size: sizet, src: str): """将 C 字符串 src 追加到 dst 末尾""" global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = 0 + dlen: sizet = 0 if _g_last_dst == t.CUInt64T(dst): dlen = _g_last_pos # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 @@ -1320,10 +1316,10 @@ def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: return - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen if remain <= 0: return - i: t.CSizeT = 0 + i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 @@ -1348,7 +1344,7 @@ def function_get_name(func: rawptr[Function]) -> str: return func.Name -def function_get_name_len(func: rawptr[Function]) -> t.CSizeT: +def function_get_name_len(func: rawptr[Function]) -> sizet: """获取函数名长度(创建时一次算好,恒等于 strlen(Name)) 对齐 function_get_name 的跨模块 stub 绕过模式:使用方模块只有 Function diff --git a/llvmlite/__init__.vp b/llvmlite/__init__.vp index 451c6cc..dc1567d 100644 --- a/llvmlite/__init__.vp +++ b/llvmlite/__init__.vp @@ -79,10 +79,10 @@ from .__verify import ( # ============================================================ # 便捷工厂: 字符串复制 # ============================================================ -def _str_dup(pool: rawptr[memhub.MemBuddy], src: str) -> str: +def _str_dup(pool: memhub.MemBuddy*, src: str) -> str: """从 pool 分配并复制一个 C 字符串""" if src is None: return None - slen: t.CSizeT = string.strlen(src) + slen: sizet = string.strlen(src) buf: str = pool.alloc(slen + 1) if buf is None: return None string.strcpy(buf, src) @@ -92,7 +92,7 @@ def _str_dup(pool: rawptr[memhub.MemBuddy], src: str) -> str: # ============================================================ # 便捷工厂: 创建带名称的基本块 # ============================================================ -def create_block(pool: rawptr[memhub.MemBuddy], func: rawptr[Function], +def create_block(pool: memhub.MemBuddy*, func: rawptr[Function], name: str) -> rawptr[BasicBlock]: """创建基本块并添加到函数""" # 块名与函数参数值名冲突防护:LLVM 中块标签 "entry:" 即值 %entry, @@ -102,7 +102,7 @@ def create_block(pool: rawptr[memhub.MemBuddy], func: rawptr[Function], use_name: str = name if func is not None and func.Params is not None and name is not None \ and name[0] != '\0': - cb_len: t.CSizeT = string.strlen(name) + 16 + cb_len: sizet = string.strlen(name) + 16 cb_buf: str = pool.alloc(cb_len) if cb_buf is not None: cb_k: int = 1 @@ -134,7 +134,7 @@ def create_block(pool: rawptr[memhub.MemBuddy], func: rawptr[Function], # ============================================================ # 便捷工厂: 创建整数常量值 # ============================================================ -def const_int(pool: rawptr[memhub.MemBuddy], bits: int, +def const_int(pool: memhub.MemBuddy*, bits: int, val: int64) -> rawptr[Value]: """创建整数常量值(自动创建类型 + 名字文本) @@ -163,12 +163,12 @@ def const_int(pool: rawptr[memhub.MemBuddy], bits: int, return ConstInt(pool, ty, val, name) -def const_int32(pool: rawptr[memhub.MemBuddy], val: int64) -> rawptr[Value]: +def const_int32(pool: memhub.MemBuddy*, val: int64) -> rawptr[Value]: """便捷: 创建 i32 整数常量""" return const_int(pool, 32, val) -def const_int64(pool: rawptr[memhub.MemBuddy], val: int64) -> rawptr[Value]: +def const_int64(pool: memhub.MemBuddy*, val: int64) -> rawptr[Value]: """便捷: 创建 i64 整数常量""" return const_int(pool, 64, val) @@ -176,7 +176,7 @@ def const_int64(pool: rawptr[memhub.MemBuddy], val: int64) -> rawptr[Value]: # ============================================================ # 便捷工厂: 创建函数并添加到模块 # ============================================================ -def create_function(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], +def create_function(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], name: str, ret_ty: rawptr[LLVMType]) -> rawptr[Function]: """创建函数并添加到模块""" name_dup: str = _str_dup(pool, name) @@ -186,7 +186,7 @@ def create_function(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], return func -def add_param(pool: rawptr[memhub.MemBuddy], func: rawptr[Function], +def add_param(pool: memhub.MemBuddy*, func: rawptr[Function], ty: rawptr[LLVMType], name: str) -> rawptr[Param]: """创建参数并添加到函数""" name_dup: str = _str_dup(pool, name) @@ -199,7 +199,7 @@ def add_param(pool: rawptr[memhub.MemBuddy], func: rawptr[Function], # ============================================================ # 便捷工厂: 创建函数声明(declare) # ============================================================ -def create_declare(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], +def create_declare(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], name: str, ret_ty: rawptr[LLVMType]) -> rawptr[Function]: """创建函数声明(declare,无函数体)并添加到模块 @@ -220,7 +220,7 @@ def create_declare(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], # 生成 LLVM IR: # @.str = private unnamed_addr constant [N x i8] c"contents\00" # ============================================================ -def create_global_string(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], +def create_global_string(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], name: str, text: str) -> rawptr[GlobalVariable]: """创建字符串常量全局变量并添加到模块 @@ -231,7 +231,7 @@ def create_global_string(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], 返回: GlobalVariable 指针,其类型为 [len+1 x i8] """ if text is None: return None - slen: t.CSizeT = string.strlen(text) + slen: sizet = string.strlen(text) count: int = slen + 1 # 含末尾 NUL # 创建 i8 类型 @@ -261,12 +261,12 @@ def create_global_string(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], # 缓冲区大小: 最坏情况每个字符4字节(\xx)+ c"..." + \00 + " init_buf: str = pool.alloc(slen * 4 + 8) if init_buf is None: return None - pos: t.CSizeT = 0 + pos: sizet = 0 init_buf[pos] = 'c' pos += 1 init_buf[pos] = '"' pos += 1 - i: t.CSizeT = 0 + i: sizet = 0 while i < slen: ch: t.CUInt8T = text[i] if ch == 0x22 or ch == 0x5C or ch < 0x20 or ch >= 0x7F: @@ -308,7 +308,7 @@ def create_global_string(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], # ============================================================ # 便捷工厂: 创建带初始化值的整数全局变量 # ============================================================ -def create_global_int(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], +def create_global_int(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], name: str, bits: int, val: int64) -> rawptr[GlobalVariable]: """创建整数全局变量并添加到模块 @@ -347,9 +347,9 @@ def create_global_int(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], @t.NoVTable class LLVMModuleCore: """模块/函数/值创建核心,封装 pool 避免每次创建都传 pool""" - Pool: rawptr[memhub.MemBuddy] + Pool: memhub.MemBuddy* - def __init__(self, pool: rawptr[memhub.MemBuddy]): + def __init__(self, pool: memhub.MemBuddy*): self.Pool = pool # ---- 模块操作 ---- @@ -436,17 +436,17 @@ class LLVMModuleCore: return ConstNull(self.Pool, ty, name) # ---- 打印 ---- - def PrintValue(self, buf: str, size: t.CSizeT, val: rawptr[Value]): + def PrintValue(self, buf: str, size: sizet, val: rawptr[Value]): ValuePrint(buf, size, val, self.Pool) - def PrintFunction(self, buf: str, size: t.CSizeT, func: rawptr[Function]): + def PrintFunction(self, buf: str, size: sizet, func: rawptr[Function]): FunctionPrint(buf, size, func, self.Pool) - def PrintModule(self, buf: str, size: t.CSizeT, mod: rawptr[LLVMModule]): + def PrintModule(self, buf: str, size: sizet, mod: rawptr[LLVMModule]): LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL) # ---- SSA 验证 ---- - def NewVerifyResult(self, buf_size: t.CSizeT) -> rawptr[VerifyResult]: + def NewVerifyResult(self, buf_size: sizet) -> rawptr[VerifyResult]: """创建验证结果对象(buf_size 为错误消息缓冲区大小)""" return _new_verify_result(self.Pool, buf_size) diff --git a/llvmlite/__module.vp b/llvmlite/__module.vp index 0c14a3e..46153a1 100644 --- a/llvmlite/__module.vp +++ b/llvmlite/__module.vp @@ -53,15 +53,15 @@ class LLVMModule: Name: str # 模块名 FuncHead: rawptr[Function] # 函数链表头 FuncTail: rawptr[Function] # 函数链表尾 - FuncCount: t.CSizeT # 函数计数 + FuncCount: sizet # 函数计数 GlobalHead: rawptr[GlobalVariable] # 全局变量链表头 GlobalTail: rawptr[GlobalVariable] # 全局变量链表尾 - GlobalCount: t.CSizeT # 全局变量计数 + GlobalCount: sizet # 全局变量计数 TargetTriple: str # 目标三元组(如 "x86_64-pc-linux-gnu") DataLayout: str # 数据布局(如 "e-m:e-p270:32:32-...") NamedTypeHead: rawptr[NamedTypeNode] # 命名结构体类型链表头 NamedTypeTail: rawptr[NamedTypeNode] # 命名结构体类型链表尾 - NamedTypeCount: t.CSizeT # 命名结构体类型计数 + NamedTypeCount: sizet # 命名结构体类型计数 # 总计: 12 字段 * 8 = 96 字节(无 vtable) # ============================================================ @@ -104,7 +104,7 @@ class LLVMModule: self.DataLayout = layout # ---- 命名结构体类型管理 ---- - def add_named_type(self, pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType]): + def add_named_type(self, pool: memhub.MemBuddy*, ty: rawptr[LLVMType]): """将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行) 非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。 @@ -188,7 +188,7 @@ class LLVMModule: cur = cur.Next return 0 - def ensure_opaque_for_type(self, pool: rawptr[memhub.MemBuddy], + def ensure_opaque_for_type(self, pool: memhub.MemBuddy*, ty: rawptr[LLVMType]): """为类型中的跨模块结构体引用添加 opaque 声明 @@ -198,8 +198,8 @@ class LLVMModule: _scan_type_for_cross_module_refs(pool, self, ty) # ---- 打印 ---- - def PrintModule(self, buf: str, size: t.CSizeT, - pool: rawptr[memhub.MemBuddy], mode: int): + def PrintModule(self, buf: str, size: sizet, + pool: memhub.MemBuddy*, mode: int): """将模块序列化为 .ll 文本写入 buf""" if self is None or buf is None or size == 0: return @@ -231,7 +231,7 @@ class LLVMModule: # 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义 # 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册 func_scan: rawptr[Function] = self.FuncHead - func_scan_steps: t.CSizeT = 0 + func_scan_steps: sizet = 0 while func_scan is not None: func_scan_steps += 1 if func_scan_steps > IR_DUMP_CHAIN_LIMIT: @@ -243,7 +243,7 @@ class LLVMModule: if func_scan.Params is not None: params_scan: rawptr[GSList[Param]] = func_scan.Params param_scan: rawptr[Param] = params_scan.Head - param_scan_steps: t.CSizeT = 0 + param_scan_steps: sizet = 0 while param_scan is not None: param_scan_steps += 1 if param_scan_steps > IR_DUMP_CHAIN_LIMIT: @@ -262,7 +262,7 @@ class LLVMModule: # 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够 # 在循环外分配一次并复用,减少 pool 碎片 ty_buf: str = pool.alloc(4096) - nt_steps: t.CSizeT = 0 + nt_steps: sizet = 0 while nt is not None: nt_steps += 1 if nt_steps > IR_DUMP_CHAIN_LIMIT: @@ -282,7 +282,7 @@ class LLVMModule: # 全局变量 gv: rawptr[GlobalVariable] = self.GlobalHead - gv_steps: t.CSizeT = 0 + gv_steps: sizet = 0 if mode == OUTPUT_STUB: # stub 模式:输出 external global(无初值) while gv is not None: @@ -319,7 +319,7 @@ class LLVMModule: # text 模式下如果输出了全局变量,也加空行 had_global: int = 0 gv2: rawptr[GlobalVariable] = self.GlobalHead - gv2_steps: t.CSizeT = 0 + gv2_steps: sizet = 0 while gv2 is not None: gv2_steps += 1 if gv2_steps > IR_DUMP_CHAIN_LIMIT: @@ -336,7 +336,7 @@ class LLVMModule: # 遍历函数 func: rawptr[Function] = self.FuncHead func_idx: int = 0 - func_steps: t.CSizeT = 0 + func_steps: sizet = 0 while func is not None: func_steps += 1 if func_steps > IR_DUMP_CHAIN_LIMIT: @@ -365,7 +365,7 @@ class LLVMModule: # ============================================================ # 工厂函数 # ============================================================ -def new_module(pool: rawptr[memhub.MemBuddy], name: str) -> rawptr[LLVMModule]: +def new_module(pool: memhub.MemBuddy*, name: str) -> rawptr[LLVMModule]: """创建一个模块""" # 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable) ptr: rawptr[LLVMModule] = pool.alloc(96) @@ -392,7 +392,7 @@ GV_SIZE: t.CDefine = 72 # NamedTypeNode 硬编码大小: Next(8) + Ty(8) + IsPacked(8) = 24 字节 NAMED_TYPE_NODE_SIZE: t.CDefine = 24 -def new_global_variable(pool: rawptr[memhub.MemBuddy], +def new_global_variable(pool: memhub.MemBuddy*, name: str, ty: rawptr[LLVMType]) -> rawptr[GlobalVariable]: """创建一个全局变量""" ptr: rawptr[GlobalVariable] = pool.alloc(GV_SIZE) @@ -473,12 +473,12 @@ def _is_opaque_struct(ty: rawptr[LLVMType]) -> int: return 0 -def module_add_named_type(mod: rawptr[LLVMModule], pool: rawptr[memhub.MemBuddy], +def module_add_named_type(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, ty: rawptr[LLVMType]): mod.add_named_type(pool, ty) -def module_set_named_type_packed(mod: rawptr[LLVMModule], pool: rawptr[memhub.MemBuddy], +def module_set_named_type_packed(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, ty: rawptr[LLVMType], is_packed: int): """按名称设置命名结构体的 packed 标记(输出 %"name" = type <{...}>)。 @@ -516,7 +516,7 @@ def _is_type_defined_in_module(mod: rawptr[LLVMModule], name: str) -> int: return mod._is_type_defined_in_module(name) -def _scan_type_for_cross_module_refs(pool: rawptr[memhub.MemBuddy], +def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], ty: rawptr[LLVMType], depth: int = 0): @@ -547,7 +547,7 @@ def _scan_type_for_cross_module_refs(pool: rawptr[memhub.MemBuddy], # 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用 if sfields is not None: fld: rawptr[ParamNode] = sfields - fld_steps: t.CSizeT = 0 + fld_steps: sizet = 0 while fld is not None: fld_steps += 1 if fld_steps > IR_DUMP_CHAIN_LIMIT: @@ -563,7 +563,7 @@ def _scan_type_for_cross_module_refs(pool: rawptr[memhub.MemBuddy], # 顶层结构体(非指针):递归扫描字段 if sfields2 is not None: fld2: rawptr[ParamNode] = sfields2 - fld2_steps: t.CSizeT = 0 + fld2_steps: sizet = 0 while fld2 is not None: fld2_steps += 1 if fld2_steps > IR_DUMP_CHAIN_LIMIT: @@ -581,7 +581,7 @@ def _scan_type_for_cross_module_refs(pool: rawptr[memhub.MemBuddy], def module_ensure_opaque_for_type(mod: rawptr[LLVMModule], - pool: rawptr[memhub.MemBuddy], + pool: memhub.MemBuddy*, ty: rawptr[LLVMType]): mod.ensure_opaque_for_type(pool, ty) @@ -633,8 +633,8 @@ IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000 # # mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码 # ============================================================ -def LLVMModulePrint(buf: str, size: t.CSizeT, - mod: rawptr[LLVMModule], pool: rawptr[memhub.MemBuddy], +def LLVMModulePrint(buf: str, size: sizet, + mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, mode: int): mod.PrintModule(buf, size, pool, mode) @@ -642,8 +642,8 @@ def LLVMModulePrint(buf: str, size: t.CSizeT, # ============================================================ # 全局变量打印 # ============================================================ -def _print_global(buf: str, size: t.CSizeT, - gv: rawptr[GlobalVariable], pool: rawptr[memhub.MemBuddy]): +def _print_global(buf: str, size: sizet, + gv: rawptr[GlobalVariable], pool: memhub.MemBuddy*): """打印单个全局变量: @ = [linkage] [unnamed_addr] [constant] """ if gv is None: return @@ -706,8 +706,8 @@ def _print_global(buf: str, size: t.CSizeT, # ============================================================ # _print_global_stub - 打印全局变量的声明形式(external global,无初值) # ============================================================ -def _print_global_stub(buf: str, size: t.CSizeT, - gv: rawptr[GlobalVariable], pool: rawptr[memhub.MemBuddy]): +def _print_global_stub(buf: str, size: sizet, + gv: rawptr[GlobalVariable], pool: memhub.MemBuddy*): """打印全局变量声明: @ = external global """ if gv is None: return @@ -736,13 +736,13 @@ def _print_global_stub(buf: str, size: t.CSizeT, # 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 # 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 _g_last_dst: t.CUInt64T = 0 -_g_last_pos: t.CSizeT = 0 +_g_last_pos: sizet = 0 -def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): +def _append_cstr(dst: str, dst_size: sizet, src: str): """将 C 字符串 src 追加到 dst 末尾""" global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = 0 + dlen: sizet = 0 if _g_last_dst == t.CUInt64T(dst): dlen = _g_last_pos # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 @@ -765,10 +765,10 @@ def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: return - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen if remain <= 0: return - i: t.CSizeT = 0 + i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 diff --git a/llvmlite/__types.vp b/llvmlite/__types.vp index 3160e4c..f43f04c 100644 --- a/llvmlite/__types.vp +++ b/llvmlite/__types.vp @@ -74,7 +74,7 @@ class LLVMType(t.REnum): # ============================================================ # 内部分配辅助 # ============================================================ -def _new_type(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def _new_type(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: """从 mpool 分配一个零初始化的 LLVMType""" ptr: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) if ptr: @@ -85,42 +85,42 @@ def _new_type(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: # ============================================================ # 类型工厂函数 # ============================================================ -def Int1(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Int1(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None c.DerefAs(ptr, LLVMType.Int(1)) return ptr -def Int8(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Int8(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None c.DerefAs(ptr, LLVMType.Int(8)) return ptr -def Int16(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Int16(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None c.DerefAs(ptr, LLVMType.Int(16)) return ptr -def Int32(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Int32(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None c.DerefAs(ptr, LLVMType.Int(32)) return ptr -def Int64(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Int64(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None c.DerefAs(ptr, LLVMType.Int(64)) return ptr -def Ptr(pool: rawptr[memhub.MemBuddy], pointee: rawptr[LLVMType]) -> rawptr[LLVMType]: +def Ptr(pool: memhub.MemBuddy*, pointee: rawptr[LLVMType]) -> rawptr[LLVMType]: """创建指针类型 Ptr(pointee) LLVM IR 中 **不允许 void* 指针**("pointers to void are invalid"), @@ -145,7 +145,7 @@ def Ptr(pool: rawptr[memhub.MemBuddy], pointee: rawptr[LLVMType]) -> rawptr[LLVM return ptr -def Func(pool: rawptr[memhub.MemBuddy], ret: rawptr[LLVMType], +def Func(pool: memhub.MemBuddy*, ret: rawptr[LLVMType], params: rawptr[ParamNode], count: int) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None @@ -153,14 +153,14 @@ def Func(pool: rawptr[memhub.MemBuddy], ret: rawptr[LLVMType], return ptr -def Void(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Void(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None c.DerefAs(ptr, LLVMType.Void()) return ptr -def Array(pool: rawptr[memhub.MemBuddy], elem_ty: rawptr[LLVMType], +def Array(pool: memhub.MemBuddy*, elem_ty: rawptr[LLVMType], count: int) -> rawptr[LLVMType]: """创建数组类型 [count x elem_ty]""" ptr: rawptr[LLVMType] = _new_type(pool) @@ -169,7 +169,7 @@ def Array(pool: rawptr[memhub.MemBuddy], elem_ty: rawptr[LLVMType], return ptr -def Struct(pool: rawptr[memhub.MemBuddy], fields: rawptr[ParamNode], +def Struct(pool: memhub.MemBuddy*, fields: rawptr[ParamNode], fcount: int, name: str) -> rawptr[LLVMType]: """创建结构体类型 {ty1, ty2, ...} @@ -183,7 +183,7 @@ def Struct(pool: rawptr[memhub.MemBuddy], fields: rawptr[ParamNode], return ptr -def Half(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Half(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: """创建半精度浮点类型 half (16-bit)""" ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None @@ -191,7 +191,7 @@ def Half(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: return ptr -def Float(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Float(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: """创建单精度浮点类型 float (32-bit)""" ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None @@ -199,7 +199,7 @@ def Float(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: return ptr -def Double(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Double(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: """创建双精度浮点类型 double (64-bit)""" ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None @@ -207,7 +207,7 @@ def Double(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: return ptr -def FP128(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def FP128(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: """创建四精度浮点类型 fp128 (128-bit)""" ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None @@ -215,7 +215,7 @@ def FP128(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: return ptr -def Label(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: +def Label(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: """创建标签类型 label""" ptr: rawptr[LLVMType] = _new_type(pool) if ptr is None: return None @@ -229,7 +229,7 @@ def Label(pool: rawptr[memhub.MemBuddy]) -> rawptr[LLVMType]: # ParamNode 硬编码大小: Next(8) + Ty(8) = 16 字节 PNODE_SIZE: t.CDefine = 16 -def new_param_node(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType]) -> rawptr[ParamNode]: +def new_param_node(pool: memhub.MemBuddy*, ty: rawptr[LLVMType]) -> rawptr[ParamNode]: """创建一个参数节点,Ty 设为给定类型指针""" ptr: rawptr[ParamNode] = pool.alloc(PNODE_SIZE) if ptr is None: return None @@ -298,9 +298,9 @@ def paramnode_set_next(node: rawptr[ParamNode], nxt: rawptr[ParamNode]): @t.NoVTable class LLVMTypeCore: """类型创建核心,封装 pool 避免每次创建类型都传 pool""" - Pool: rawptr[memhub.MemBuddy] + Pool: memhub.MemBuddy* - def __init__(self, pool: rawptr[memhub.MemBuddy]): + def __init__(self, pool: memhub.MemBuddy*): self.Pool = pool def Int1(self) -> rawptr[LLVMType]: @@ -360,7 +360,7 @@ class LLVMTypeCore: return param_list_append(head, tail, node) # ---- 打印 ---- - def PrintType(self, buf: str, size: t.CSizeT, ty: rawptr[LLVMType]): + def PrintType(self, buf: str, size: sizet, ty: rawptr[LLVMType]): TypePrint(buf, size, ty, self.Pool) @@ -378,8 +378,8 @@ class LLVMTypeCore: # # pool 用于复杂类型(Array/Struct/Func)递归打印子类型时分配临时缓冲区。 # ============================================================ -def TypePrint(buf: str, size: t.CSizeT, - ty: rawptr[LLVMType], pool: rawptr[memhub.MemBuddy]): +def TypePrint(buf: str, size: sizet, + ty: rawptr[LLVMType], pool: memhub.MemBuddy*): """将类型 ty 序列化为 IR 文本写入 buf(容量 size) pool 用于递归打印子类型时分配临时缓冲区。 @@ -392,8 +392,8 @@ def TypePrint(buf: str, size: t.CSizeT, # 造成 OOM(单文件暴涨 900MB 根因)。超过 100 层即停止打印。 TYPEPRINT_MAX_DEPTH: t.CDefine = 100 -def _TypePrintDepth(buf: str, size: t.CSizeT, - ty: rawptr[LLVMType], pool: rawptr[memhub.MemBuddy], +def _TypePrintDepth(buf: str, size: sizet, + ty: rawptr[LLVMType], pool: memhub.MemBuddy*, depth: int): """带递归深度上限的 TypePrint 内部实现""" if ty is None or buf is None or size == 0: @@ -446,7 +446,7 @@ def _TypePrintDepth(buf: str, size: t.CSizeT, return # 通用路径: 递归打印 pointee 后追加 '*' _TypePrintDepth(buf, size, pointee, pool, depth + 1) - pos: t.CSizeT = string.strlen(buf) + pos: sizet = string.strlen(buf) if pos + 1 < size: buf[pos] = '*' buf[pos + 1] = '\0' @@ -514,18 +514,18 @@ def _TypePrintDepth(buf: str, size: t.CSizeT, # ============================================================ # 内部辅助 # ============================================================ -def _strappend(dst: str, dst_size: t.CSizeT, src: str): +def _strappend(dst: str, dst_size: sizet, src: str): """将 src 追加到 dst 末尾(不超过 dst_size)""" if dst is None or src is None: return - dlen: t.CSizeT = string.strlen(dst) + dlen: sizet = string.strlen(dst) # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到 GB 外 if dlen >= dst_size: return - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen if remain <= 0: return - i: t.CSizeT = 0 + i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 @@ -537,8 +537,8 @@ def _strappend(dst: str, dst_size: t.CSizeT, src: str): # # 供 TypePrint(匿名结构体)和 PrintStructDefinition(命名结构体定义行)复用 # ============================================================ -def _print_struct_body(buf: str, size: t.CSizeT, - fields: rawptr[ParamNode], pool: rawptr[memhub.MemBuddy], +def _print_struct_body(buf: str, size: sizet, + fields: rawptr[ParamNode], pool: memhub.MemBuddy*, depth: int = 0, packed: int = 0): """打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容) @@ -568,7 +568,7 @@ def _print_struct_body(buf: str, size: t.CSizeT, _strappend(buf, size, ", ") # 直接在 buf 当前末尾位置写入字段类型 # TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0') - pos: t.CSizeT = string.strlen(buf) + pos: sizet = string.strlen(buf) if pos + 2 < size: _TypePrintDepth(buf + pos, size - pos, cur.Ty, pool, depth + 1) cur = cur.Next @@ -586,8 +586,8 @@ def _print_struct_body(buf: str, size: t.CSizeT, # 输出格式: %"name" = type { ty1, ty2, ... } # 供 LLVMModulePrint 在全局变量/函数之前输出类型定义 # ============================================================ -def PrintStructDefinition(buf: str, size: t.CSizeT, - ty: rawptr[LLVMType], pool: rawptr[memhub.MemBuddy], +def PrintStructDefinition(buf: str, size: sizet, + ty: rawptr[LLVMType], pool: memhub.MemBuddy*, packed: int = 0): """打印命名结构体类型定义行 %"name" = type { ty1, ty2, ... } @@ -668,13 +668,13 @@ def get_struct_fcount(ty: rawptr[LLVMType]) -> int: # ============================================================ DEEPCOPY_MAX_DEPTH: t.CDefine = 64 -def DeepCopyType(pool: rawptr[memhub.MemBuddy], +def DeepCopyType(pool: memhub.MemBuddy*, ty: rawptr[LLVMType]) -> rawptr[LLVMType]: """深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None""" return _DeepCopyDepth(pool, ty, 0) -def _DeepCopyDepth(pool: rawptr[memhub.MemBuddy], +def _DeepCopyDepth(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], depth: int) -> rawptr[LLVMType]: """带深度上限的深拷贝实现 @@ -736,7 +736,7 @@ def _DeepCopyDepth(pool: rawptr[memhub.MemBuddy], return new_ty -def _DeepCopyParamChain(pool: rawptr[memhub.MemBuddy], +def _DeepCopyParamChain(pool: memhub.MemBuddy*, head: rawptr[ParamNode], depth: int) -> rawptr[ParamNode]: """深拷贝 ParamNode 链表到 stdlib""" if head is None: @@ -764,11 +764,11 @@ def _DeepCopyParamChain(pool: rawptr[memhub.MemBuddy], return first -def _DeepCopyStr(pool: rawptr[memhub.MemBuddy], s: str) -> str: +def _DeepCopyStr(pool: memhub.MemBuddy*, s: str) -> str: """深拷贝字符串到 stdlib""" if s is None: return None - slen: t.CSizeT = string.strlen(s) + slen: sizet = string.strlen(s) copy: str = pool.alloc(slen + 1) if copy is None: return None diff --git a/llvmlite/__values.vp b/llvmlite/__values.vp index 7413299..4206429 100644 --- a/llvmlite/__values.vp +++ b/llvmlite/__values.vp @@ -32,7 +32,7 @@ class Value(GSListNode[Value]): # Value 硬编码大小: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 字节 VALUE_SIZE: t.CDefine = 48 -def new_value(pool: rawptr[memhub.MemBuddy]) -> rawptr[Value]: +def new_value(pool: memhub.MemBuddy*) -> rawptr[Value]: """从 mpool 分配一个零初始化的 Value""" ptr: rawptr[Value] = pool.alloc(VALUE_SIZE) if ptr: @@ -40,7 +40,7 @@ def new_value(pool: rawptr[memhub.MemBuddy]) -> rawptr[Value]: return ptr -def ConstInt(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], +def ConstInt(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], val: int64, name: str) -> rawptr[Value]: """创建整数常量值 @@ -58,7 +58,7 @@ def ConstInt(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], return v -def ConstNull(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], +def ConstNull(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], name: str) -> rawptr[Value]: """创建 null 指针常量""" v: rawptr[Value] = new_value(pool) @@ -70,7 +70,7 @@ def ConstNull(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], return v -def ConstZero(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType]) -> rawptr[Value]: +def ConstZero(pool: memhub.MemBuddy*, ty: rawptr[LLVMType]) -> rawptr[Value]: """创建 zeroinitializer 常量(零初始化聚合类型:结构体/数组)""" v: rawptr[Value] = new_value(pool) if v is None: return None @@ -81,7 +81,7 @@ def ConstZero(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType]) -> rawptr[Val return v -def ConstFloat(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], +def ConstFloat(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], val: t.CDouble) -> rawptr[Value]: """创建浮点常量值 @@ -118,7 +118,7 @@ def ConstFloat(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], return v -def SSAValue(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], +def SSAValue(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], name: str) -> rawptr[Value]: """创建 SSA 临时值 @@ -142,8 +142,8 @@ def SSAValue(pool: rawptr[memhub.MemBuddy], ty: rawptr[LLVMType], # ConstInt(i32, 42, "42") -> "i32 42" # SSAValue(i32, "%0") -> "i32 %0" # ============================================================ -def ValuePrint(buf: str, size: t.CSizeT, - val: rawptr[Value], pool: rawptr[memhub.MemBuddy]): +def ValuePrint(buf: str, size: sizet, + val: rawptr[Value], pool: memhub.MemBuddy*): """将值 val 序列化为 IR 文本写入 buf 格式: @@ -154,7 +154,7 @@ def ValuePrint(buf: str, size: t.CSizeT, # 先写类型 TypePrint(buf, size, val.Ty, pool) # 追加空格 - pos: t.CSizeT = string.strlen(buf) + pos: sizet = string.strlen(buf) if pos + 1 < size: buf[pos] = ' ' buf[pos + 1] = '\0' @@ -216,18 +216,18 @@ def value_set_isconst(val: rawptr[Value], is_const: int): # ============================================================ # 内部辅助 # ============================================================ -def _append_str(dst: str, dst_size: t.CSizeT, src: str): +def _append_str(dst: str, dst_size: sizet, src: str): """将 src 追加到 dst 末尾""" if dst is None or src is None: return - dlen: t.CSizeT = string.strlen(dst) + dlen: sizet = string.strlen(dst) # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: return - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen if remain <= 0: return - i: t.CSizeT = 0 + i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 diff --git a/llvmlite/__verify.vp b/llvmlite/__verify.vp index 66747e1..cf6bbc4 100644 --- a/llvmlite/__verify.vp +++ b/llvmlite/__verify.vp @@ -44,14 +44,14 @@ class VerifyResult: WarningCount: int # 警告总数 ErrorCode: int # 第一个错误码 ErrorBuf: str # 错误消息缓冲区 - ErrorBufSize: t.CSizeT # 缓冲区大小 + ErrorBufSize: sizet # 缓冲区大小 # ============================================================ # 辅助函数 # ============================================================ -def _new_verify_result(pool: rawptr[memhub.MemBuddy], - buf_size: t.CSizeT) -> rawptr[VerifyResult]: +def _new_verify_result(pool: memhub.MemBuddy*, + buf_size: sizet) -> rawptr[VerifyResult]: """创建验证结果对象""" ptr: rawptr[VerifyResult] = pool.alloc(VerifyResult.__sizeof__()) if ptr is None: return None @@ -82,13 +82,13 @@ def _report_error(result: rawptr[VerifyResult], code: int, msg: str): # 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 # 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 _g_last_dst: t.CUInt64T = 0 -_g_last_pos: t.CSizeT = 0 +_g_last_pos: sizet = 0 -def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): +def _append_cstr(dst: str, dst_size: sizet, src: str): """将 src 追加到 dst 末尾""" global _g_last_dst, _g_last_pos if dst is None or src is None: return - dlen: t.CSizeT = 0 + dlen: sizet = 0 if _g_last_dst == t.CUInt64T(dst): dlen = _g_last_pos # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 @@ -108,10 +108,10 @@ def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: return - slen: t.CSizeT = string.strlen(src) - remain: t.CSizeT = dst_size - dlen + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen if remain <= 0: return - i: t.CSizeT = 0 + i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 @@ -122,7 +122,7 @@ def _append_cstr(dst: str, dst_size: t.CSizeT, src: str): # ============================================================ # SSA 名表操作 # ============================================================ -def _new_name_table(pool: rawptr[memhub.MemBuddy]) -> rawptr[GSList[NameEntry]]: +def _new_name_table(pool: memhub.MemBuddy*) -> rawptr[GSList[NameEntry]]: """创建空名表""" gsl: rawptr[GSList[NameEntry]] = pool.alloc(24) # GSList: Head+Tail+Count if gsl is None: return None @@ -134,7 +134,7 @@ def _new_name_table(pool: rawptr[memhub.MemBuddy]) -> rawptr[GSList[NameEntry]]: NENTRY_SIZE: t.CDefine = 16 def _name_table_add(table: rawptr[GSList[NameEntry]], - pool: rawptr[memhub.MemBuddy], + pool: memhub.MemBuddy*, name: str) -> int: """添加名到表。返回 1=重复, 0=成功添加""" if table is None or name is None: return 0 @@ -168,7 +168,7 @@ def _name_table_contains(table: rawptr[GSList[NameEntry]], # ============================================================ # 文本分析辅助 # ============================================================ -def _is_char_name(ch: t.CChar) -> int: +def _is_char_name(ch: char) -> int: """判断字符是否为 SSA 名字符 [a-zA-Z0-9._]""" if ch >= 'a' and ch <= 'z': return 1 if ch >= 'A' and ch <= 'Z': return 1 @@ -177,7 +177,7 @@ def _is_char_name(ch: t.CChar) -> int: return 0 -def _extract_def_name(pool: rawptr[memhub.MemBuddy], +def _extract_def_name(pool: memhub.MemBuddy*, text: str) -> str: """从定义行提取被定义的 SSA 名。 @@ -280,9 +280,9 @@ def _str_matches_at(text: str, start: int, length: int, """ if text is None or target is None: return 0 # 检查 target 长度 - target_len: t.CSizeT = string.strlen(target) + target_len: sizet = string.strlen(target) if target_len != length: return 0 - i: t.CSizeT = 0 + i: sizet = 0 while i < length: if text[start + i] != target[i]: return 0 i += 1 @@ -292,7 +292,7 @@ def _str_matches_at(text: str, start: int, length: int, # ============================================================ # 主验证函数 # ============================================================ -def verify_function(pool: rawptr[memhub.MemBuddy], +def verify_function(pool: memhub.MemBuddy*, func: rawptr[Function], result: rawptr[VerifyResult]) -> int: """验证函数的 SSA 正确性。 @@ -327,12 +327,12 @@ def verify_function(pool: rawptr[memhub.MemBuddy], blk_iter = 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_name_len: sizet = string.strlen(blk_iter.Name) blk_ref: str = pool.alloc(blk_name_len + 2) if blk_ref is not None: # 构造 "%" 字符串 blk_ref[0] = '%' - k: t.CSizeT = 0 + k: sizet = 0 while k < blk_name_len: blk_ref[k + 1] = blk_iter.Name[k] k += 1 @@ -415,7 +415,7 @@ def verify_function(pool: rawptr[memhub.MemBuddy], return result.ErrorCount -def verify_module(pool: rawptr[memhub.MemBuddy], mod: rawptr[LLVMModule], result: rawptr[VerifyResult]) -> int: +def verify_module(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], result: rawptr[VerifyResult]) -> int: """验证模块中所有函数的 SSA 正确性。 返回: 错误总数 diff --git a/math.vp b/math.vp new file mode 100644 index 0000000..d543ccd --- /dev/null +++ b/math.vp @@ -0,0 +1,440 @@ +# * Soft Math Library for Viper +# * Implements a self-contained software floating-point math runtime for float (binary32) and double (binary64), +# * without external libm dependencies. Designed for embedded, bare-metal, or custom VM environments where hardware +# * FPU math routines or system-provided standard math functions are unavailable, undesirable, or require fully +# * auditable source. +# * +# * Scope and feature set: +# * - Fundamental mathematical constants: π, e, π/2, π/4, reciprocal π, 2/π, ln(2), ln(10), 2/sqrt(π), DBL_MAX. +# * - Angle conversion: radians ↔ degrees helpers. +# * - Trigonometric functions: sin, cos, tan, sinf, cosf, tanf. Argument reduction is performed using subtraction of +# * 2π until the value falls into [-π, π]; polynomial approximations are truncated series tuned for the target interval. +# * - Inverse trigonometric functions: asin, acos, atan, atan2. asin uses a minimax polynomial suitable for [-1, 1]; +# * atan relies on a Taylor core limited to |x| ≤ 1 combined with range folding via reciprocal and quadrant logic. +# * - Hyperbolic trigonometry: sinh, cosh, tanh, built atop exp and exp(-x). +# * - Exponential and logarithm: exp uses range reduction into [-ln2/2, ln2/2] followed by a Taylor polynomial for the +# * reduced residual, then scales by powers of two. Natural log implements a binary normalization pass to bring the +# * mantissa into [1, 2), then uses the rational substitution y=(s-1)/(s+1) with a convergent series. +# * - Derived logarithms and exponentials: log10, log2, exp2, expm1, log1p. +# * - General power: pow for real bases and exponents, implemented as exp(y * log(x)), with special-case handling for +# * zero and negative bases. cbrt is a wrapper over pow using the 1/3 exponent. +# * - Root and distance: Newton–Raphson sqrt / sqrtf with fixed 10 iterations; hypot for Euclidean norm. +# * - Rounding primitives: floor, ceil, round, trunc, with float variants floorf, ceilf. +# * - Modulo: fmod, fmodf following the C remainder convention where the result carries the sign of the dividend. +# * - Decomposition: modf to split a double into integer and fractional parts via a pointer output. +# * - Inverse hyperbolics: asinh, acosh, atanh expressed through log and sqrt compositions. +# * - Special functions: Gamma using Stirling’s approximation; error function erf / complementary erfc using a simple +# * rational exponential approximation. +# * - Combinatorics: factorial, binomial combination, permutation, returning double for wider dynamic range. +# * - Integer helpers: abs for int, labs for long, fabs / fabsf for floating-point absolute value. +# * - IEEE-754 predicate helpers: isnan and isinf implemented via type punning union to inspect binary64 bit patterns. +# * These avoid numeric conversion which would destroy NaN/inf payloads; they examine exponent and mantissa bits directly. +# * +# * Precision notes: +# * All polynomial cores are truncated series, not infinite expansions. Errors are bounded for the reduced interval but +# * will accumulate through composition (e.g. pow depends on log and exp; trigonometric inverses depend on asin/atan cores). +# * This implementation prioritizes determinism and source transparency over last-bit IEEE compliance. It is not a drop-in +# * replacement for a high-quality libm with accurate argument reduction, correct rounding, and exhaustive edge-case +# * handling. Input values outside the designed convergence domains will see degraded accuracy. +# * +# * Range and edge behavior: +# * exp clamps extreme inputs: values above approximately 709 return DBL_MAX, values below approximately -745 return 0.0, +# * preventing uncontrolled overflow in downstream code such as softmax. log returns NEG_1E308 for non-positive inputs +# * as a sentinel instead of NaN. Division-by-zero conditions in tan/tanf return zero as a simple fallback; other edge +# * cases propagate NaN where the underlying computation produces it. The isnan/isinf predicates use direct bit inspection +# * and respect the binary64 encoding rules for quiet/signaling NaN and signed infinities. +# * +# * Usage notes: +# * This library assumes Viper’s double maps to IEEE 754 binary64 and float maps to IEEE 754 binary32. Type punning in +# * isnan/isinf relies on a union reinterpretation of the underlying memory layout; this is portable only on targets +# * with standard little-endian or big-endian IEEE float storage and must be reviewed for exotic memory models. +# * Polynomial loops are manually folded into fixed for-loops over coefficient arrays to remove redundant source lines +# * while preserving the original floating-point evaluation order, which matters for reproducibility and error accumulation. +# * +# * License: MIT + + +define U_M_PI: double = 3.14159265358979323846 +define U_M_E: double = 2.71828182845904523536 +define U_M_PI_2: double = 1.57079632679489661923 +define U_M_PI_4: double = 0.78539816339744830962 +define U_M_1_PI: double = 0.31830988618379067154 +define U_M_2_PI: double = 0.63661977236758134308 + +define U_M_LN2: double = 0.69314718055994530942 +define U_M_LN10: double = 2.30258509299404568402 + +define U_M_2_SQRT_PI: double = 1.77245385090551602730 + +define DBL_MAX: double = 1.7976931348623157e308 +define NEG_1E308: double = -1e308 + +def radians(degrees: double) -> double: return degrees * (U_M_PI / 180.0) +def degrees(radians: double) -> double: return radians * (180.0 / U_M_PI) + +def sin(x: double) -> double: + while x > U_M_PI: + x -= 2.0 * U_M_PI + while x < -U_M_PI: + x += 2.0 * U_M_PI + x2: double = x * x + result: double = x + term: double = x + coeffs: const [8]double = [6.0, 20.0, 42.0, 72.0, 110.0, 156.0, 210.0, 272.0] + sign: double = -1.0 + for c in coeffs: + term = term * x2 / c + result += sign * term + sign = -sign + return result + +def cos(x: double) -> double: + while x > U_M_PI: + x -= 2.0 * U_M_PI + while x < -U_M_PI: + x += 2.0 * U_M_PI + x2: double = x * x + result: double = 1.0 + term: double = 1.0 + sign: double = -1.0 + coeffs: const [8]double = [2.0, 12.0, 30.0, 56.0, 90.0, 132.0, 182.0, 240.0] + for c in coeffs: + term = term * x2 / c + result += sign * term + sign = -sign + return result + +def tan(x: double) -> double: return sin(x) / cos(x) + + +def asin(x: double) -> double: + if x > 1.0: x = 1.0 + if x < -1.0: x = -1.0 + x2: double = x * x + result: double = x + result += 1.0 * x * x2 / 6.0 + result += 3.0 * x * x2 * x2 / 40.0 + result += 5.0 * x * x2 * x2 * x2 / 112.0 + result += 35.0 * x * x2 * x2 * x2 * x2 / 1152.0 + result += 63.0 * x * x2 * x2 * x2 * x2 * x2 / 2816.0 + return result + + +def acos(x: double) -> double: return U_M_PI / 2.0 - asin(x) + + +def _atan_core(x: double) -> double: + x2: double = x * x + result: double = x + term: double = x + sign: double = -1.0 + coeffs: const [10]double = [3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0, 21.0] + for c in coeffs: + term = term * x2 / c + result += sign * term + sign = -sign + return result + + +def atan(x: double) -> double: + ax: double = x + if ax < 0.0: + ax = -ax + if ax > 1.0: + return 0.0 - _atan_core(1.0 / ax) + U_M_PI_2 if x > 0.0 else _atan_core(1.0 / ax) - U_M_PI_2 + return _atan_core(x) if x >= 0.0 else 0.0 - _atan_core(ax) + + +def atan2(y: double, x: double) -> double: + if x > 0.0: return atan(y / x) + elif x < 0.0: + if y >= 0.0: return atan(y / x) + U_M_PI + else: return atan(y / x) - U_M_PI + else: + if y > 0.0: return U_M_PI_2 + elif y < 0.0: return 0.0 - U_M_PI_2 + else: return 0.0 + + +def sinh(x: double) -> double: + ex: double = exp(x) + e_negx: double = exp(-x) + return (ex - e_negx) / 2.0 + + +def cosh(x: double) -> double: + ex: double = exp(x) + e_negx: double = exp(-x) + return (ex + e_negx) / 2.0 + + +def tanh(x: double) -> double: + ex: double = exp(x) + e_negx: double = exp(-x) + return (ex - e_negx) / (ex + e_negx) + + +def exp(x: double) -> double: + """e^x + Range reduction Short Taylor: Directly expanding x with 18 terms of Taylor series diverges when |x| is slightly large + (x=-10 gives 54.5, true value 4.5e-5; x=-30 gives 3.7e10), on the negative side it gives huge positive values, + which can blow up the denominator in softmax → all probabilities ≈ 0. Instead, first do + x = k*ln2 + r (|r| <= ln2/2), then calculate exp(r) and multiply by 2^k. + """ + # First do a "finite and within range" positive check: comparisons with NaN are always false and would skip + # the following two checks, and int(NaN) on x86 becomes INT_MIN -> the later 2^k scaling loop would run + # 2.1 billion times, appearing as "frozen". Therefore NaN/overflow must be blocked here. + if x <= 709.0 and x >= -745.0: + pass + else: + if x > 709.0: return DBL_MAX + if x < -745.0: return 0.0 + return x # NaN: Return as is, let NaN propagate instead of crashing + # Reduction: Fold x into [-ln2/2, ln2/2], accumulate the integer part into k (inline rounding to avoid forward reference) + ln2: double = U_M_LN2 + q: double = x / ln2 + k: int = int(q) + frac: double = q - double(k) + if frac > 0.5: k = k + 1 + elif frac < -0.5: k = k - 1 + r: double = x - double(k) * ln2 + # IE # exp(r), |r| <= 0.3466: after 12 terms, truncation error < 1e-17 + result: double = 1.0 + term: double = 1.0 + n: int = 1 + while n <= 12: + term = term * r / double(n) + result = result + term + n += 1 + while k > 0: + result = result * 2.0 + k = k - 1 + while k < 0: + result = result * 0.5 + k = k + 1 + return result + + +def log(x: double) -> double: + if x <= 0.0: return NEG_1E308 + exponent: int = 0 + while x >= 2.0: + x /= 2.0 + exponent += 1 + while x < 1.0: + x *= 2.0 + exponent -= 1 + y: double = (x - 1.0) / (x + 1.0) + y2: double = y * y + result: double = 2.0 * y + term: double = 2.0 * y + coeffs: const [10]double = [3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0, 21.0] + for c in coeffs: + term *= y2 + result += term / c + result += double(exponent) * U_M_LN2 + return result + + +def sqrt(x: double) -> double: + if x < 0.0: return 0.0 + if x == 0.0: return 0.0 + guess: double = x / 2.0 + for _ in range(10): + guess = (guess + x / guess) / double(2.0) + return guess + + +def abs(x: int) -> int: return x if x >= 0 else -x +def fabs(x: double) -> double: return x if x >= double(0.0) else -x +def labs(x: long) -> long: return x if x >= 0 else -x + +def factorial(n: int) -> double: + if n < 0: return 0.0 + if n == 0 or n == 1: return 1.0 + result: double = 1.0 + for i in range(2, n + 1): + result *= i + return result + + +def combination(n: int, k: int) -> double: + if k < 0 or k > n: return 0.0 + if k == 0 or k == n: return 1.0 + k = k if k < n - k else n - k + result: double = 1.0 + for i in range(1, k + 1): + result = result * (n - k + i) / i + return result + + +def permutation(n: int, k: int) -> double: + if k < 0 or k > n: return 0.0 + result: double = 1.0 + for i in range(0, k): + result *= (n - i) + return result + +def pow(x: double, y: double) -> double: + if x == 0.0: return 0.0 if y > 0.0 else 1.0 + if x < 0.0: return exp(y * log(-x)) + return exp(y * log(x)) + + +def powf(x: double, y: double) -> double: return pow(x, y) +def cbrt(x: double ) -> double: return pow(x, 1.0 / 3.0) +def hypot(x: double, y: double) -> double: return sqrt(x * x + y * y) + + +def floor(x: double) -> double: + if x >= 0.0: return double(int(x)) + i: int = int(x) + if x < double(i): return double(i - 1) + else: return double(i) + + +def ceil(x: double) -> double: + if x < 0.0: return double(int(x)) + i: int = int(x) + if x > double(i): return double(i + 1) + else: return double(i) + + +def round(x: double) -> double: return floor(x + 0.5) +def trunc(x: double) -> double: return floor(x) if x >= 0.0 else ceil(x) + + +def fmod(x: double, y: double) -> double: + if y == 0.0: return 0.0 + result: double = x - y * floor(x / y) + if result < 0.0: result += y + return result + + +def fmodf(x: float, y: float) -> float: + if y == 0.0: return 0.0 + result: float = x - y * floorf(x / y) + if result < 0.0: result += y + return result + + +def modf(x: double, iptr: rawptr[double]) -> double: + int_part: double = floor(x) + *iptr = int_part + return x - int_part + + +def log10(x: double) -> double: return log(x) / U_M_LN10 +def log2(x: double) -> double: return log(x) / U_M_LN2 + + +def exp2(x: double) -> double: return pow(2.0, x) +def expm1(x: double) -> double: return exp(x) - 1.0 + +def log1p(x: double) -> double: return log(1.0 + x) + +def asinh(x: double) -> double: return log(x + sqrt(x * x + 1.0)) +def acosh(x: double) -> double: return log(x + sqrt(x * x - 1.0)) +def atanh(x: double) -> double: return (log(1.0 + x) - log(1.0 - x)) / 2.0 + + +def gamma(x: double) -> double: + if x <= 0.0: return 0.0 + if x == 1.0 or x == 2.0: return 1.0 + ln_gamma: double = 0.5 * log(2.0 * U_M_PI / x) + x * log(x / U_M_E) + return exp(ln_gamma) + + +def erf(x: double) -> double: + sign: double = 1.0 if x >= 0.0 else -1.0 + abs_x: double = fabs(x) + t0: double = 4.0 * abs_x * abs_x / U_M_PI + exp_term: double = exp(-t0) + return sign * sqrt(1.0 - exp_term) + + +def erfc(x: double) -> double: + return 1.0 - erf(x) + +def sqrtf(x: float) -> float: + if x < 0.0: return 0.0 + if x == 0.0: return 0.0 + guess: float = x / 2.0 + for i in range(10): + guess = (guess + x / guess) / 2.0 + return guess + +def sinf(x: float) -> float: + while x > 3.14159265: + x -= 6.28318530 + while x < -3.14159265: + x += 6.28318530 + x2: float = x * x + result: float = x + term: float = x + sign: float = -1.0 + coeffs: const [8]float = [6.0, 20.0, 42.0, 72.0, 110.0, 156.0, 210.0, 272.0] + for c in coeffs: + term = term * x2 / c + result += sign * term + sign = -sign + return result + + +def cosf(x: float) -> float: + while x > 3.14159265: + x -= 6.28318530 + while x < -3.14159265: + x += 6.28318530 + x2: float = x * x + result: float = 1.0 + term: float = 1.0 + sign: float = -1.0 + coeffs: const [8]float = [2.0, 12.0, 30.0, 56.0, 90.0, 132.0, 182.0, 240.0] + for c in coeffs: + term = term * x2 / c + result += sign * term + sign = -sign + return result + +def tanf(x: float) -> float: + c: float = cosf(x) + if c == 0.0: return 0.0 + return sinf(x) / c + +def fabsf(x: float) -> float: return x if x >= 0.0 else -x + +def floorf(x: float) -> float: + if x >= 0.0: return float(int(x)) + i: float = float(int(x)) + if x < i: return i - 1 + else: return i + +def ceilf(x: float) -> float: + if x < 0.0: return float(int(x)) + i: float = float(int(x)) + if x > i: return i + 1 + else: return i + + +union _U: + d: double + u: uint64 + +def isnan(x: double) -> int: + # IEEE-754 bit reinterpretation (can't use uint64(x) numerical conversion: that's fptosi, which loses the bit pattern completely + # → exp_part is always 0 → always returns 0). Bitwise copy + xv: double = x + u: uint64 = 0 + *&u = *&xv + exp_part: uint64 = (u >> 52) & 0x7FF + mantissa_part: uint64 = u & 0xFFFFFFFFFFFFF + return 1 if exp_part == 0x7FF and mantissa_part != 0 else 0 + +def isinf(x: double) -> int: + xv2: double = x + u2: uint64 = 0 + *&u2 = *&xv2 + exp_part2: uint64 = (u2 >> 52) & 0x7FF + mantissa_part2: uint64 = u2 & 0xFFFFFFFFFFFFF + return 1 if exp_part2 == 0x7FF and mantissa_part2 == 0 else 0 diff --git a/memhub.vp b/memhub.vp index 27baac1..3a5bf9b 100644 --- a/memhub.vp +++ b/memhub.vp @@ -122,25 +122,124 @@ MEMBUDDY_THREAD_SAFE: t.CDefine = 0 # >0x7FFFFFFF 时 _make_define_constant 升 i64,与原函数返回的 t.CUInt64T 同位宽)。 MEMBUDDY_CANARY_PATTERN: t.CDefine = (0xA5A5A5A5 << 32) | 0xA5A5A5A5 +# [FREEFRAME] 空闲块元数据印记(取证用;仅在 detection != 0 时写入/校验)。 +# +# 存在理由:`_fl_pop` 的取值守卫只能把"空闲块首字被写穿"变成确定性报文,报文里的 +# 两个数(block / next)**不足以指名写入者**——next 常是非指针数据,说明有越界写/ +# 野指针写落进了空闲块首字。本机制把"哪个空闲块的哪几个字被改成什么、跨度多长" +# 记在空闲块自身,并在**释放点**把越界写归因到具体的分配块(= 写入者的所有者)。 +# +# 空闲块布局(仅 detection != 0 时占用;空闲期字节 8..31 无其他用途——memhub 对空闲 +# 块只读写 word0): +# word0 = next 指针(既有语义,_fl_push/_fl_pop/_fl_find_and_remove 的原字段) +# word1 = MEMBUDDY_FREEFRAME_TAG ^ (order << 32) —— 阶印记 +# word2 = MEMBUDDY_FREEFRAME_TAG2 —— 第二校验字 +# word3 = word0 的镜像(next 副本) +# 判定:四字全为期望值 ⇒ 元数据完好;否则按"哪几个字不符"推断写穿跨度 +# (只 word0 不符 ⇒ 写入者写了 8..15 字节且起点在左邻块 canary 之后)。 +# 两常量均 < 2^63,避开本仓"大十进制字面量被解析截断"的坑(同 MEMBUDDY_CANARY_PATTERN)。 +MEMBUDDY_FREEFRAME_TAG: t.CDefine = 0x4652454500000000 +MEMBUDDY_FREEFRAME_TAG2: t.CDefine = 0x4652454600000000 + +# [DETSITE] 调用点 tag 常量(稳定、可读):标识"某次 alloc 的申请点(文件:行)"。 +# 存在理由:记录表每条只有 {ptr, size},[FREEFRAME] 报文里"写入者 sz=32"只能落到 +# 尺寸档,无法收敛到具体代码点。alloc_tagged 在同一记录下标处登记一个 tag, +# 报文据此打印 site=文件名:行,直接指名写入者的申请点。 +# 取值稳定:固定常量,非随机/非时间;0 保留为"无 tag"(报文打 site=?,不伪造)。 +DETSITE_NONE: t.CDefine = 0 # 无 tag(alloc / 未登记) +DETSITE_STRUCTGENMIXIN_570: t.CDefine = 1 # StructGenMixin.vp:570 add_field 字段名拷贝 +DETSITE_STRUCTGENMIXIN_698: t.CDefine = 2 # StructGenMixin.vp:698 _deep_copy_list_ast elts 数据 +DETSITE_STRUCTGENMIXIN_1804: t.CDefine = 3 # StructGenMixin.vp:1804 跨模块 SHA1 缓冲 32B +DETSITE_CALLGENCTOR_1175: t.CDefine = 4 # CallGenCtor.vp:1175 泛型构造 extra_args +DETSITE_CALLGENCTOR_1186: t.CDefine = 5 # CallGenCtor.vp:1186 泛型构造 arg_filled +DETSITE_STRUCTGENMIXIN_641: t.CDefine = 6 # StructGenMixin.vp:641 _deep_copy_default_ast Constant 节点 +DETSITE_STRUCTGENMIXIN_659: t.CDefine = 7 # StructGenMixin.vp:659 _deep_copy_default_ast 字符串副本 +DETSITE_STRUCTGENMIXIN_693: t.CDefine = 8 # StructGenMixin.vp:693 _deep_copy_list_ast elts 容器 + +# [DETSITE] 记录表 tag 的模块级平行表(不占 MemBuddy 字段、不改其字段布局): +# 第 i 条 = {ptr, tag}(2×u64),与 MemBuddy._det_records 同索引、同生命周期。 +# ptr 仅用于索引校验(索引错位或跨实例共用时不匹配 ⇒ 返回 0 ⇒ 报打 site=?)。 +# detection==0 时从不写入、从不读取(alloc_tagged 直接转发)。 +_det_site_arena: t.CUInt64T | t.CPtr = None +_det_site_cap: sizet = 0 + + +def _det_site_put(idx: sizet, ptr: t.CUInt64T, tag: t.CUInt64T): + """登记第 idx 条记录的调用点 tag(懒扩容,翻倍)。 + + stdlib.malloc/realloc 失败时不登记(返回),报告端据此打 site=?—— + 不静默降级、不伪造 site。仅 detection != 0 时被调用。 + """ + global _det_site_arena, _det_site_cap + if idx >= _det_site_cap: + new_cap: sizet = _det_site_cap * 2 + if new_cap <= idx: + new_cap = idx + 1 + if new_cap < 64: + new_cap = 64 + new_ptr: t.CPtr = None + if _det_site_arena is None: + new_ptr = t.CPtr(stdlib.malloc(new_cap * 16)) + else: + new_ptr = t.CPtr(stdlib.realloc(t.CPtr(_det_site_arena), new_cap * 16)) + if new_ptr is None: + return + _det_site_arena = (t.CUInt64T | t.CPtr)(t.CPtr(new_ptr)) + _det_site_cap = new_cap + _det_site_arena[idx * 2] = ptr + _det_site_arena[idx * 2 + 1] = tag + + +def _det_site_get(idx: sizet, ptr: t.CUInt64T) -> t.CUInt64T: + """取第 idx 条记录的 tag;越界或 ptr 不符(错位/跨实例)返回 0(= 无 tag)。""" + if _det_site_arena is None or idx >= _det_site_cap: + return 0 + if t.CUInt64T(_det_site_arena[idx * 2]) != ptr: + return 0 + return t.CUInt64T(_det_site_arena[idx * 2 + 1]) + + +def _det_site_name(tag: t.CUInt64T) -> str: + """tag → "文件名:行" 注册表;未登记(含 0)返回 "?"(不伪造 site)。""" + if tag == t.CUInt64T(DETSITE_STRUCTGENMIXIN_570): + return "StructGenMixin.vp:570" + if tag == t.CUInt64T(DETSITE_STRUCTGENMIXIN_698): + return "StructGenMixin.vp:698" + if tag == t.CUInt64T(DETSITE_STRUCTGENMIXIN_1804): + return "StructGenMixin.vp:1804" + if tag == t.CUInt64T(DETSITE_CALLGENCTOR_1175): + return "CallGenCtor.vp:1175" + if tag == t.CUInt64T(DETSITE_CALLGENCTOR_1186): + return "CallGenCtor.vp:1186" + if tag == t.CUInt64T(DETSITE_STRUCTGENMIXIN_641): + return "StructGenMixin.vp:641" + if tag == t.CUInt64T(DETSITE_STRUCTGENMIXIN_659): + return "StructGenMixin.vp:659" + if tag == t.CUInt64T(DETSITE_STRUCTGENMIXIN_693): + return "StructGenMixin.vp:693" + return "?" + def _canary_pattern() -> t.CUInt64T: """块尾 canary 值(0xA5A5A5A5A5A5A5A5,64 位)——统一引用编译期常量""" return t.CUInt64T(MEMBUDDY_CANARY_PATTERN) -def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: +def _align_up(val: sizet, align: sizet) -> sizet: if align == 0: return val return (val + align - 1) & ~(align - 1) -def _largest_pow2_le(val: t.CSizeT) -> t.CSizeT: +def _largest_pow2_le(val: sizet) -> sizet: + # 判据 `p <= val / 2` 与 `p * 2 <= val` 等价(整数除法),但不做乘法: + # 原写法在 val > 2^63 时 p * 2 回绕为 0 ⇒ `0 <= val` 恒真 ⇒ 死循环。 if val == 0: return 0 - p: t.CSizeT = 1 - while p * 2 <= val: - p = p * 2 + p: sizet = 1 + while p <= (val >> 1): + p = p << 1 return p -def _block_size_at_order(order: t.CInt) -> t.CSizeT: +def _block_size_at_order(order: t.CInt) -> sizet: """第 order 阶的块大小(等价于 MEMBUDDY_MIN_BLOCK << order) 热点优化(实测):本函数被调用约 1.008 亿次(占全程序调用 4.67%,第 7 名), @@ -151,7 +250,7 @@ def _block_size_at_order(order: t.CInt) -> t.CSizeT: """ if order <= 0: return MEMBUDDY_MIN_BLOCK - return MEMBUDDY_MIN_BLOCK << t.CSizeT(order) + return MEMBUDDY_MIN_BLOCK << sizet(order) # ============================================================ @@ -163,15 +262,15 @@ def _block_size_at_order(order: t.CInt) -> t.CSizeT: class MemManager: __provides__: list[str] = ['__memmgr__'] base: t.CPtr # Starting address of memory region - size: t.CSizeT # Total size of memory region + size: sizet # Total size of memory region - def __init__(self, base: t.CPtr, size: t.CSizeT): + def __init__(self, base: t.CPtr, size: sizet): self.base = base self.size = size # === Virtual functions (overridden by subclasses) === - def alloc(self, size: t.CSizeT) -> t.CPtr: + def alloc(self, size: sizet) -> t.CPtr: # Default: allocation not supported return None @@ -185,14 +284,14 @@ class MemManager: # === Concrete methods (invoke virtual functions for automatic polymorphic dispatch) === - def calloc(self, count: t.CSizeT, size: t.CSizeT) -> t.CPtr: - total: t.CSizeT = count * size + def calloc(self, count: sizet, size: sizet) -> t.CPtr: + total: sizet = count * size ptr: t.CPtr = self.alloc(total) if ptr is not None: string.memset(ptr, 0, total) return ptr - def realloc(self, ptr: t.CPtr, new_size: t.CSizeT) -> t.CPtr: + def realloc(self, ptr: t.CPtr, new_size: sizet) -> t.CPtr: if ptr is None: return self.alloc(new_size) if new_size == 0: @@ -211,7 +310,7 @@ class MemManager: def __exit__(self): self.reset() - def alloc_buf(self, capacity: t.CSizeT) -> rawptr[viperio.Buf]: + def alloc_buf(self, capacity: sizet) -> rawptr[viperio.Buf]: buf: rawptr[viperio.Buf] = self.alloc(viperio.Buf.__sizeof__()) if buf is None: return None @@ -219,7 +318,7 @@ class MemManager: if data_ptr is None: return None buf.__before_init__() - buf.__init__(t.CChar(t.CUInt64T(data_ptr), t.CPtr), capacity) + buf.__init__(char(t.CUInt64T(data_ptr), t.CPtr), capacity) return buf @@ -228,24 +327,47 @@ class MemManager: # Individual free operations are unsupported; reset reclaims all memory at once # ============================================================ class MemPool(MemManager): - offset: t.CSizeT # Bump pointer offset - high_water: t.CSizeT # High-water mark + offset: sizet # Bump pointer offset + high_water: sizet # High-water mark - def __init__(self, base: t.CPtr, size: t.CSizeT): + def __init__(self, base: t.CPtr, size: sizet): self.base = base self.size = size self.offset = 0 self.high_water = 0 - def alloc(self, size: t.CSizeT) -> t.CPtr: + # 容量预检(纯判定:不移动 offset、不触发 exit(1))。 + # 返回 1 = 本次可分配;0 = 会耗尽(与 alloc 的判定逐条一致:size==0、 + # 同一 _align_up、同一 offset+aligned>size)。 + # 用途:调用方在"一次给足"的场景(如条目级 reset 复用的工作池)先自检, + # 把"池耗尽 ⇒ printf + exit(1)"转成可控失败。 + def AllocOk(self, size: sizet) -> t.CInt: + if size == 0: + return 0 + aligned: sizet = _align_up(size, MEMHUB_ALIGN) + if self.offset + aligned > self.size: + return 0 + return 1 + + # 池耗尽仍 fail-fast(printf 诊断 + exit(1)),本轮**不**改成"返回 None": + # * MemPool 是无释放的 bump 分配器; + # * 它的实例会经 `rawptr[memhub.MemManager]` 形参流入大量"不判 None"的调用方 + # —— includes/ast/**(AST 各节点 __new__,如 exprs.vp:23/astaux.vp:23)、 + # includes/llvmlite/**、includes/numpy/** 等(全仓 `.alloc(` 调用点 200+ 处); + # * 这些点若拿到 None 会从"清晰的 [OOM] 诊断 + 立即终止"退化为空指针解引用 + # (更难定位),且本轮无法编译/运行逐点补齐 None 判断。 + # 需要可控失败的新调用点请先用 AllocOk() 预检(对齐 MemBuddy 的 None 契约由 + # MemBuddy 提供;MemPool 的契约仍为"绝不返回 None,耗尽即终止")。 + def alloc(self, size: sizet) -> t.CPtr: if size == 0: return None - aligned: t.CSizeT = _align_up(size, MEMHUB_ALIGN) + aligned: sizet = _align_up(size, MEMHUB_ALIGN) if self.offset + aligned > self.size: stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size) stdio.printf("[OOM] MemPool: total=%zu used=%zu (bump allocator, 无释放)\n", self.size, self.offset) stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n") + stdio.printf("[OOM] 提示: 需要可控失败而非终止的调用方,请先用 MemPool.AllocOk(size) 预检。\n") stdlib.exit(1) ptr: t.CPtr = t.CPtr(t.CUInt64T(self.base) + self.offset) self.offset += aligned @@ -263,21 +385,57 @@ class MemPool(MemManager): return 1 +# ============================================================ +# Heap-construction factories +# +# 类构造表达式(`memhub.MemPool(arena, cap)`)的存储落在**调用者栈帧**上: +# 生成序列为 alloca → __before_init__ → __init__,见已落盘 IR +# VET/.tpv_build/temp/d4/d46198bb42ab7aec.text.ll:60/76/81 与 +# VET/output/d46198bb42ab7aec_dso.ll:2963/3005/3008。把该指针存进模块级 +# 变量或交给别的帧,持有者拿到的就是即将失效的栈地址。 +# +# 需要跨帧存活的管理器用下面的工厂:先在 stdlib.malloc 的堆块上取存储, +# 再就地构造。两步各自的作用: +# * __before_init__ 写 vtable 指针(如 MemPool_Vtable,见 +# VET/output/c1ba4395169f2768.text.ll:345-350)并把字段清零/置默认值; +# * __init__ 填充 base/size/offset/high_water 等构造参数。 +# 构造完成后,经 MemManager 基类指针的虚调用(alloc/free/reset/realloc/ +# calloc/AllocOk)按 vtable 命中子类实现。 +# +# 用法(MemBuddy 先例:TransPyV/Test/App/nested_match_test.vp:33-38): +# p: rawptr[memhub.MemPool] = memhub.NewMemPool(arena, cap) +# if p is None: ... +# +# 生命周期:管理器对象由 stdlib.malloc 分配,与 arena 同属进程生命周期; +# 常驻用途(进程内复用的工作池)不 free。 +# ============================================================ + +# 在堆上构造 MemPool(arena bump 分配器)。base 为 arena 首地址,size 为其字节数。 +# 返回 None 表示 malloc 失败。 +def NewMemPool(base: t.CPtr, size: sizet) -> rawptr[MemPool]: + obj: rawptr[MemPool] = stdlib.malloc(MemPool.__sizeof__()) + if obj is None: + return None + obj.__before_init__() + obj.__init__(base, size) + return obj + + # ============================================================ # MemSlab - Fixed-size block pool # Bitmap stored at the start of arena; subsequent area split into block_size units managed by free list # ============================================================ class MemSlab(MemManager): - block_size: t.CSizeT # Block size (aligned) - block_count: t.CSizeT # Total block count - used_count: t.CSizeT # Used block count + block_size: sizet # Block size (aligned) + block_count: sizet # Total block count + used_count: sizet # Used block count free_list: t.CPtr # Free list head alloc_map: t.CUInt8T | t.CPtr # Allocation bitmap (at start of arena) - alloc_map_size: t.CSizeT # Bitmap byte count + alloc_map_size: sizet # Bitmap byte count usable: t.CPtr # Usable block area start (after bitmap) - usable_size: t.CSizeT # Usable block area size + usable_size: sizet # Usable block area size - def __init__(self, base: t.CPtr, size: t.CSizeT, block_size: t.CSizeT): + def __init__(self, base: t.CPtr, size: sizet, block_size: sizet): self.base = base self.size = size self.block_size = 0 @@ -291,10 +449,10 @@ class MemSlab(MemManager): if base is None: return - bs: t.CSizeT = _align_up(block_size, MEMHUB_ALIGN) + bs: sizet = _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) + map_bytes: sizet = _align_up(MEMSLAB_BITMAP_BYTES, MEMHUB_ALIGN) if size < map_bytes + bs: return self.alloc_map = base @@ -304,7 +462,7 @@ class MemSlab(MemManager): self.block_size = bs # Clear bitmap - idx: t.CSizeT = 0 + idx: sizet = 0 while idx < map_bytes: self.alloc_map[idx] = 0 idx += 1 @@ -314,14 +472,14 @@ class MemSlab(MemManager): # Construct free list: the first 8 bytes of each block store pointer to next block self.free_list = None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.block_count: block: t.CPtr = t.CPtr(t.CUInt64T(self.usable) + i * bs) c.DerefAs(block, self.free_list) self.free_list = block i += 1 - def alloc(self, size: t.CSizeT) -> t.CPtr: + def alloc(self, size: sizet) -> t.CPtr: # Slab mode: allocate one block only if requested size <= block_size if self.free_list is None: stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") @@ -339,7 +497,7 @@ class MemSlab(MemManager): block: t.CPtr = self.free_list self.free_list = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(block))) self.used_count += 1 - idx: t.CSizeT = (t.CUInt64T(block) - t.CUInt64T(self.usable)) / self.block_size + idx: sizet = (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 @@ -349,8 +507,8 @@ class MemSlab(MemManager): 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 + idx: sizet = (p - t.CUInt64T(self.usable)) / self.block_size + byte_idx: sizet = 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)) @@ -362,7 +520,7 @@ class MemSlab(MemManager): def reset(self) -> t.CInt: self.used_count = 0 self.free_list = None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.block_count: block: t.CPtr = t.CPtr(t.CUInt64T(self.usable) + i * self.block_size) c.DerefAs(block, self.free_list) @@ -394,12 +552,12 @@ class MemBuddy(MemManager): free_lists: t.CUInt64T | t.CPtr # Free list head array (located at arena start) lock_val: t.CVolatile | t.CInt # Spinlock usable: t.CPtr # Start of usable memory region (skips free_lists) - usable_size: t.CSizeT # Size of usable memory (power of two) + usable_size: sizet # Size of usable memory (power of two) chk_stack: t.CUInt64T | t.CPtr # Checkpoint 分配记录栈(存 block 地址) - chk_cap: t.CSizeT # 记录栈容量(条目数) - chk_depth: t.CSizeT # 当前记录深度 + chk_cap: sizet # 记录栈容量(条目数) + chk_depth: sizet # 当前记录深度 chk_base: t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区) - big_alloc_count: t.CSizeT # ≥8KB 大分配计数(OOM 诊断:定位大缓冲反复分配) + big_alloc_count: sizet # ≥8KB 大分配计数(OOM 诊断:定位大缓冲反复分配) # [DET] 分配检测(默认关,排查越界写/存活块覆盖时开启): # detection=1 → alloc 前后 2 字节 0xCDCD 标记 + 记录表 + 每次 alloc 后探测 detection: t.CInt = 0 @@ -408,13 +566,13 @@ class MemBuddy(MemManager): # + 打开 MEMBUDDY_PERIOD_SCAN 的周期全表扫描。仅诊断用,极慢。 # 默认 0 = 与历史实现完全一致(范式同上方 detection 字段)。 deep_detect: t.CInt = 0 - detection_size: t.CSizeT = MEMBUDDY_DET_RECORD_SIZE + detection_size: sizet = MEMBUDDY_DET_RECORD_SIZE _det_arena: t.CPtr = None # 记录区基址(stdlib.malloc,供 realloc 扩容) _det_records: t.CUInt64T | t.CPtr = None # 记录表(每 2×u64 = 1 条:{ptr, size}) - _det_count: t.CSizeT = 0 # 已记录条数 - _det_cap: t.CSizeT = 0 # 记录容量(条) + _det_count: sizet = 0 # 已记录条数 + _det_cap: sizet = 0 # 记录容量(条) - def __init__(self, base: t.CPtr, size: t.CSizeT, + def __init__(self, base: t.CPtr, size: sizet, detection: t.CInt = 0, deep_detect: t.CInt = 0): self.base = base self.size = size @@ -441,7 +599,7 @@ class MemBuddy(MemManager): self.big_alloc_count = 0 self.lock_val = 0 - fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8 + fl_bytes: sizet = (MEMBUDDY_MAX_ORDERS + 1) * 8 self.free_lists = base # Initialize all free list heads to be 0 @@ -455,7 +613,7 @@ class MemBuddy(MemManager): self.max_order = 0 return - remaining: t.CSizeT = size - fl_bytes + remaining: sizet = size - fl_bytes # 注意:不能在 __init__ 里预留 checkpoint 记录栈! # 记录栈改为 mark() 时从 buddy 池懒分配(见 mark())。 @@ -466,7 +624,7 @@ class MemBuddy(MemManager): # 按 offset^bs 匹配,跨分解边界的块因 order 不匹配自然停止 # 合并,不会破坏 buddy 一致性。remaining 恰为 2 的幂时分解 # 结果与原实现(单个 max_order 块)完全等价。 - max_blk: t.CSizeT = _largest_pow2_le(remaining) + max_blk: sizet = _largest_pow2_le(remaining) if max_blk < MEMBUDDY_MIN_BLOCK: self.usable = None self.usable_size = 0 @@ -477,7 +635,7 @@ class MemBuddy(MemManager): # 计算 max_order: log2(max_blk / MIN_BLOCK) self.max_order = 0 - bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + bs: sizet = MEMBUDDY_MIN_BLOCK while bs < max_blk: bs = bs << 1 self.max_order += 1 @@ -485,13 +643,13 @@ class MemBuddy(MemManager): # 二进制分解:把 [usable, usable+remaining) 拆成 2 的幂空闲块。 # 尾部碎片(< MIN_BLOCK)不入 free list;usable_size 记实际 # 可分配字节(used/free 统计不含碎片)。 - pos: t.CSizeT = 0 - rem: t.CSizeT = remaining - used_area: t.CSizeT = 0 + pos: sizet = 0 + rem: sizet = remaining + used_area: sizet = 0 while rem >= MEMBUDDY_MIN_BLOCK: - blk: t.CSizeT = _largest_pow2_le(rem) + blk: sizet = _largest_pow2_le(rem) o: t.CInt = 0 - ob: t.CSizeT = MEMBUDDY_MIN_BLOCK + ob: sizet = MEMBUDDY_MIN_BLOCK while ob < blk: ob = ob << 1 o += 1 @@ -515,7 +673,7 @@ class MemBuddy(MemManager): # === Checkpoint support === - def mark(self) -> t.CSizeT: + def mark(self) -> sizet: """返回当前分配水位(checkpoint) 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、 @@ -526,7 +684,7 @@ class MemBuddy(MemManager): 1GB 主池 OOM(NewAstTest Phase2 根因)。 """ if self.chk_stack is None: - cap: t.CSizeT = 2 * 1024 * 1024 + cap: sizet = 2 * 1024 * 1024 base: t.CPtr = t.CPtr(stdlib.malloc(cap * 8)) if base is None: return 0 @@ -536,7 +694,7 @@ class MemBuddy(MemManager): self.chk_depth = 0 return self.chk_depth - def reset_to(self, mark: t.CSizeT): + def reset_to(self, mark: sizet): """释放水位 mark 之后分配的所有块,回收到 free list 栈中每个 block:若 header 仍标记为已分配(奇数),_coalesce 归还; @@ -566,6 +724,10 @@ class MemBuddy(MemManager): order: t.CInt = t.CInt(stored_val >> 1) if order < 0 or order > self.max_order: continue + # [FREEFRAME] 归还前所有者检查(仅 detection):回收块是"所有者已知"的 + # 释放点,若其块尾 canary 已被写穿 ⇒ 它的所有者就是写穿右邻空闲块首字的 + # 写入者。detection == 0 时该调用立即返回(无额外内存访问)。 + self._ff_owner_check(block, order) self._coalesce(block, order) # [DET] reset-aware:记录表与 chk 栈等长(每次 alloc 各追加一条, # free 只置标志不删),截断 chk_depth 必须同步截断 _det_count, @@ -590,14 +752,472 @@ class MemBuddy(MemManager): old_head: t.CUInt64T = self.free_lists[order] c.DerefAs(block, t.CPtr(old_head)) self.free_lists[order] = t.CUInt64T(block) + # [FREEFRAME] detection 模式下补写空闲块印记(word1..3),供 _fl_pop 出块前 + # 校验。detection == 0 时只多一次可预测未命中的分支(零内存写),正常路径 + # 逐字节等价。本函数是**唯一**的"块进空闲链"写点,故印记覆盖全部入链路径。 + if self.detection != 0: + self._ff_push_mark(order, block, old_head) + + def _fl_block_ok(self, block: t.CPtr) -> t.CInt: + """free list 块地址取值校验:必须落在 [usable, usable+usable_size) 且按 + MEMBUDDY_MIN_BLOCK 对齐(与 self_check 的"范围 + 对齐"同口径)。 + + 与 _is_valid_ptr 的区别:本函数校验的是**空闲块**,其块头为 0(alloc 时 + 才写 (order<<1)|1),故不能沿用 _is_valid_ptr 的"header 必须为奇数"判据。 + 供 _fl_pop 在解引用前判定链表头 / next 指针是否已被写穿成垃圾值。 + """ + if block is None: + return 0 + if self.usable is None: + return 0 + if t.CUInt64T(block) < t.CUInt64T(self.usable): + return 0 + if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size: + return 0 + if (t.CUInt64T(block) - t.CUInt64T(self.usable)) % MEMBUDDY_MIN_BLOCK != 0: + return 0 + return 1 + + # === [FREEFRAME] 空闲块印记:取证(只读/只写诊断字,仅 detection 模式) === + + def _ff_word(self, block: t.CPtr, idx: t.CInt) -> t.CUInt64T: + """读空闲块第 idx 个 8 字节字(0=next 指针,1=阶印记,2=校验字,3=next 镜像)""" + p: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)( + t.CPtr(t.CUInt64T(block) + t.CUInt64T(idx) * 8)) + return p[0] + + def _ff_word_set(self, block: t.CPtr, idx: t.CInt, val: t.CUInt64T): + """写空闲块第 idx 个 8 字节字(仅诊断字;不触碰 word0 的既有语义)""" + p: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)( + t.CPtr(t.CUInt64T(block) + t.CUInt64T(idx) * 8)) + p[0] = val + + def _ff_stamp(self, order: t.CInt) -> t.CUInt64T: + """第 order 阶空闲块的阶印记 = TAG ^ (order << 32)(order 可从印记反解)""" + return t.CUInt64T(MEMBUDDY_FREEFRAME_TAG) ^ (t.CUInt64T(order) << 32) + + def _ff_push_mark(self, order: t.CInt, block: t.CPtr, next_val: t.CUInt64T): + """入链后写印记(word1..3)。调用方已判 detection != 0,且已写 word0=next_val。 + + 只被 _fl_push(唯一的"块进空闲链"写点)与 _fl_find_and_remove 的中间摘除 + (改 prev 的 next 后同步镜像)调用,故"空闲块在链上"期间 word1..3 恒等于 + 期望值——任何偏离都只可能来自链外写入(越界写/野指针写)。 + """ + self._ff_word_set(block, 1, self._ff_stamp(order)) + self._ff_word_set(block, 2, t.CUInt64T(MEMBUDDY_FREEFRAME_TAG2)) + self._ff_word_set(block, 3, next_val) + + def _ff_report(self, order: t.CInt, block: t.CPtr): + """[FREEFRAME] 取证转储(调用方随后 fflush + exit(1))。 + + 三块内容,构成"指名写入者"的证据: + 1. 空闲块四字的实测值 + 期望值 ⇒ 被写穿的字节区间(跨度); + 2. 左邻探测:对每个阶 o 取 L = A - (MIN_BLOCK<>1) == o,则 L 就是"块尾正好落在 A"的分配块(**连续越界**的唯一 + 可能起点),再校验 L 的块尾 canary:损坏者**可能**是越界写来源——几何 + + canary 本身**不足以**断言归属,故补 `_ff_left_classify` 的证据化判据; + 3. 记录表近邻(|ptr-A| <= 256):该区域分配过哪些对象、各多大, + 据此反查写入者的分配尺寸与调用点。 + """ + w0: t.CUInt64T = self._ff_word(block, 0) + w1: t.CUInt64T = self._ff_word(block, 1) + w2: t.CUInt64T = self._ff_word(block, 2) + w3: t.CUInt64T = self._ff_word(block, 3) + exp1: t.CUInt64T = self._ff_stamp(order) + exp2: t.CUInt64T = t.CUInt64T(MEMBUDDY_FREEFRAME_TAG2) + stdio.printf("[FREEFRAME] 空闲块四字: block=%llu order=%d w0(next)=%llu w1=%llu(期望=0x%llx) w2=%llu(期望=0x%llx) w3(next镜像)=%llu\n", + t.CUInt64T(block), order, w0, w1, exp1, w2, exp2, w3) + dev_n: t.CInt = 0 + if w3 != w0: + dev_n += 1 + if w1 != exp1: + dev_n += 1 + if w2 != exp2: + dev_n += 1 + # 跨度推断(通用式,替换原"只覆盖 n=1 / n=3"的两点枚举——实测 n=2 落空档): + # dev_n 只约束"本空闲块内至少被连续写穿的 n 个 8 字节字",不能反推唯一长度, + # 只能给区间。frame-only(仅本块内被改的字): + # 写入跨度 ∈ [8*n, 8*(n+1)-1] 字节 + # n=1 ⇒ 8..15(起点落本块之前的 8 字节内);n=2 ⇒ 16..23;n=3 ⇒ >=24。 + # 若左邻块的块尾 canary 亦被写穿(见下方"左邻探测"行),说明同一次连续写从 + # 本块之前 8 字节起步 ⇒ 跨度再前移一个字(起点 = canary 处): + # 含 canary 跨度 ∈ [8*(n+1), 8*(n+2)-1] 字节(n=2 ⇒ 24..31)。 + # 起点判定(几何):free-frame 的 4 个字在偏移 0/8/16/24,一律以本块基址为界; + # 写入者只要覆盖偏移 0 就落在本块首字(word0),故"起点落在本块首字之前"由 + # 左邻 canary 是否被改写给出(canary 在本块之前 8 字节)。 + lo_f: sizet = sizet(dev_n) * 8 + hi_f: sizet = (sizet(dev_n) + 1) * 8 - 1 + stdio.printf("[FREEFRAME] 跨度推断: 不符字数=%d/3 ⇒ 本空闲块内写入跨度 ∈ [%zu, %zu] 字节(通用式 [8n, 8n+7],n=不符字数;n=1⇒8..15, n=2⇒16..23, n=3⇒>=24);含左邻 canary 则 ∈ [%zu, %zu]\n", + dev_n, lo_f, hi_f, lo_f + 8, hi_f + 8) + # w1 / w3 成因判定(代码证据,见 _fl_push 注释:本文件的"块进空闲链"写点唯一): + # * 入链唯一入口 _fl_push 在 detection 模式下无条件写 w1=阶印记(非 0, + # `_ff_push_mark` 一次写 w1/w2/w3)⇒ "进过链"的块 w1 恒非 0。 + # * w2 == TAG2 ⇒ 本块确实被 _ff_push_mark 打过印记 ⇒ w1=0 只能由链外写入者 + # 清零,**不是**"入链未打印记"(代码里不存在绕开 _fl_push 的入链路径)。 + # * w2 != TAG2 ⇒ 印记整体不可信(入链即未打 / 三字俱被覆盖),w1=0 不单独归因。 + if w2 == exp2: + stdio.printf("[FREEFRAME] w1 成因: w2==TAG2 ⇒ 本块确经 _fl_push 打过印记(_ff_push_mark 三字同写)⇒ w1=0 是链外写入者清零,非入链漏打印记\n") + else: + stdio.printf("[FREEFRAME] w1 成因: w2!=TAG2 ⇒ 印记整体不可信(入链未打或三字俱被覆盖),w1=0 不单独归因\n") + if w3 == 0: + stdio.printf("[FREEFRAME] w3 成因: 若写入范围未达偏移 24 ⇒ w3 保持入链原值 = 入链时的 old_head ⇒ =0 表示入链时 free_lists[order]==0(本块是链尾,next=NULL)\n") + else: + stdio.printf("[FREEFRAME] w3 成因: w3!=0 但 !=w0 ⇒ 或 w0 被改(镜像失配)或 w3 本身被改,需结合跨度区间判读\n") + # 左邻探测:max_order 若被写穿则夹到容量,避免转储路径自旋 + mo: t.CInt = self.max_order + if mo < 0 or mo > MEMBUDDY_MAX_ORDERS: + mo = MEMBUDDY_MAX_ORDERS + stdio.printf("[FREEFRAME] 左邻探测(块尾正好落在 A 的分配块 = 越界写来源): max_order=%d usable=%llu\n", + mo, t.CUInt64T(self.usable)) + o: t.CInt = 0 + found_l: t.CInt = 0 + while o <= mo: + bs_o: sizet = MEMBUDDY_MIN_BLOCK << sizet(o) + if t.CUInt64T(block) >= t.CUInt64T(self.usable) + bs_o: + l_addr: t.CUInt64T = t.CUInt64T(block) - bs_o + lp: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)(t.CPtr(l_addr)) + lhdr: t.CUInt64T = lp[0] + if (lhdr & 1) != 0 and t.CInt(lhdr >> 1) == o: + can_p: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)( + t.CPtr(t.CUInt64T(block) - MEMBUDDY_CANARY)) + lcan: t.CUInt64T = can_p[0] + found_l += 1 + if lcan != t.CUInt64T(MEMBUDDY_CANARY_PATTERN): + stdio.printf("[FREEFRAME] 阶 o=%d L=%llu hdr=0x%llX 用户ptr=%llu canary=0x%llx ⇒ canary 损坏(本块可能是写入者,也可能是被同一写者波及的受害者)——归属见下方「左邻归属判据/判定」两行\n", + o, l_addr, lhdr, l_addr + MEMBUDDY_HEADER_SIZE, + lcan) + # 反查"写入者这次分配":记录表键 = 该分配块返回的用户指针 + # (detection 模式下 alloc 返回 block+10 且记录同值;否则 block+8)。 + # 命中的 sz 即写入者 alloc 的**请求尺寸**,据此落"哪一个分配点"。 + if self._det_records is not None: + l_usr: t.CUInt64T = l_addr + MEMBUDDY_HEADER_SIZE + if self.detection != 0: + l_usr = l_usr + 2 + lr_i: sizet = 0 + lr_hit: t.CInt = 0 + while lr_i < self._det_count: + if t.CUInt64T(self._det_records[lr_i * 2]) == l_usr: + # 单次加载 + 显式位测(打印与判定同源):size 槽的原始 + # 8 字节只读一次,sz/freemark 皆由该字派生——不用 + # `x >> 63`(对 64 位整数只可能得 0/1,任何大数都说明 + # 取值/位宽有误),freemark 用 (1<<63) 掩码比较得到。 + w_raw_r: t.CUInt64T = self._det_records[lr_i * 2 + 1] + w_sz_r: t.CUInt64T = w_raw_r & ((t.CUInt64T(1) << 63) - 1) + w_fr_r: t.CInt = 0 + if (w_raw_r & (t.CUInt64T(1) << 63)) != 0: + w_fr_r = 1 + # 调用点 tag(与本条记录同索引):命中则以稳定常量 + # 映射为 文件名:行,无 tag / 未登记一律 "?",不伪造。 + w_site_r: str = _det_site_name( + _det_site_get(lr_i, l_usr)) + stdio.printf("[FREEFRAME] 写入者分配记录: [%zu] ptr=%llu sz=%llu freemark=%d 原始字=%llu site=%s(sz 即写入者 alloc 请求尺寸;freemark=1 表该 ptr 已 free、0 表存活;site=该记录的调用点 tag 映射,无 tag 打 ?)\n", + lr_i, l_usr, w_sz_r, w_fr_r, w_raw_r, w_site_r) + lr_hit += 1 + lr_i += 1 + if lr_hit == 0: + stdio.printf("[FREEFRAME] 写入者分配记录: 无(该用户指针无记录 ⇒ 记录表曾扩容/截断,或该块非经 alloc 得)\n") + # [FREEFRAME] 写入者 payload 头/尾转储:区分"对象越界写"与 + # "野指针落点恰为本块尾"(见 _ff_owner_dump 注释)。 + self._ff_owner_dump(t.CPtr(l_addr), o) + # [FREEFRAME] 左邻归属的**证据化**判定(几何 + canary 不足以 + # 断言归属;判据见 _ff_left_classify)。 + self._ff_left_classify(l_addr, bs_o, lcan, w0) + else: + stdio.printf("[FREEFRAME] 阶 o=%d L=%llu hdr=0x%llX 用户ptr=%llu canary=0x%llx(完好:不是它的连续越界写)\n", + o, l_addr, lhdr, l_addr + MEMBUDDY_HEADER_SIZE, + lcan) + o += 1 + if found_l == 0: + stdio.printf("[FREEFRAME] 无候选:左邻不存在「块头奇数且阶与几何一致」的分配块 ⇒ **不能**用左邻几何归因(写入者可能是野指针落点,或来自更远处,需另证)\n") + # 记录表近邻:给出该区域分配过哪些对象(detection 模式下记录 ptr = 用户指针 + 2) + if self._det_records is not None: + stdio.printf("[FREEFRAME] 记录表近邻(|ptr-A| <= 256): ") + printed: t.CInt = 0 + ri2: sizet = 0 + while ri2 < self._det_count and printed < 8: + rp2: t.CUInt64T = self._det_records[ri2 * 2] + rs2: t.CUInt64T = self._det_records[ri2 * 2 + 1] + if rp2 >= t.CUInt64T(block) - 256 and rp2 <= t.CUInt64T(block) + 256: + # 单次加载 + 显式位测(与"写入者分配记录"行同源;不用 `>> 63`) + n_sz: t.CUInt64T = rs2 & ((t.CUInt64T(1) << 63) - 1) + n_fr: t.CInt = 0 + if (rs2 & (t.CUInt64T(1) << 63)) != 0: + n_fr = 1 + stdio.printf("[%zu]ptr=%llu sz=%llu freemark=%d ", + ri2, rp2, n_sz, n_fr) + printed += 1 + ri2 += 1 + stdio.printf("\n") + stdio.fflush(None) + + def _ff_owner_dump(self, block: t.CPtr, order: t.CInt): + """[FREEFRAME] 写入者(分配块)payload 头/尾各 16 字节 + 其请求尺寸转储。 + + 用途(把 §32.5 的两种等价读法在报文层分开): + * payload 头呈"已初始化对象"形态(指针/字符串/连续非零字段)而该块容量 + 远小于写入跨度 ⇒ "某对象 > 块容量却放进本阶块"(对象越界写穿右邻); + * payload 头/尾仍是 alloc 填充值(0xCD...)/零 ⇒ 更可能是"野指针落点恰为 + 本块尾"(写者基址不是本块)。 + 并反查记录表给出该块的 alloc 请求尺寸(= 所有者被允许写的字节数), + 与 `_ff_report` 的"写入者分配记录"行同源(同一 slot 单次加载 + 显式位测)。 + + 边界:池外/超池块一律不读(转储路径不得新增越界读)。 + """ + if self.detection == 0: + return + if self.usable is None: + return + if order < 0 or order > MEMBUDDY_MAX_ORDERS: + return + big: sizet = MEMBUDDY_MIN_BLOCK << sizet(order) + if t.CUInt64T(block) < t.CUInt64T(self.usable): + return + if t.CUInt64T(block) + big > t.CUInt64T(self.usable) + self.usable_size: + return + # payload 头 16B(起点 = block+8;detection 模式下前 2 字节为 alloc 前标记) + head_addr: t.CUInt64T = t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE + # payload 尾 16B(canary 之前 16 字节) + tail_addr: t.CUInt64T = t.CUInt64T(block) + big - MEMBUDDY_CANARY - 16 + stdio.printf("[FREEFRAME] 写入者 payload 头16B(=%llu): ", head_addr) + bi_h: t.CInt = 0 + while bi_h < 16: + bv_h: t.CUInt8T = (t.CUInt8T | t.CPtr)(t.CPtr(head_addr + t.CUInt64T(bi_h)))[0] + stdio.printf("%02X ", t.CUInt32T(bv_h)) + bi_h += 1 + stdio.printf("| 尾16B(=%llu): ", tail_addr) + bi_t: t.CInt = 0 + while bi_t < 16: + bv_t: t.CUInt8T = (t.CUInt8T | t.CPtr)(t.CPtr(tail_addr + t.CUInt64T(bi_t)))[0] + stdio.printf("%02X ", t.CUInt32T(bv_t)) + bi_t += 1 + stdio.printf("\n") + if self._det_records is not None: + usr_d: t.CUInt64T = t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE + if self.detection != 0: + usr_d = usr_d + 2 + ri_d: sizet = 0 + hit_d: t.CInt = 0 + while ri_d < self._det_count: + if t.CUInt64T(self._det_records[ri_d * 2]) == usr_d: + w_d: t.CUInt64T = self._det_records[ri_d * 2 + 1] + d_sz: t.CUInt64T = w_d & ((t.CUInt64T(1) << 63) - 1) + d_fr: t.CInt = 0 + if (w_d & (t.CUInt64T(1) << 63)) != 0: + d_fr = 1 + stdio.printf("[FREEFRAME] 写入者请求尺寸: [%zu] sz=%llu freemark=%d 原始字=%llu;本块可写=%zu 字节(bs=%zu − 头%zu − canary%zu)\n", + ri_d, d_sz, d_fr, w_d, + big - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY, + big, sizet(MEMBUDDY_HEADER_SIZE), + sizet(MEMBUDDY_CANARY)) + hit_d += 1 + ri_d += 1 + if hit_d == 0: + stdio.printf("[FREEFRAME] 写入者请求尺寸: 无记录(记录表曾扩容/截断,或该块非经 alloc 得)\n") + stdio.fflush(None) + + def _ff_addr_in_pool(self, a: t.CUInt64T) -> t.CInt: + """a 是否落在本池区间 [usable, usable + usable_size)。判据用,不解引用 a。""" + if self.usable is None: + return 0 + if a < t.CUInt64T(self.usable): + return 0 + if a >= t.CUInt64T(self.usable) + self.usable_size: + return 0 + return 1 + + def _ff_left_classify(self, l_addr: t.CUInt64T, l_bs: sizet, + lcan: t.CUInt64T, w0: t.CUInt64T): + """[FREEFRAME] 左邻归属的**证据化**判定(几何 + canary 损坏本身不足以断言归属)。 + + 实测四组判据(只读 L 的块内字节;L 的 payload 第 i 字 = L + 8 + 8i): + ① `canary == A.word0`:同一 8 字节值出现在相邻两字 ⇒ 该次写按 8 字节字推进; + ② L payload 尾 16B 是否全零:非全零 ⇒ 写者从 payload 内部起步(可能是连续 + 越界);全零 ⇒ 写者**未**回退到偏移 32..47——连续溢出必然先覆盖尾 16B + 才到 canary,故"起点 ≤ 偏移 48 且跳过 32..47"排除「从 payload 尾部连续溢出」; + ③ 写入值(= canary 值)在 L payload 内出现的字数:0 ⇒ 写入值与 payload 内容 + 无关(在 canary 处起步,而非沿 payload 递增写出去); + ④ L payload 内「池内地址 / 池外非零字」计数:本池 alloc 只会把**池内地址** + 或 0 写进本池缓冲;出现池外非零字 ⇒ 该 payload 不是「按 8 字节槽写元素 + 指针」的结果 ⇒ **写入宽度 ≠ 申请宽度**(按更宽的结构体宽度跨字写),或 + payload 被第三方覆盖。记录项只证明「本块由该 alloc 点分配」,其 `sz` 是 + **申请**尺寸、**不是**写入范围。 + + 输出只给实测值 + 由值唯一推出的条件式结论(结论 A/B/C),不做无条件归属断言。 + 预期输出样例(三次复现的现场:L 的 canary 与 A.word0 同为 0x00140000002B0000 + = 元素节点源码位置 lineno/end_lineno=43、col_offset/end_col_offset=20 落在 + L+56..L+79 的字节切片;L payload 首字 = 被深拷贝节点的 vptr 0x00007FF6C414FEB0, + 尾 16B 全零;记录 sz=32): + [FREEFRAME] 左邻归属判据(实测): canary==A.word0=1;L payload 尾16B全零=1;写入值(=canary)在 L payload 出现=0 字;L payload 非零字 池内=0 池外=4(payload 共 6 字,起点 L+8;4 个字 = 同一 vptr,模型见 _ff_left_classify 注释) + [FREEFRAME] ⇒ 结论A:… + [FREEFRAME] ⇒ 结论B:… + """ + nw: sizet = (l_bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY) / 8 + tail_zero: t.CInt = 1 + if nw >= 2: + w_a: t.CUInt64T = self._ff_word(t.CPtr(l_addr), t.CInt(nw) - 1) + w_b: t.CUInt64T = self._ff_word(t.CPtr(l_addr), t.CInt(nw)) + if w_a != 0 or w_b != 0: + tail_zero = 0 + hit_v: sizet = 0 + in_pool: sizet = 0 + out_pool: sizet = 0 + i: sizet = 0 + while i < nw: + wv: t.CUInt64T = self._ff_word(t.CPtr(l_addr), t.CInt(i) + 1) + if wv == lcan: + hit_v += 1 + if wv != 0: + if self._ff_addr_in_pool(wv) != 0: + in_pool += 1 + else: + out_pool += 1 + i += 1 + can_eq_w0: t.CInt = 0 + if lcan == w0: + can_eq_w0 = 1 + stdio.printf("[FREEFRAME] 左邻归属判据(实测): canary==A.word0=%d;L payload 尾16B全零=%d;写入值(=canary)在 L payload 出现=%zu 字;L payload 非零字 池内=%zu 池外=%zu(payload 共 %zu 字,起点 L+%zu)\n", + can_eq_w0, tail_zero, hit_v, in_pool, out_pool, nw, + sizet(MEMBUDDY_HEADER_SIZE)) + case_n: t.CInt = 0 + if tail_zero != 0 and can_eq_w0 != 0 and hit_v == 0: + case_n = 1 + if out_pool != 0: + case_n = case_n + 2 + if case_n == 1 or case_n == 3: + stdio.printf("[FREEFRAME] ⇒ 结论A:写入按 8 字节字推进(canary 与 A.word0 同值)且起点 ≤ L+%zu、**跳过**偏移 32..47 ⇒ 该次写**不是**「从 L 的 payload 尾部连续溢出」;若 L 的所有者确实越界,其写入宽度必然 > 申请尺寸 sz(对照上方「写入者请求尺寸」行)\n", + l_bs - MEMBUDDY_CANARY) + if case_n == 2 or case_n == 3: + stdio.printf("[FREEFRAME] ⇒ 结论B:L 的 payload 含**池外非零字**(本池 alloc 只产生池内地址或 0)⇒ 该 payload 不是「按 8 字节槽写元素指针」的结果 ⇒ 记录项的 sz 只是**申请**尺寸、不是写入范围:写入按更宽的结构体宽度跨字进行(或 payload 被第三方覆盖)⇒ 归属不能只看几何\n") + if case_n == 0: + stdio.printf("[FREEFRAME] ⇒ 结论C:可区分特征均未命中 ⇒ 不据「几何 + canary 损坏」断言归属(需结合记录表现场与 payload 全量转储另证)\n") + + def _ff_verify(self, order: t.CInt, block: t.CPtr): + """[FREEFRAME] 出块前校验空闲块印记(仅 detection 模式,调用方已判)。 + + 印记/镜像不符 ⇒ 该块入链后其字被链外写入 ⇒ 立即转储现场并终止 + (比"next 是否为合法块地址"更早、更精确:写入者若恰好写了 8 字节的合法 + 块地址,旧守卫会放过,本校验不会)。 + """ + # 先过池内/对齐判据:_fl_find_and_remove 的链头值没有范围校验,若槽位本身被 + # 写穿成池外值,读 word1..3 会成池外读(word0 的读取是既有行为,扩展读不应 + # 增加新的越界面)⇒ 非池内对齐地址一律不校验(交给既有的取值守卫处理)。 + if self._fl_block_ok(block) == 0: + return + w0: t.CUInt64T = self._ff_word(block, 0) + w1: t.CUInt64T = self._ff_word(block, 1) + w2: t.CUInt64T = self._ff_word(block, 2) + w3: t.CUInt64T = self._ff_word(block, 3) + if w1 == self._ff_stamp(order) and w2 == t.CUInt64T(MEMBUDDY_FREEFRAME_TAG2) and w3 == w0: + return + stdio.printf("[FREEFRAME] 空闲块元数据被写穿: order=%d block=%llu w0(next)=%llu w1=%llu(期望=0x%llx) w2=%llu(期望=0x%llx) w3(next镜像)=%llu(入链后被链外写入,立即转储)\n", + order, t.CUInt64T(block), w0, w1, self._ff_stamp(order), w2, + t.CUInt64T(MEMBUDDY_FREEFRAME_TAG2), w3) + self._ff_report(order, block) + stdio.fflush(None) + stdlib.exit(1) + + def _ff_owner_check(self, block: t.CPtr, order: t.CInt): + """[FREEFRAME] 释放前所有者检查(仅 detection 模式):校验块尾 canary。 + + 连续越界写者必然先写穿自身块尾 canary,再进入右邻块首字(canary 后 8 字节 + 即右邻块头)⇒ canary 损坏即"本块所有者就是写穿邻块首字的写入者"。报文给出 + order / 用户指针 / 合法写长,并逐字节转储 canary 起 24 字节(写穿跨度与写入 + 值)。调用点:free 的活块分支、reset_to 的每个回收块(都是"所有者已知"的 + 释放点)。 + """ + if self.detection == 0: + return + bs: sizet = MEMBUDDY_MIN_BLOCK << sizet(order) + # 范围前置校验:reset_to 的 block 直接取自 chk_stack(未做池内校验), + # 越界值会令下面的 canary 读落在池外;池外一律不报(无归属可言)。 + if self.usable is None: + return + if t.CUInt64T(block) < t.CUInt64T(self.usable): + return + if t.CUInt64T(block) + bs > t.CUInt64T(self.usable) + self.usable_size: + return + can_addr: t.CUInt64T = t.CUInt64T(block) + bs - MEMBUDDY_CANARY + cp: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)(t.CPtr(can_addr)) + can_val: t.CUInt64T = cp[0] + if can_val == t.CUInt64T(MEMBUDDY_CANARY_PATTERN): + return + stdio.printf("[FREEFRAME] 释放前 canary 损坏(本块所有者**越过了本块可用区**;写入宽度见下方 payload 转储,`sz` 是申请尺寸、不是写入范围): block=%llu order=%d 用户ptr=%llu 合法写长=%zu canary=0x%llx 期望=0x%llx\n", + t.CUInt64T(block), order, t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, + bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY, can_val, + t.CUInt64T(MEMBUDDY_CANARY_PATTERN)) + # canary 起 24 字节(8=只写坏 canary、16=连带右邻块首字、24=再连带其第二字); + # 池尾块只转储池内部分(避免转储路径越界读)。 + dump_n: t.CInt = 8 + if t.CUInt64T(block) + bs + 16 <= t.CUInt64T(self.usable) + self.usable_size: + dump_n = 24 + stdio.printf("[FREEFRAME] canary 起 %d 字节: ", dump_n) + bi: t.CInt = 0 + while bi < dump_n: + bv: t.CUInt8T = (t.CUInt8T | t.CPtr)(t.CPtr(can_addr + t.CUInt64T(bi)))[0] + stdio.printf("%02X ", t.CUInt32T(bv)) + bi += 1 + stdio.printf("\n") + # [FREEFRAME] 写入者 payload 头/尾 + 请求尺寸(与 canary 转储同一现场: + # canary 被写穿 ⇒ 本块所有者即写穿右邻空闲块首字的写入者)。 + self._ff_owner_dump(block, order) + stdio.fflush(None) + stdlib.exit(1) def _fl_pop(self, order: t.CInt) -> t.CPtr: + """弹出第 order 阶空闲链头(O(1):本函数体内无任何循环/递归)。 + + 取值校验(fail-fast):本函数只有两次内存访问——读 free_lists[order]、 + 再把该值当块地址解引用 block[0]。原实现无任何前置校验,故 free_lists[order] + 一旦被写穿(如 0xFFFF…FF = -1),第二次访问即"解引用任意地址" + (ASAN:access-violation on unknown address 0xffffffffffffffff;崩溃点 + 远离真正的写入者)。此处先判 order 在 free_lists 容量内,再判头指针与 + next 指针落在池内且对齐;不满足就地打印现场并终止——内存管理器崩溃必须 + 响亮。不做静默跳过/降级:跳过会把"堆已损坏"伪装成"分配失败",失败点 + 沿调用链漂移到别处,与本文件既有 fail-fast 口径([MEMDBG]/[DET] 均 + printf+fflush+exit)不一致。 + """ + if order < 0 or order > MEMBUDDY_MAX_ORDERS: + stdio.printf("[MEM] _fl_pop 调用者=_split_to_order order 越界: order=%d 容量=%d MAX_ORDERS=%d max_order=%d\n", + order, MEMBUDDY_MAX_ORDERS + 1, MEMBUDDY_MAX_ORDERS, self.max_order) + stdio.fflush(None) + stdlib.exit(1) + # 结构不变量(__init__ 唯一写点,此后不再改):free_lists 数组基址 == usable - 264 + # (264 = (MEMBUDDY_MAX_ORDERS+1)*8)。它被破坏意味着 MemBuddy **对象**本身被写穿 + # (而不是池内数据),此时 `self.free_lists[order]` 的地址本身就是野地址 + # (如 free_lists=-1、order=0 ⇒ 首访地址恰为 0xffffffffffffffff)。必须在 + # 任何 free_lists[…] 取值之前判掉,否则守卫也来不及。 + if self.usable is not None and t.CUInt64T(self.free_lists) != t.CUInt64T(self.usable) - (MEMBUDDY_MAX_ORDERS + 1) * 8: + stdio.printf("[MEM] _fl_pop 调用者=_split_to_order free_lists 基址非法(MemBuddy 对象被写穿): free_lists=%llu usable=%llu max_order=%d\n", + t.CUInt64T(self.free_lists), t.CUInt64T(self.usable), self.max_order) + stdio.fflush(None) + stdlib.exit(1) head_val: t.CUInt64T = self.free_lists[order] if head_val == 0: return None + if self._fl_block_ok(t.CPtr(head_val)) == 0: + stdio.printf("[MEM] _fl_pop 调用者=_split_to_order 链表头非法: order=%d head=%llu max_order=%d usable_size=%zu(free_lists[order] 被写穿:非池内对齐块地址)\n", + order, head_val, self.max_order, self.usable_size) + stdio.fflush(None) + stdlib.exit(1) block: t.CPtr = t.CPtr(head_val) + # [FREEFRAME] detection 模式:出块前校验空闲块印记/镜像(比"next 是否为合法 + # 块地址"更早、更灵敏——写入者若恰好写了 8 字节合法块地址,下面的旧守卫会 + # 放过,本校验不会)。detection == 0 时只多一次可预测未命中的分支,无额外 + # 内存访问。 + if self.detection != 0: + self._ff_verify(order, block) next_ptr: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(block))) - self.free_lists[order] = t.CUInt64T(next_ptr) + next_val: t.CUInt64T = t.CUInt64T(next_ptr) + if next_val != 0 and self._fl_block_ok(t.CPtr(next_val)) == 0: + stdio.printf("[MEM] _fl_pop 调用者=_split_to_order next 指针非法: order=%d block=%llu next=%llu max_order=%d usable_size=%zu(空闲块首字被写穿:next 非池内对齐块地址)\n", + order, head_val, next_val, self.max_order, self.usable_size) + stdio.fflush(None) + # [FREEFRAME] detection 模式下追加取证转储(左邻探测 + 记录表近邻), + # 用来把"哪个块被写穿"进一步落到"哪个分配块写了它"。 + if self.detection != 0: + self._ff_report(order, block) + stdlib.exit(1) + self.free_lists[order] = next_val return block def _fl_find_and_remove(self, order: t.CInt, target: t.CPtr) -> t.CInt: @@ -605,16 +1225,41 @@ class MemBuddy(MemManager): if head_val == 0: return 0 head: t.CPtr = t.CPtr(head_val) + # [FREEFRAME] detection 模式:本函数会**沿链走**(遍历 next),沿途节点若被写穿 + # 会令遍历走进野链(成环/超上限报文只说明"堆坏了",不指名)。故对头节点与被 + # 访问节点逐一校验印记——命中即在现场转储并终止,把"沿链漂移"变成"指名到块"。 + if self.detection != 0: + self._ff_verify(order, head) if t.CUInt64T(head) == t.CUInt64T(target): next_ptr: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(head))) self.free_lists[order] = t.CUInt64T(next_ptr) return 1 prev: t.CPtr = head cur: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(head))) + # 环检测(与 self_check 同界):free list 的 next 指针被越界写破坏后会成环, + # 无步数上限时本循环永不终止(free/coalesce 卡死且崩溃点漂移)。上限取 + # "全部最小块数 + 2",合法自由块数不可能超过它;超限即判定堆已损坏, + # 打印现场并停止遍历(返回 0 = 未找到),不再自旋。 + max_steps: sizet = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 + steps: sizet = 0 while t.CUInt64T(cur) != 0: + steps += 1 + if steps > max_steps: + stdio.printf("[MEM] free_lists[%d] 链成环或节点数超上限(next 指针被破坏): head=%llu target=%llu;停止遍历避免自旋,堆已损坏\n", + order, head_val, t.CUInt64T(target)) + return 0 + # [FREEFRAME] 被访问节点的印记校验(detection):下一跳取自 cur 的 word0, + # 若 cur 已被写穿,此处当场指名 cur 并终止(否则会沿野链漂移)。 + if self.detection != 0: + self._ff_verify(order, cur) if t.CUInt64T(cur) == t.CUInt64T(target): next_ptr: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(cur))) c.DerefAs(prev, next_ptr) + # [FREEFRAME] 中间摘除改写了 prev 的 word0(next),必须同步其镜像 + # word3——否则 _ff_verify 会把 memhub 自己的合法摘除误报为"被写穿"。 + # prev 的阶 = 本链表阶 order(_fl_push 写入的印记阶)。 + if self.detection != 0: + self._ff_word_set(prev, 3, t.CUInt64T(next_ptr)) return 1 prev = cur cur = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(cur))) @@ -623,23 +1268,43 @@ class MemBuddy(MemManager): # === Buddy system core === def _buddy_of(self, block: t.CPtr, order: t.CInt) -> t.CPtr: - offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + offset: sizet = t.CUInt64T(block) - t.CUInt64T(self.usable) # order 恒 ≥ 0(调用链:_coalesce 的 order 源自合法 header (stored>>1) 且只递增, # 起点为已释放块的阶)。内联左移等价于 _block_size_at_order(order),省去每次 # 调用的 call/ret(_buddy_of 实测 3517 万次,为 _block_size_at_order 主要来源)。 - bs: t.CSizeT = MEMBUDDY_MIN_BLOCK << t.CSizeT(order) - buddy_offset: t.CSizeT = offset ^ bs + bs: sizet = MEMBUDDY_MIN_BLOCK << sizet(order) + buddy_offset: sizet = offset ^ bs return t.CPtr(t.CUInt64T(self.usable) + buddy_offset) - def _order_for_size(self, size: t.CSizeT) -> t.CInt: + def _order_for_size(self, size: sizet) -> t.CInt: + """由字节数求阶:最小的 order 使 MEMBUDDY_MIN_BLOCK << order >= size。 + + 上界守卫(终止性):原实现 `while bs < size` 在 size 巨大(含被写穿/溢出 + 后的近 2^64 值)时,bs << 1 会回绕为 0 ⇒ `0 < size` 恒真 ⇒ 死循环;且 + order(t.CInt=i32) 会先溢出为负(负 order 再参与 `MIN_BLOCK << order` + 是未定义行为)。语义不变的界:order 只有 ≤ max_order 才有意义,更大一律 + 返回 max_order + 1——调用方 alloc(`order <= self.max_order`)与 realloc + (`new_order <= old_order`)都据此判定"超池"而走各自的既有失败分支, + 与改前的最终结果一致(改前返回的任何 > max_order 的值同样被拒)。 + """ order: t.CInt = 0 - bs: t.CSizeT = MEMBUDDY_MIN_BLOCK - while bs < size: + bs: sizet = MEMBUDDY_MIN_BLOCK + while bs < size and order <= self.max_order: bs = bs << 1 order += 1 return order def _split_to_order(self, to_order: t.CInt) -> t.CPtr: + # max_order 字段取值校验(fail-fast):下面的两个 while 都以 `self.max_order` + # 为界,而 `self.free_lists[found_order]` 直接用 found_order 作下标。若 + # max_order 被写穿(负数或 > 容量),循环界随之失效 ⇒ 读 free_lists 越界, + # 读到的垃圾值再经 _fl_pop 解引用(ASAN 现场)。此处先在入口判其合法。 + if self.max_order < 0 or self.max_order > MEMBUDDY_MAX_ORDERS: + stdio.printf("[MEM] _split_to_order max_order 非法(字段被写穿): to_order=%d max_order=%d 容量=%d MAX_ORDERS=%d usable_size=%zu\n", + to_order, self.max_order, MEMBUDDY_MAX_ORDERS + 1, MEMBUDDY_MAX_ORDERS, + self.usable_size) + stdio.fflush(None) + stdlib.exit(1) found_order: t.CInt = to_order while found_order <= self.max_order: if self.free_lists[found_order] != 0: @@ -652,12 +1317,23 @@ class MemBuddy(MemManager): found_order -= 1 # 循环条件保证 found_order > to_order ≥ 0,故递减后 found_order ≥ 0; # 内联左移等价于 _block_size_at_order(found_order),省去每次拆分的 call/ret。 - bs: t.CSizeT = MEMBUDDY_MIN_BLOCK << t.CSizeT(found_order) + bs: sizet = MEMBUDDY_MIN_BLOCK << sizet(found_order) buddy: t.CPtr = t.CPtr(t.CUInt64T(block) + bs) self._fl_push(found_order, buddy) return block def _coalesce(self, block: t.CPtr, order: t.CInt): + # 取值校验(fail-fast,与 _fl_pop/_split_to_order 同口径):本函数的 + # `self.free_lists[order]` 直接用 order 作下标(首轮循环),而 order 来自块头 + # `stored >> 1`(free/reset_to 路径)——块头被写穿时会给出任意下标 ⇒ + # free_lists 越界读/写。合法调用点(free 经 _is_valid_ptr、reset_to 显式判界) + # 都已保证 order ∈ [0, max_order] ⇒ 只在"已被写穿"时改变行为。 + if order < 0 or order > MEMBUDDY_MAX_ORDERS: + stdio.printf("[MEM] _coalesce order 非法(块头被写穿): order=%d 容量=%d MAX_ORDERS=%d max_order=%d block=%llu\n", + order, MEMBUDDY_MAX_ORDERS + 1, MEMBUDDY_MAX_ORDERS, + self.max_order, t.CUInt64T(block)) + stdio.fflush(None) + stdlib.exit(1) while order < self.max_order: # 提前退出(不改变语义,仅省去"注定找不到"的两次调用):本阶空闲链表 # 为空 ⇒ _fl_find_and_remove 入口即判 head==0 返回 0 ⇒ 本阶不可能合并。 @@ -681,7 +1357,7 @@ class MemBuddy(MemManager): block: t.CPtr = t.CPtr(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE) 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) + offset: sizet = t.CUInt64T(block) - t.CUInt64T(self.usable) if offset % MEMBUDDY_MIN_BLOCK != 0: return 0 stored: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(block))) stored_val: t.CUInt64T = t.CUInt64T(stored) @@ -699,7 +1375,7 @@ class MemBuddy(MemManager): # 此时无法区分,跳过校验(退化到仅 header 校验,避免误判正常 free)。 if self.chk_stack is not None and self.chk_depth < self.chk_cap: alive: t.CInt = 0 - ci: t.CSizeT = 0 + ci: sizet = 0 while ci < self.chk_depth: if self.chk_stack[ci] == t.CUInt64T(block): alive = 1 @@ -722,15 +1398,26 @@ class MemBuddy(MemManager): atom.__atomic_clear(c.Addr(self.lock_val), atom.ATOMIC_RELEASE) # === Virtual function overrides === - def alloc(self, size: t.CSizeT) -> t.CPtr: + def alloc(self, size: sizet) -> t.CPtr: self._lock() result: t.CPtr = None if size != 0 and self.usable is not None: # +MEMBUDDY_CANARY:预留块尾 8 字节哨兵(用户数据区之外),越界写定位用 - needed: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + needed: sizet = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY if self.detection != 0: # [DET] 前后各 2 字节 0xCDCD 标记,实际比请求多 4 字节 needed = needed + 4 + # 尺寸溢出守卫(fail-fast):size 近 u64 上限时 `size + 16 (+4)` 回绕成 + # 极小值 ⇒ order 变小 ⇒ 会"成功"返回一个远小于请求的块,调用方按请求 + # 尺寸写入即越界写穿相邻块——这是堆损坏最上游的来源之一(free list + # 槽位/块首字被写成垃圾,最终在别处表现为 ASAN)。合法请求不可能回绕, + # 故就地响亮终止;不回绕、不静默返回小块、不改动既有的"超池→None"契约 + # (后者仍由下方 `order <= self.max_order` 分支按原样处理)。 + if needed < size: + stdio.printf("[MEM] alloc 调用者=上层 size 溢出: size=%zu needed=%zu(size+HEADER+CANARY 回绕,拒绝分配)\n", + size, needed) + stdio.fflush(None) + stdlib.exit(1) order: t.CInt = self._order_for_size(needed) if order <= self.max_order: block: t.CPtr = self._split_to_order(order) @@ -740,14 +1427,14 @@ class MemBuddy(MemManager): # 写块尾 canary(block + block_size - CANARY) # order 恒 ≥ 0(_order_for_size 返回值),内联左移等价于 # _block_size_at_order(order),省去每次 alloc 的 call/ret。 - bs: t.CSizeT = MEMBUDDY_MIN_BLOCK << t.CSizeT(order) + bs: sizet = MEMBUDDY_MIN_BLOCK << sizet(order) c.DerefAs(t.CPtr(t.CUInt64T(block) + bs - MEMBUDDY_CANARY), t.CPtr(MEMBUDDY_CANARY_PATTERN)) # 分配守卫:填充用户数据区 0xCD 哨兵(未初始化检测)。 # 调用方初始化(list.__init__ 等)覆盖前,字段保持 0xCDCD... # CTORDBG 打印 d0-d40 时:0xCDCD...=未初始化,其他=被覆盖。 if MEMBUDDY_FILL_GUARD != 0: - fill_size: t.CSizeT = bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY + fill_size: sizet = bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY if fill_size > 0: string.memset(result, MEMBUDDY_FILL_PATTERN, fill_size) # 记录到 checkpoint 栈(供 reset_to 回收) @@ -755,7 +1442,7 @@ class MemBuddy(MemManager): # → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题) if self.chk_stack is not None: if self.chk_depth >= self.chk_cap: - new_cap: t.CSizeT = self.chk_cap * 2 + new_cap: sizet = self.chk_cap * 2 new_stack: t.CPtr = t.CPtr(stdlib.realloc(self.chk_base, new_cap * 8)) if new_stack is not None: self.chk_base = new_stack @@ -800,7 +1487,7 @@ class MemBuddy(MemManager): # 只写 0/40 根因)。重叠 = MemBuddy free list 损坏(active 块 # 混入 free list),在第一次重叠处拦截并打印两个 size。 ff_d: t.CUInt64T = t.CUInt64T(1) << 63 - dup_i: t.CSizeT = 0 + dup_i: sizet = 0 while dup_i < self._det_count: drp: t.CUInt64T = self._det_records[dup_i * 2] drs: t.CUInt64T = self._det_records[dup_i * 2 + 1] @@ -817,8 +1504,19 @@ class MemBuddy(MemManager): dbg_block: t.CPtr = t.CPtr(base_ret_d - MEMBUDDY_HEADER_SIZE) dbg_hdr: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(dbg_block))) dbg_order: t.CInt = t.CInt(t.CUInt64T(dbg_hdr) >> 1) + # 取值校验(fail-fast,与 _fl_pop/_coalesce 同口径):dbg_order + # 直接取自刚出块的块头(正常 = (order<<1)|1 的 order),但块头若 + # 已被越界写穿(本分支正是为查这类损坏而开),`free_lists[dbg_order]` + # 就是越界读;读到的垃圾再被当块地址解引用 ⇒ 崩溃点漂移。合法 + # 路径下 dbg_order ∈ [0, max_order] ⇒ 只在已损坏时改变行为。 + if dbg_order < 0 or dbg_order > MEMBUDDY_MAX_ORDERS: + stdio.printf("[MEMDBG] alloc dbg_order 非法(块头被写穿): hdr=0x%llX dbg_order=%d 容量=%d block=%llu(终止)\n", + t.CUInt64T(dbg_hdr), dbg_order, MEMBUDDY_MAX_ORDERS + 1, + t.CUInt64T(dbg_block)) + stdio.fflush(None) + stdlib.exit(1) dbg_cur: t.CPtr = t.CPtr(self.free_lists[dbg_order]) - dbg_n: t.CSizeT = 0 + dbg_n: sizet = 0 while t.CUInt64T(dbg_cur) != 0: if t.CUInt64T(dbg_cur) == t.CUInt64T(dbg_block): stdio.printf("[MEMDBG] alloc 重复出块: size=%llu block=%llu 仍残留 free list order=%d(重复 put 实锤,终止)\n", @@ -835,7 +1533,7 @@ class MemBuddy(MemManager): # 记录表满:stdlib.realloc 翻倍扩容(防 is_alive/_det_probe # 因容量耗尽漏检——SlotsBugTest 编译 includes 超 2M 次 alloc, # 满后新块无记录 → is_alive 误报"读取悬空") - new_cap: t.CSizeT = self._det_cap * 2 + new_cap: sizet = self._det_cap * 2 new_rec: t.CPtr = t.CPtr(stdlib.realloc(self._det_arena, new_cap * 16)) if new_rec is not None: self._det_arena = new_rec @@ -866,7 +1564,7 @@ class MemBuddy(MemManager): "(常量未解析/被同名符号遮蔽/被算成 0)\n") stdio.fflush(None) elif self.usable is not None: - needed2: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + needed2: sizet = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY order2: t.CInt = self._order_for_size(needed2) stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu pool_base=%llu\n", size, needed2, order2, self.max_order, self.used_bytes(), @@ -891,6 +1589,27 @@ class MemBuddy(MemManager): self._unlock() return result + def alloc_tagged(self, size: sizet, tag: sizet) -> t.CPtr: + """带调用点 tag 的 alloc 包装(供 [FREEFRAME] 直接指名写入者申请点)。 + + 语义与 alloc 完全一致,仅多一步登记:detection != 0 时,转发 + self.alloc(size) 后把 (返回 ptr, tag) 写入模块级平行表 _det_site_arena, + 索引 = 调用前 self._det_count(= 本次新记录下标)。_ff_report 据此打印 + site=文件名:行。tag 由调用点以稳定常量(DETSITE_*)传入。 + + detection == 0(或记录表未建 / tag==0)时直接转发 self.alloc(size): + 不读写任何 tag 状态,MemBuddy.alloc 函数体未改动 ⇒ 分配器默认路径 + 逐字节等价(本包装对该路仅是一次尾转发)。记录表满且 realloc 失败时 + _det_count 未增 ⇒ 不登记(报文打 site=?),不伪造。 + """ + if self.detection == 0 or self._det_records is None or tag == 0: + return self.alloc(size) + before: sizet = self._det_count + r: t.CPtr = self.alloc(size) + if r is not None and self._det_count == before + 1: + _det_site_put(before, t.CUInt64T(r), t.CUInt64T(tag)) + return r + def free(self, ptr: t.CPtr) -> t.CInt: self._lock() if ptr is not None: @@ -904,7 +1623,7 @@ class MemBuddy(MemManager): # 从记录表取本条真实 size(detection 下 free 后填 0xCD,UAF # 写入检测:free 后块被写穿 → 探测时 0xCD 被破坏 → 报警); # 记录保留并置 free 标志(探测时对仍 free 的块验证 0xCD 完整)。 - ri: t.CSizeT = 0 + ri: sizet = 0 while ri < self._det_count: rp: t.CUInt64T = self._det_records[ri * 2] rs: t.CUInt64T = self._det_records[ri * 2 + 1] @@ -930,11 +1649,16 @@ class MemBuddy(MemManager): stdlib.exit(1) self._unlock() return 1 + # [FREEFRAME] 释放前所有者检查(仅 detection):活块的块尾 canary 被 + # 写穿 ⇒ 本块所有者就是"写穿右邻空闲块首字"的写入者(canary 后 8 字节 + # 即右邻块头)。放在下面 [MEMDBG] 扫描之前:重复归还(double-put)与 + # 越界写是两类不同损坏,先报更上游的那类。detection == 0 时立即返回。 + self._ff_owner_check(block, order) if _memdbg_enable != 0: # [MEMDBG] 重复归还检测:活跃块(header 奇数)绝不该已在本 order # free list;命中 = 同块被 put 两次(free list 重复 put 实锤)。 dbg_f: t.CPtr = t.CPtr(self.free_lists[order]) - dbg_fn: t.CSizeT = 0 + dbg_fn: sizet = 0 while t.CUInt64T(dbg_f) != 0: if t.CUInt64T(dbg_f) == t.CUInt64T(block): stdio.printf("[MEMDBG] 重复归还: free(ptr=%llu) block=%llu 已在 free list order=%d(double-put 实锤,终止)\n", @@ -976,12 +1700,12 @@ class MemBuddy(MemManager): i: t.CInt for i in range(MEMBUDDY_MAX_ORDERS + 1): self.free_lists[i] = 0 - pos: t.CSizeT = 0 - rem: t.CSizeT = self.usable_size + pos: sizet = 0 + rem: sizet = self.usable_size while rem >= MEMBUDDY_MIN_BLOCK: - blk: t.CSizeT = _largest_pow2_le(rem) + blk: sizet = _largest_pow2_le(rem) o: t.CInt = 0 - ob: t.CSizeT = MEMBUDDY_MIN_BLOCK + ob: sizet = MEMBUDDY_MIN_BLOCK while ob < blk: ob = ob << 1 o += 1 @@ -1001,7 +1725,7 @@ class MemBuddy(MemManager): return 1 # realloc override: buddy system reads original order from block header; old_size is not required - def realloc(self, ptr: t.CPtr, new_size: t.CSizeT) -> t.CPtr: + def realloc(self, ptr: t.CPtr, new_size: sizet) -> t.CPtr: if ptr is None: return self.alloc(new_size) if new_size == 0: @@ -1017,7 +1741,14 @@ class MemBuddy(MemManager): stored: t.CPtr = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(block))) stored_val: t.CUInt64T = t.CUInt64T(stored) old_order: t.CInt = t.CInt(stored_val >> 1) - needed: t.CSizeT = new_size + MEMBUDDY_HEADER_SIZE + # 容量口径必须与 alloc **逐字同源**(唯一真相源):alloc 的块容量判据是 + # `needed = size + HEADER + CANARY (+4 检测标记)`,块内真实可写 = bs-16。 + # 本函数原缺 CANARY(`needed = new_size + HEADER`)⇒ 原地判定宽一整个边界: + # new_size ∈ (bs-16, bs-8] 时 new_order ≤ old_order 而原地返回,调用方按契约 + # 写 new_size 字节即越界写进自己的 **canary**(例:order-1 bs=64,可写 48; + # 旧口径放行到 56 ⇒ 多写 8 字节入 canary)。补齐 CANARY 后两侧一致: + # 48(=bs-16)是块内真实上限、56(=bs-8)是错的口径;>48 必须升阶(order2=128)。 + needed: sizet = new_size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY if self.detection != 0: needed = needed + 4 # [DET] 前后标记 new_order: t.CInt = self._order_for_size(needed) @@ -1026,9 +1757,9 @@ class MemBuddy(MemManager): new_ptr: 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 - cp_len: t.CSizeT = old_data_size + old_block_size: sizet = _block_size_at_order(old_order) + old_data_size: sizet = old_block_size - MEMBUDDY_HEADER_SIZE + cp_len: sizet = old_data_size if self.detection != 0: cp_len = old_data_size - 4 # [DET] 排除前后 2 字节标记 string.memcpy(new_ptr, ptr, cp_len) @@ -1049,7 +1780,7 @@ class MemBuddy(MemManager): return 1 target: t.CUInt64T = t.CUInt64T(ptr) free_flag: t.CUInt64T = t.CUInt64T(1) << 63 - i: t.CSizeT = 0 + i: sizet = 0 while i < self._det_count: rp: t.CUInt64T = self._det_records[i * 2] rs: t.CUInt64T = self._det_records[i * 2 + 1] @@ -1068,7 +1799,7 @@ class MemBuddy(MemManager): if self._det_records is None: return free_flag: t.CUInt64T = t.CUInt64T(1) << 63 - i: t.CSizeT = 0 + i: sizet = 0 while i < self._det_count: p: t.CUInt64T = self._det_records[i * 2] s: t.CUInt64T = self._det_records[i * 2 + 1] @@ -1114,7 +1845,7 @@ class MemBuddy(MemManager): stdio.printf("\n记录上下文: ") ci2: t.CInt = -3 while ci2 <= 3: - idx2: t.CSizeT = t.CSizeT(t.CInt(i) + ci2) + idx2: sizet = sizet(t.CInt(i) + ci2) if idx2 < self._det_count: cip: t.CUInt64T = self._det_records[idx2 * 2] cis: t.CUInt64T = self._det_records[idx2 * 2 + 1] @@ -1123,7 +1854,7 @@ class MemBuddy(MemManager): # 重叠检测:同一 ptr 是否有多条记录(alloc 重叠实锤——不同 size # 请求拿到同一块 → 互相覆盖;如 Token(72B) 与字符串 buf(7B) 共用块) stdio.printf("\n同ptr记录: ") - ci3: t.CSizeT = 0 + ci3: sizet = 0 while ci3 < self._det_count: cp3: t.CUInt64T = self._det_records[ci3 * 2] cs3: t.CUInt64T = self._det_records[ci3 * 2 + 1] @@ -1138,46 +1869,64 @@ class MemBuddy(MemManager): # === Status Queries === @property - def mem_size(self) -> t.CSizeT: + def mem_size(self) -> sizet: # Total usable region size (power of two). Maximum allocatable size = mem_size - MEMBUDDY_HEADER_SIZE return self.usable_size - def stats(self) -> t.CSizeT: + def stats(self) -> sizet: # Return total usable region size, for status statistics return self.usable_size - def free_count(self) -> t.CSizeT: + def free_count(self) -> sizet: # Count total blocks in all order lists for status statistics - count: t.CSizeT = 0 + # 环检测(与 self_check 同界):本函数是诊断/OOM 报错路径的取数口, + # free list 成环时无上限会"打点自身卡死"(Phase1Main 的 dump_stats 前哨 + # 已按同一理由先调 self_check)。超限即停止该阶遍历,返回已数到的部分值。 + count: sizet = 0 i: t.CInt + max_steps: sizet = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 for i in range(MEMBUDDY_MAX_ORDERS + 1): head_val: t.CUInt64T = self.free_lists[i] cur: t.CPtr = t.CPtr(head_val) + steps: sizet = 0 while t.CUInt64T(cur) != 0: + steps += 1 + if steps > max_steps: + stdio.printf("[MEM] free_lists[%d] 链成环或节点数超上限(next 指针被破坏): head=%llu;停止计数避免自旋,堆已损坏\n", + i, head_val) + break count += 1 cur = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(cur))) return count - def free_bytes(self) -> t.CSizeT: + def free_bytes(self) -> sizet: # Count total bytes in all free blocks for status statistics - total: t.CSizeT = 0 + # 环检测(与 self_check 同界):语义同 free_count。 + total: sizet = 0 i: t.CInt + max_steps: sizet = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 for i in range(MEMBUDDY_MAX_ORDERS + 1): head_val: t.CUInt64T = self.free_lists[i] cur: t.CPtr = t.CPtr(head_val) + steps: sizet = 0 while t.CUInt64T(cur) != 0: + steps += 1 + if steps > max_steps: + stdio.printf("[MEM] free_lists[%d] 链成环或节点数超上限(next 指针被破坏): head=%llu;停止统计避免自旋,堆已损坏\n", + i, head_val) + break total += _block_size_at_order(i) cur = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(cur))) return total - def used_bytes(self) -> t.CSizeT: + def used_bytes(self) -> sizet: # Used bytes = total usable region size - free bytes in all free blocks return self.usable_size - self.free_bytes() - def dump_stats(self, label: t.CChar | t.CPtr): + def dump_stats(self, label: char | t.CPtr): # Print memory usage statistics - fb: t.CSizeT = self.free_bytes() - ub: t.CSizeT = self.usable_size - fb + fb: sizet = self.free_bytes() + ub: sizet = self.usable_size - fb stdio.printf("[MEM] %s: total=%zu used=%zu (%zu%%) free=%zu free_blocks=%zu\n", label, self.usable_size, ub, (ub * 100) / self.usable_size if self.usable_size > 0 else 0, @@ -1189,12 +1938,12 @@ class MemBuddy(MemManager): return 0 # 环检测:free list 被越界写破坏 next 指针后可能成环, # 无步数上限会导致无限循环(崩溃点漂移排查哨兵必须能终止)。 - max_steps: t.CSizeT = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 + max_steps: sizet = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 i: t.CInt for i in range(MEMBUDDY_MAX_ORDERS + 1): head_val: t.CUInt64T = self.free_lists[i] cur: t.CPtr = t.CPtr(head_val) - steps: t.CSizeT = 0 + steps: sizet = 0 while t.CUInt64T(cur) != 0: steps += 1 if steps > max_steps: @@ -1205,14 +1954,14 @@ class MemBuddy(MemManager): if t.CUInt64T(cur) >= t.CUInt64T(self.usable) + self.usable_size: return 2 # Check alignment: order i blocks must be aligned to size _block_size_at_order(i) - offset: t.CSizeT = t.CUInt64T(cur) - t.CUInt64T(self.usable) - bs: t.CSizeT = _block_size_at_order(i) + offset: sizet = t.CUInt64T(cur) - t.CUInt64T(self.usable) + bs: sizet = _block_size_at_order(i) if offset % bs != 0: return 3 cur = t.CPtr(c.Deref((t.CUInt64T | t.CPtr)(cur))) return 0 - def check_alive_blocks(self, from_mark: t.CSizeT) -> t.CInt: + def check_alive_blocks(self, from_mark: sizet) -> t.CInt: # 检查 [from_mark, chk_depth) 记录的所有已分配块 header 完整性。 # 越界写(参数错位/下标 GEP 越界)会破坏相邻块 header(奇偶位/order 错乱), # 返回 0=OK,非 0=损坏(rc 语义见调用方注释)。 @@ -1230,7 +1979,7 @@ class MemBuddy(MemManager): return 0 if self.usable is None: return 0 - ci: t.CSizeT = from_mark + ci: sizet = from_mark while ci < self.chk_depth: block: t.CPtr = t.CPtr(self.chk_stack[ci]) if block is not None: @@ -1259,8 +2008,8 @@ class MemBuddy(MemManager): stdio.printf("[MEM] 存活块损坏 rc=4(order 超 max_order): block=%llu order=%d max_order=%d ci=%zu from_mark=%zu\n", t.CUInt64T(block), order, self.max_order, ci, from_mark) return 4 - offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) - bs: t.CSizeT = _block_size_at_order(order) + offset: sizet = t.CUInt64T(block) - t.CUInt64T(self.usable) + bs: sizet = _block_size_at_order(order) if offset % bs != 0: # [TEMP-DIAG] 现场:块未对齐到该 order 的块大小 stdio.printf("[MEM] 存活块损坏 rc=5(块未对齐 order 大小): block=%llu order=%d bs=%zu offset=%zu ci=%zu from_mark=%zu\n", @@ -1276,7 +2025,12 @@ class MemBuddy(MemManager): # 指针 + 整数走 GEP ⇒ 每单位前进 sizeof(T)=8 字节 # ⇒ 实际读到 block + 8*bs - 64(order0/bs=32 时 = block+192), # 读到的是别的块(池内其它路径缓冲)的数据 ⇒ 假阳性 rc=6。 - can_stored: t.CPtr = t.CPtr(c.Deref(t.CPtr(t.CUInt64T(block) + bs - MEMBUDDY_CANARY))) + # 宽度只由指针的元素类型决定:canary 是 8 字节量,故必须给出 + # 有元素类型的指针视图 t.CUInt64T(x, t.CPtr)(→ i64*;本文件 + # 多处同款)。i8* 现在恒读 1 字节,不能再靠赋值目标注解反推。 + # 地址口径与原写法一致:先整数加减,再转指针。 + can_stored: t.CPtr = t.CPtr(c.Deref( + t.CUInt64T(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr))) if t.CUInt64T(can_stored) != t.CUInt64T(MEMBUDDY_CANARY_PATTERN): # [TEMP-DIAG] 越界写现场:块尾 canary 被写穿(rc=6 的判据)。 # 原实现只回 rc(int),调用方拿不到块/阶/实际值 → 无法定位。 @@ -1285,7 +2039,7 @@ class MemBuddy(MemManager): # 校验下标与窗口起点;canary vs 期望均以十六进制打印。 # printf 形式与格式符沿用本文件既有先例: # stdio.printf(...) / stdio.fflush(None) 见 L800-802、L816-817 - # %zu ← t.CSizeT(L1216 from_mark/chk_depth、L765 chk_cap/depth) + # %zu ← sizet(L1216 from_mark/chk_depth、L765 chk_cap/depth) # %llu ← t.CUInt64T(L800 size/ptr、L861 pool_base) # %d ← t.CInt(L816 dbg_order、L822) # %llx ← t.CUInt64T 十六进制(L917 header=0x%llX) diff --git a/mlirlite/README.md b/mlirlite/README.md new file mode 100644 index 0000000..8f1dc40 --- /dev/null +++ b/mlirlite/README.md @@ -0,0 +1,324 @@ +# mlirlite 设计方案 + +用 TransPyC 自身实现的 **MLIR(llvm 方言)文本发射库**。它与 `includes/llvmlite` +**逐名逐签名同形**:内部模型(类型/值/函数/基本块/构建器/模块)与公开 API 完全一致, +唯一区别是"打印"阶段输出 MLIR 文本而不是 LLVM IR 文本。 + +目的:让 TransPyV 侧只需把 `llvmlite.` 前缀重命名为 `mlirlite.` 即可编译, +从而在不改内部模型、不改 builders 的前提下切换到 MLIR 后端。 + +> 术语约定:文中"中间文本"指 builders 写进 `Line` 的**指令文本**(仍是 LLVM 语法, +> 如 `%0 = add i32 %a, %b`);"MLIR 文本"指 `FunctionPrint` / `LLVMModulePrint` +> 最终输出、可喂给 `mlir-translate` / `mlir-opt` 的文本。 + +--- + +## 1. 同形性边界 + +### 1.1 逐名同形(保证 `llvmlite.` → `mlirlite.` 重命名可编译) + +| 文件 | 内容 | 与 llvmlite 的关系 | +|------|------|--------------------| +| `__init__.vp` | 公共导出 + 便捷工厂(`create_function`/`const_int*`/`create_global_*` 等)+ `LLVMTypeCore`/`LLVMModuleCore` | **导入清单逐名一致(208 个名字),代码逐行一致**,仅注释不同 | +| `__types.vp` | `LLVMType`(REnum) / `ParamNode` / 类型工厂 / `TypePrint` / `DeepCopyType` | 模型与工厂**逐名同形**;`TypePrint` 改为 MLIR 语义,`PrintStructDefinition` 变为空操作 | +| `__values.vp` | `Value` / `ConstInt`/`ConstNull`/`ConstZero`/`ConstFloat`/`SSAValue` / `ValuePrint` | 模型与工厂同形;仅 `ValuePrint` 改为 MLIR 语义 | +| `__function.vp` | `Line`/`BasicBlock`/`Param`/`Function` + 工厂 + `RenumberSSA` + 窥孔 + `FunctionPrint` | 模型、`RenumberSSA`、本地窥孔**逐行一致**;`FunctionPrint` 重写为 MLIR 渲染 | +| `__builder.vp` | `IRBuilder` + 全部 `build_*` | **逐行一致**(仅 `_type_str` 的 fail-fast 校验字符集适配 MLIR 类型首字符) | +| `__module.vp` | `LLVMModule`/`GlobalVariable`/`NamedTypeNode` + `LLVMModulePrint` | 模型同形;`PrintModule` 与全局渲染改为 MLIR | +| `__verify.vp` | `VerifyResult`/`verify_function`/`verify_module` | **逐行一致**(校验的是内部模型 + 中间文本,与 MLIR 文本无关) | + +### 1.2 差异只在打印阶段(设计红线) + +- builders **一行不改**:仍按 LLVM 语法把指令文本写入 `Line`。 +- MLIR 特有的三类差异**全部集中在 `FunctionPrint` / `PrintModule` 内**: + 1. **常量物化**(MLIR 操作数不能是字面量); + 2. **phi → 块参数**(MLIR 块参数取代 phi 指令); + 3. **不透明指针**(所有指针渲染 `!llvm.ptr`)。 +- 因此"纯重命名可用"成立:模型层与 API 层不变,语义差异只体现在文本。 + +唯一的 builders 例外:`IRBuilder._type_str` 的 fail-fast 护栏原本只接受 LLVM 类型 +首字符(`i/f/d/h/l/m/v/%/[/{/.`),MLIR 类型首字符是 `!`(`!llvm.ptr`)或 `n`(`none`), +故把合法集合扩为 `i/f/!/n/[/{/%/"`。该改动只放宽校验、不改文本生成。 + +### 1.3 关键推论:中间文本里的类型已经是 MLIR 文本 + +builders 未改,而它们内嵌的类型一律来自 `IRBuilder._type_str` → `TypePrint`, +所以**中间指令文本里的类型已经是 MLIR 形态**。例如 `build_load` 生成的中间行是 + +``` +%1 = load i32, !llvm.ptr %p +``` + +(llvmlite 版同位置是 `%1 = load i32, i32* %p`)。由此: + +- `MlirTypeText`(中间类型文本 → MLIR 类型文本)以 **`!llvm.…` / `none` 直通**为主路径, + 同时保留 LLVM 语法分支(`i8*`、`[N x x]`、`{…}`)以兼容手工构造的中间文本; +- 结构体类型在中间文本里就已是完整内联形态 `!llvm.struct<(…)>`, + 因此**不需要**命名结构体类型登记表,也不存在 `%"name"`(出现即响亮报错); +- `_mlir_read_type` 的类型读取按 `[] {} () <>` 统一做括号平衡, + 以正确读出含空格/逗号的 `!llvm.array<…>` / `!llvm.struct<(…)>`。 + +--- + +## 2. MLIR 渲染规则表 + +### 2.1 类型(`TypePrint`) + +| 内部模型 | MLIR 文本 | +|----------|-----------| +| `Int1/8/16/32/64` | `i1/i8/i16/i32/i64` | +| `Half/Float/Double/FP128` | `f16/f32/f64/f128` | +| `Ptr(_)` | `!llvm.ptr`(不透明指针;pointee 只保留在内部模型里) | +| `Array(elem,N)` | `!llvm.array`(嵌套:`!llvm.array<2 x !llvm.array<3 x i8>>`) | +| `Struct(fields,N,name)` | `!llvm.struct<(f0, f1, …)>`;空 → `!llvm.struct<()>`(**名字不参与渲染**) | +| `Func(ret,params)` | `!llvm.func` | +| `Void` | `none`(仅必须打印时;函数返回值位置**省略**) | +| `Label` / `Metadata` | **v1 不支持 → 响亮报错** | + +中间文本 → MLIR 类型文本的转换(`MlirTypeText`,用于 op 行里的类型标注): + +| 中间文本 | MLIR 文本 | +|----------|-----------| +| `!llvm.ptr` / `!llvm.array<…>` / `!llvm.struct<(…)>` / `!llvm.func<…>` | **直通**(builders 内嵌类型的实际形态) | +| `none` | `none`(builders 对 `Void` 的类型文本) | +| `void` / `half` / `float` / `double` / `fp128` | `none` / `f16` / `f32` / `f64` / `f128` | +| `iN` | `iN` | +| 任意以 `*` 结尾(`i8*`、`i8**`) | `!llvm.ptr` | +| `[N x T]` | `!llvm.array` | +| `{T1, T2}` | `!llvm.struct<(T1', T2')>` | +| `%name`(只有名字的结构体类型) | **v1 不支持 → 响亮报错**(中间文本不应出现该形态) | +| `T (P0, P1)` | `!llvm.func` | + +### 2.2 函数 / 块 / 指令 + +``` +llvm.func @add(%a: i32, %b: i32) -> i32 { + %0 = llvm.add %a, %b : i32 + llvm.return %0 : i32 +} +``` + +- void 返回:`llvm.func @noop() { … llvm.return }`;declare(无体):`llvm.func @f(%x: i32) -> i32` +- **entry 块不带标签**;后续块 `^:`(块名去掉前导 `%`) +- 块参数:`^merge(%7: i32):`(块首连续 phi 变成块参数,phi 行不再输出) + +| 中间文本 | MLIR 文本 | +|----------|-----------| +| `%N = add i32 %a, %b` | `%N = llvm.add %a, %b : i32`(sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr 同) | +| `%N = fadd f64 %a, %b` | `%N = llvm.fadd %a, %b : f64`(fsub/fmul/fdiv/frem 同) | +| `%N = fneg f64 %a` | `%N = llvm.fneg %a : f64` | +| `%N = icmp sgt i32 %a, %b` | `%N = llvm.icmp "sgt" %a, %b : i32` | +| `%N = fcmp oeq f64 %a, %b` | `%N = llvm.fcmp "oeq" %a, %b : f64` | +| `%N = alloca i32` | `%N = llvm.alloca %c0 x i32 : (i32) -> !llvm.ptr`(个数按常量 op 物化) | +| `%N = load i32, !llvm.ptr %p` | `%N = llvm.load %p : !llvm.ptr -> i32` | +| `store i32 %v, !llvm.ptr %p` | `llvm.store %v, %p : i32, !llvm.ptr` | +| `%N = getelementptr i32, !llvm.ptr %p, i64 %i` | `%N = llvm.getelementptr %p[%i] : (!llvm.ptr, i64) -> !llvm.ptr, i32` | +| `%N = getelementptr !llvm.array<4 x i32>, !llvm.ptr %p, i32 0, i64 %i` | `%N = llvm.getelementptr %p[%c0, %i] : (!llvm.ptr, i32, i64) -> !llvm.ptr, !llvm.array<4 x i32>` | +| `%N = getelementptr !llvm.struct<(i32, !llvm.ptr)>, !llvm.ptr %p, i32 0, i32 1` | `%N = llvm.getelementptr %p[%c0, %c1] : (!llvm.ptr, i32, i32) -> !llvm.ptr, !llvm.struct<(i32, !llvm.ptr)>` | +| `%N = bitcast !llvm.ptr %p to !llvm.ptr` | **no-op**:不输出指令,`%N` 登记为 `%p` 的别名(后续引用自动改写) | +| `%N = bitcast i32 %v to f32` | `%N = llvm.bitcast %v : i32 to f32` | +| `%N = trunc i64 %v to i32` | `%N = llvm.trunc %v : i64 to i32`(zext/sext/ptrtoint/inttoptr/fpext/fptrunc/fptosi/sitofp/fptoui/uitofp 同构) | +| `%N = call i32 @f(i32 %a)` | `%N = llvm.call @f(%a) : (i32) -> i32` | +| `call none @f(i32 %a)` | `llvm.call @f(%a) : (i32) -> ()`(`Void` 的中间类型文本是 `none`) | +| `%N = call i32 %fp(i32 %a)` | `%N = llvm.call %fp(%a) : !llvm.ptr, (i32) -> i32` | +| `br label %blk` | `llvm.br ^blk`(目标有块参数时 `llvm.br ^merge(%c0 : i32)`) | +| `br i1 %c, label %t, label %e` | `llvm.cond_br %c, ^t, ^e` | +| `ret i32 %v` / `ret void` | `llvm.return %v : i32` / `llvm.return` | +| `unreachable` | `llvm.unreachable` | +| `%N = select i1 %c, i32 %a, i32 %b` | `%N = llvm.select %c, %a, %b : i1, i32` | +| `switch i32 %v, label %d [i32 0, label %c0]` | `llvm.switch %v, ^d [0: ^c0]`(case 值是属性,不物化) | +| `%N = atomicrmw add !llvm.ptr %p, i32 %v monotonic` | `%N = llvm.atomicrmw add %p, %v monotonic : !llvm.ptr, i32` | + +### 2.3 常量必须物化为 op(关键) + +MLIR 的操作数不能是字面量。**扫描阶段**(pass 1)遍历函数所有指令行,凡非 SSA +操作数(整数/浮点字面量、`null`、`zeroinitializer`、`@符号引用`)都在**常量表** +登记 `(MLIR 类型, 常量文本)`;**发射阶段**(pass 2)在 **entry 块开头**按登记顺序 +生成物化 op,并在原位置改用 `%cN`: + +| 常量 | 物化 op | +|------|---------| +| `i32 42` | `%c0 = llvm.mlir.constant(42 : i32) : i32` | +| `f64 0x40091EB851EB851F` | `%c0 = llvm.mlir.constant(3.140000e+00 : f64) : f64`(位模式 → 十进制科学计数法) | +| `null` / `zeroinitializer` | `%c0 = llvm.mlir.zero : !llvm.ptr`(或 `: i32` 等) | +| `@f` / `@"sha1.x"` | `%c0 = llvm.mlir.addressof @f : !llvm.ptr` | + +- 同函数内相同 `(类型, 文本)` **只物化一次**; +- 常量统一放 entry 块开头 ⇒ entry 支配全函数,常量在所有块内可见, + 且**不破坏 phi 的"块首"约束**(phi 只在非 entry 块,块首仍由 phi 独占); +- `phi` 入边里的常量同样会被物化(`phi` 行在 pass 1 也参与扫描,只是发射阶段不输出)。 + +### 2.4 phi → 块参数 + +- 块首**连续** phi ⇒ 建立块参数:`^merge(%7: i32):`,phi 行**不再输出**; +- 跳转到该块的 `br`/`cond_br` 按**源块**匹配入边追加实参:`llvm.br ^merge(%c1 : i32)`; +- 找不到匹配入边 ⇒ **响亮报错**(绝不静默丢实参); +- phi 不在块首(非连续)⇒ **响亮报错**; +- entry 块出现 phi ⇒ **响亮报错**(MLIR entry 块不接受块参数)。 + +### 2.5 全局变量 + +| 内部模型 | MLIR 文本 | +|----------|-----------| +| 字符串常量(`c"hello\00"`,`[6 x i8]`) | `llvm.mlir.global private unnamed_addr constant @".str"("hello\00") : !llvm.array<6 x i8>` | +| 整数全局(`0`,`i32`) | `llvm.mlir.global @counter(0 : i32) : i32` | +| stub 模式(无初值) | `llvm.mlir.global external @x : i32` | +| linkage / constant / unnamed_addr | 对应关键字(`private`/`internal`/`linkonce_odr`、`constant`、`unnamed_addr`) | +| section / align | 属性字典 `{section = "…", alignment = N : i64}`(**形态未经 mlir-opt 验证**) | +| 整型/浮点数组 `[i8 1, i8 2]` | `[1 : i8, 2 : i8]`(元素**带类型注解**;`dense<…>` 对 `!llvm.array` **非法**) | +| `null` / `zeroinitializer` | `zeroinitializer` | + +- `module_set_target` / `module_set_datalayout`:MLIR 模块不携带 triple/datalayout + ⇒ **记录但不输出**,模块输出里给一行注释标明"由 mlir-translate / llc 阶段提供"。 + +**⚠ 三条由 mlir-opt 22.1.8 实测确立的硬约束(违反即解析/校验失败)** + +1. **符号名判据与 LLVM 不同**:MLIR 裸标识符**首字符必须是字母或 `_`**,且 + **不允许 `-`**(LLVM 允许)。⇒ TPV 的 `{sha1}.{name}`(sha1 以数字开头)与 + `@.str`(以 `.` 开头)**一律需要 `@"…"` 引号形式**。判据见 + `__function.vp:_ll_name_needs_quote`,输出统一走 `_MlirSymRefAppend`。 +2. **字符串属性长度必须等于 i8 数组长度**:TPV 的字符串常量类型含尾随 NUL + (`[N+1 x i8]`)⇒ 属性里**必须保留 `\00`**。**绝不能**为了对齐长度去剥掉 + 类型里的 NUL —— 那会丢掉 C 字符串终止符、破坏 ABI。 +3. **`dense<[…] : !llvm.array<…>>` 非法**(`dense` 只接受 builtin shaped 类型 + tensor/vector);数组属性必须是 `值 : 类型` 的元素列表形态,且元素类型与 + 全局类型一致(元素不注解时按 i64 解释)。 + +**⚠ 验收口径**:类型文本、值文本、**裸函数**都不是合法的 MLIR 顶层单元 +(类型/值不是顶层 op;裸函数父级不是 SymbolTable,其外部符号引用无法解析) +⇒ **一律以整模块(`module {}`)作为验收单元**。 + +### 2.6 模块输出 + +``` +module { + // MLIR-TEXT: 仅带体函数与含初值全局 ← 模式注释(MLIR 无 stub/text 二分) + llvm.mlir.global … + llvm.func @f(…) -> i32 { … } +} +``` + +| 模式 | MLIR 输出 | +|------|-----------| +| `OUTPUT_FULL` | 全量(全局 + 全部函数) | +| `OUTPUT_STUB` | 只输出全局 `external` 声明 + 函数 declare(无体) | +| `OUTPUT_TEXT` | 只输出带体函数 + 含初值的全局 | + +`ValuePrint`:SSA → `%0`;常量 → `42 : i32`(**仅供诊断**)。 +指令渲染**不依赖** `ValuePrint`,`FunctionPrint` 用自己的操作数解析。 + +--- + +## 3. v1 支持 / 不支持清单 + +### 3.1 支持(已实现) + +类型:`iN` 全整数、`f16/f32/f64/f128`、不透明指针、数组、结构体、函数类型、`Void`。 + +指令:`add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr`、 +`fadd/fsub/fmul/fdiv/frem/fneg`、`icmp/fcmp`、`alloca`、`load/store`(含 `volatile`)、 +`getelementptr`(单索引 / 数组 / 结构体)、`bitcast`(ptr→ptr 折叠为 no-op)、 +`sext/trunc/zext/ptrtoint/inttoptr/fpext/fptrunc/fptosi/sitofp/fptoui/uitofp`、 +`call`(直接 / 间接)、`br/cond_br`(含块实参)、`ret/ret void`、`unreachable`、 +`select`、`phi`(→ 块参数)、`switch`、`atomicrmw`。 + +全局初值:整数、浮点、`null`、`zeroinitializer`、cstring、整型数组(含嵌套数组)。 + +### 3.2 不支持 —— 一律**响亮报错**(`MlirFail`:打印定位信息后 `exit(1)`) + +| 形态 | 报错位点(函数) | 报文 | +|------|------------------|------| +| `Label` 类型 | `TypePrint` / `_MlirTypePrintDepth` | `TypePrint(Label): MLIR 无 label 类型,v1 不支持` | +| `Metadata` 类型 | `TypePrint` / `_MlirTypePrintDepth` | `TypePrint(Metadata): MLIR llvm 方言 v1 不支持 metadata 类型` | +| `alloca …, align N` | `_MlirAlloca` | `alloca 对齐(build_alloca_aligned)v1 不支持` | +| 变参函数 `...` | `_MlirFuncSig` | `变参函数(...)的 llvm.func 形态未固化,v1 不支持` | +| 变参 `call`(builder 的 `call () @f(...)`) | `_MlirCall` | `变参 call 的 MLIR 形态未固化,v1 不支持` | +| `cmpxchg` | `_MlirRenderLine` | `cmpxchg 的 MLIR 形态未固化,v1 不支持` | +| `va_arg` | `_MlirRenderLine` | `va_arg v1 不支持` | +| 内联汇编(中间文本为 `call asm …`) | `_MlirCall` | `inline_asm 的 MLIR 形态未固化,v1 不支持` | +| `{ … }` 结构体 / vtable 全局初始化串 | `_MlirGlobalInit` | `全局初值形态 v1 不支持(结构体/vtable 初始化串需改用结构化初始化)` | +| phi 不在块首(非连续) | `_MlirRenderLine` | `phi 不在块首(v1 只支持块首连续 phi → 块参数)` | +| entry 块出现 phi | `_MlirCheckEntryNoPhi` | `entry 块不允许 phi(MLIR entry 块不接受块参数)` | +| 跳转目标带 phi 但缺匹配入边 | `_MlirBlockOperands` | `跳转目标块带 phi,但找不到与源块匹配的入边` | +| `switch` 目标块带 phi | `_MlirSwitch` | `switch 目标块带 phi(携带块实参)v1 不支持` | +| `switch` case 值是 SSA | `_MlirSwitch` | `switch case 值必须是常量(SSA 值不支持)` | +| `%name` 命名结构体类型文本(中间文本里不应出现) | `_MlirNamedStructText` | `命名结构体类型文本 v1 不支持(应使用内联 !llvm.struct<(…)>)` | +| 中间文本里出现未知 opcode | `_MlirRenderLine` | `未知指令 opcode` | +| 无法转换的类型文本 | `_MlirTypeAppend` | `无法转换为 MLIR 类型文本(v1 未覆盖该形态)` | +| 常量操作数形态非 整数/浮点/null/符号 | `_MlirEmitOneConst` | `不支持的常量操作数形态` | +| 常量表 / 别名表溢出 | `_MlirConstGet` / `_MlirAliasAdd` | `常量表溢出` / `bitcast 别名表溢出` | + +### 3.3 记录但不输出(信息不丢,但不在 MLIR 文本里) + +- `module_set_target` / `module_set_datalayout`:MLIR 模块不携带,由 + `mlir-translate` / `llc` 阶段提供(模块输出里有注释标明)。 +- 函数属性 `Attrs` / `AttrGroup` / `AttrGroupId`:MLIR 的属性表达方式差异较大, + v1 **记录但不渲染**(模型字段保留,`function_set_attrs` / `function_set_attr_group` 同名可用)。 +- `Param.Attrs`(`noundef`/`nocapture` 等):同上。 +- `NamedTypeHead` 类型定义链表:MLIR 无独立类型定义语法,结构体在使用处内联为 + `!llvm.struct<(…)>`;`module_add_named_type` 保留模型语义(去重/opaque 替换)但 + 不再产生输出文本,`PrintStructDefinition` 输出空串(保留 API 同形)。 + +--- + +## 4. 与 llvmlite 的语义差异(**同形但语义必然不同**) + +| # | 同形点 | 语义差异 | +|---|--------|----------| +| 1 | `TypePrint(buf,size,ty,pool)` | 输出 MLIR 类型而非 LLVM 类型;`Ptr(_)` 恒为 `!llvm.ptr`(丢失 pointee),`Void` 为 `none`,`Label` 报错 | +| 2 | `ValuePrint(buf,size,val,pool)` | SSA 只输出 `%0`(不带类型);常量输出 `42 : i32`;llvmlite 版是 `i32 42` | +| 3 | `FunctionPrint(buf,size,func,pool)` | 输出 `llvm.func`/`llvm.*` op;**入口常量物化**、**phi→块参数**、**no-op bitcast 折叠** | +| 4 | `LLVMModulePrint(buf,size,mod,pool,mode)` | 输出 `module { … }`;`OUTPUT_STUB/TEXT` 只能用注释标示(MLIR 无此二分);triple/datalayout 不输出 | +| 5 | `IRBuilder.build_bitcast(val,to_ty)` | 返回的 `Value` 名字仍会出现在中间文本里,但打印时若两端都是指针则**整个指令消失**、名字被别名替换(`Value` 对象本身不变) | +| 6 | `IRBuilder.build_phi` / `build_br` | builder 语义不变(仍写 phi 行);MLIR 打印时 phi 行消失、br 追加实参 | +| 7 | `IRBuilder.build_alloca` | 打印时个数按常量 `1`(i32)物化;`build_alloca_aligned` 报错 | +| 8 | `const_int` / `ConstFloat` | `Name` 文本仍是 llvmlite 形态(十进制 / `0x` 位模式);**转换发生在打印阶段**(浮点位模式→十进制科学计数法) | +| 9 | `create_global_string` | `Initializer` 仍是 `c"…\00"`;打印时转成 `"…"`(**去掉尾随 `\00`**,见 §5 待确认) | +| 10 | `verify_function` / `verify_module` | 校验内部模型 + 中间文本(与 llvmlite 完全一致);**不**校验 MLIR 文本合法性(交给 mlir-opt) | +| 11 | `PrintStructDefinition` | 输出空串(MLIR 无类型定义行),llvmlite 版输出 `%"name" = type {…}` | +| 12 | `G_PeepEnable` | 语义不变:窥孔作用在**中间文本**(`ret zeroinitializer→0/null`、入口槽 store→load 转发、no-op bitcast 消除),与 MLIR 渲染正交(T3 与 MLIR 的 no-op 折叠叠加,结果一致) | +| 13 | `module_set_named_type_packed` | 语义不变(记录 packed);MLIR 侧 packed 布局未参与渲染(字段列表渲染不区分 packed) | +| 14 | 中间指令文本(`Line.Buf`) | **内容与 llvmlite 不同**:builders 内嵌类型经 `_type_str` → `TypePrint` 已是 MLIR 形态(`load i32, !llvm.ptr %p` 而非 `load i32, i32* %p`)。文本层使用者(窥孔、verify)按名称/结构匹配,语义不受影响 | + +--- + +## 5. 待确认(不做静默假设,逐条标注) + +1. `switch` 的方言形态按设计规范输出 `llvm.switch %v, ^default [0: ^case0, …]`, + 未用 `mlir-opt` 校验(真实 MLIR 可能要求 `%v : i32, ^default [ … ]` 形式)。 +2. `alloca` / `load` / `store` 的 `volatile`、`atomicrmw` 的 ordering 关键字按 + LLVM 词法直译为 MLIR 词法,未用 `mlir-opt` 校验。 +3. 全局 `{section = "…", alignment = N : i64}` 属性字典的**位置**(值之后、类型之前) + 未用 `mlir-opt` 校验。 +4. `c"hello\00"` → `"hello"`:按设计规范**去掉尾随 `\00`**(设计规范样例为 + `@.str("hello") : !llvm.array<6 x i8>`)。严格 MLIR 语义下 `!llvm.array<6 x i8>` + 需要 6 字节;若工具链要求显式 NUL,去掉 `_MlirCStringToMlir` 里的剥离逻辑即可。 +5. `Func(Void, …)` 的类型文本渲染为 `!llvm.func`(由 `Void → none` 规则 + 组合而来);函数签名位置的 void 返回值则是**省略** `-> ty`(不影响)。 +6. 渲染期的常量表 / 别名表 / 解析 scratch 都是**模块级全局**(每次 `FunctionPrint` + 重新初始化),因此本库的打印阶段**不可重入**:同一进程内不支持两个线程同时打印 + (与 llvmlite 的 `_g_last_dst` 等全局缓存同一假设)。 +7. 每次 `FunctionPrint` 会从内存池分配约 **40KB** 的常量表(512 项)与解析 scratch + (20 个缓冲),模块打印另需一个 64KB 临时缓冲。函数数量很大的编译单元需要相应 + 放大编译器内存池;后续若要降内存,可改为"同一池内一次性分配并复用"。 +8. `MlirFail` 采用 `stdio.printf` + `stdlib.exit(1)` 的 fail-fast 风格(对齐 llvmlite + 的 `[IR-DUMP]`/`[IR-FAIL]`):不支持形态会**终止进程**而非返回错误码。 + +--- + +## 6. 文件结构 + +``` +includes/mlirlite/ +├── __init__.vp # 公共导出(与 llvmlite 逐名一致)+ 便捷工厂 + *Core 类 +├── __types.vp # LLVMType(REnum) + 类型工厂 + MLIR TypePrint + 命名类型登记 +├── __values.vp # Value/常量/SSA + MLIR ValuePrint +├── __function.vp # Function/BasicBlock/Line + RenumberSSA + 窥孔 + MLIR FunctionPrint +├── __module.vp # LLVMModule/GlobalVariable + MLIR 模块与全局渲染 +├── __builder.vp # IRBuilder(与 llvmlite 逐行一致) +├── __verify.vp # SSA 验证器(与 llvmlite 逐行一致) +└── README.md # 本文件 +``` + +测试:`Test/MLIRLiteTest/`(`App/main.vp` + `project.json`),用 `testcheck` +断言各渲染规则(类型 / 函数 / 模块 / 常量物化 / phi→块参数 / 内存·调用·转换 / 全局 / verify)。 diff --git a/mlirlite/__builder.vp b/mlirlite/__builder.vp new file mode 100644 index 0000000..98624c2 --- /dev/null +++ b/mlirlite/__builder.vp @@ -0,0 +1,1884 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import stdio +import stdlib +from linkedlist import GSListNode, GSList +from .__types import LLVMType, TypePrint +from .__values import Value, new_value, SSAValue +from .__function import Function, BasicBlock, block_append_text, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote, block_insert_text_before_terminator + +# ============================================================ +# IRBuilder: 游标式 IR 指令发射器 +# +# 跟踪当前 BasicBlock,将指令文本追加到块的指令链表。 +# 维护递增的 SSA 名计数器(%0, %1, %2, ...)。 +# +# 用法: +# builder = new_builder(pool, func) +# builder.PositionAtEnd(entry_block) +# a = builder.build_alloca(i32_ty) +# b = builder.build_alloca(i32_ty) +# builder.build_store(ConstInt(42), a) +# r = builder.build_load(i32_ty, a) +# builder.build_ret(r) +# +# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=32 保持一致 +# (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。 +# ============================================================ +novirtual class IRBuilder: + Pool: memhub.MemBuddy* # 内存池 + Func: rawptr[Function] # 所属函数 + CurBlock: rawptr[BasicBlock] # 当前插入点 + Counter: int # SSA 名计数器 + + # ============================================================ + # 内部辅助 + # ============================================================ + def _alloc_ssa_name(self) -> str: + """分配一个 SSA 名字符串 "%N" 并递增计数器""" + pool: memhub.MemBuddy* = self.Pool + buf: str = pool.alloc(16) + if buf is None: return None + viperlib.snprintf(buf, 16, "%%%d", self.Counter) + self.Counter += 1 + return buf + + + def _type_str(self, ty: rawptr[LLVMType]) -> str: + """获取类型的 MLIR 文本(从 pool 分配 512 字节缓冲区) + + 注意:复杂结构体类型(如 13 方法的虚表 !llvm.struct<(...)>)可能超过 + 64 字节,必须使用足够大的缓冲区,否则 '>' 会被截断导致语法错误。 + """ + pool: memhub.MemBuddy* = self.Pool + buf: str = pool.alloc(512) + if buf is None: return None + buf[0] = '\0' + TypePrint(buf, 512, ty, pool) + # [IR-FAIL] 校验护栏:LLVMType 类型对象可能被 MemBuddy 覆盖/悬空 + # (跨遍 reset 回收后 pool 内存复用),此时 TypePrint 输出首字符 + # 变为垃圾(如 't')或为空。立即 fail-fast 终止,防止生成 + # 垃圾 op 行,避免后续报错难以定位根因。 + # 合法首字符:MLIR 类型('i'/'f'/'!llvm.' 的 '!')与 + # 中间文本里可能出现的 '{'/'['/'"'(聚合/命名类型)等。 + c0: int = buf[0] + if c0 == 0 or (c0 != 'i' and c0 != 'f' and c0 != '!' and c0 != 'n' and + c0 != '[' and c0 != '{' and c0 != '%' and c0 != '"'): + stdio.printf("[IR-FAIL] _type_str: LLVMType 对象已损坏 ty=0x%llx 首字符=%d 输出='%s'\n", + t.CUInt64T(ty), c0, buf) + stdlib.exit(1) + return None + return buf + + + def _emit(self, text: str): + """将指令文本追加到当前块""" + if self is None or self.CurBlock is None: return + block_append_text(self.Pool, self.CurBlock, text) + + + def _mark_terminated(self): + """标记当前块已终止""" + if self is None or self.CurBlock is None: return + block_set_terminated(self.CurBlock, 1) + + + def _build_binop(self, op: str, + lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: + """二元运算通用实现""" + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(lhs.Ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = %s %s %s, %s", name, op, ty_s, lhs.Name, rhs.Name) + self._emit(line) + return SSAValue(pool, lhs.Ty, name) + + + # ============================================================ + # 块定位 + # ============================================================ + def position_at_end(self, block: rawptr[BasicBlock]): + """将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。 + + 移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致, + 避免 SSA 名在文本中非单调递增导致 llc 编译失败。 + """ + if self is None: return + self.CurBlock = block + if self.Func is not None: + function_move_block_to_end(self.Func, block) + + + def builder_cur_block_is_terminated(self) -> int: + """检查当前块的 IsTerminated 标志 + + 通过 block_get_terminated 辅助函数访问,避免链式属性 + self.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque + 导致的 GEP 静默跳过问题。 + """ + if self is None or self.CurBlock is None: + return 1 + return block_get_terminated(self.CurBlock) + + + # ============================================================ + # 内存指令 + # ============================================================ + def build_alloca(self, ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = alloca + + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 + """ + if self is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(ty) + line: str = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s", name, ty_s) + self._emit(line) + + # 结果类型是 ty* + result_ty: rawptr[LLVMType] = LLVMType.Ptr(ty) + result_ty_ptr: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_alloca_aligned(self, ty: rawptr[LLVMType], + align: int) -> rawptr[Value]: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + if self is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(ty) + line: str = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s, align %d", name, ty_s, align) + self._emit(line) + + # 结果类型是 ty* + result_ty: rawptr[LLVMType] = LLVMType.Ptr(ty) + result_ty_ptr: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_alloca_at_entry(self, ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = alloca (在函数入口块生成,确保支配性) + + 在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca + 导致的支配性违规(Instruction does not dominate all uses)。 + """ + if self is None: return None + pool: memhub.MemBuddy* = self.Pool + func: rawptr[Function] = self.Func + if func is None or func.Blocks is None: + return self.build_alloca(ty) + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + entry_blk: rawptr[BasicBlock] = blocks.Head + if entry_blk is None: + return self.build_alloca(ty) + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(ty) + line_text: str = pool.alloc(128) + if line_text is None: return None + viperlib.snprintf(line_text, 128, "%s = alloca %s", name, ty_s) + # 在入口块终止指令之前插入:若入口块已以 br/ret 终止(如嵌套循环内 + # 再分配循环变量),block_append_text 会把 alloca 追加到终止指令之后, + # 生成 "br 之后不可达指令" 的非法 IR(llc: "instruction expected to be + # numbered '%N' or greater")。block_insert_text_before_terminator + # 在块未终止时等同追加,已终止时插到终止指令之前。 + block_insert_text_before_terminator(pool, entry_blk, line_text) + # 结果类型是 ty* + result_ty: rawptr[LLVMType] = LLVMType.Ptr(ty) + result_ty_ptr: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_load(self, ty: rawptr[LLVMType], + ptr: rawptr[Value], + is_volatile: int = 0) -> rawptr[Value]: + """%N = load [volatile ], + + is_volatile=0(默认)逐字输出既有形态;=1 时在 load 后插入 volatile + 限定符(`%N = load volatile i32, i32* %p`),供自旋锁等必须禁止 + 优化器提升/合并重复访问的场景使用。 + """ + if self is None or ptr is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(ty) + ptr_ty_s: str = self._type_str(ptr.Ty) + line: str = pool.alloc(256) + if line is None: return None + if is_volatile != 0: + viperlib.snprintf(line, 256, "%s = load volatile %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) + else: + viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) + self._emit(line) + return SSAValue(pool, ty, name) + + + def build_store(self, val: rawptr[Value], ptr: rawptr[Value], + is_volatile: int = 0): + """store [volatile ] , + + is_volatile=0(默认)逐字输出既有形态;=1 时在 store 后插入 volatile + 限定符(`store volatile i32 %v, i32* %p`)。 + """ + if self is None or val is None or ptr is None: return + pool: memhub.MemBuddy* = self.Pool + val_ty_s: str = self._type_str(val.Ty) + ptr_ty_s: str = self._type_str(ptr.Ty) + line: str = pool.alloc(256) + if line is None: return + if is_volatile != 0: + viperlib.snprintf(line, 256, "store volatile %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) + else: + viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) + self._emit(line) + + + # ============================================================ + # 二元运算指令 + # ============================================================ + def build_add(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = add , """ + return self._build_binop("add", lhs, rhs) + + + def build_sub(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = sub , """ + return self._build_binop("sub", lhs, rhs) + + + def build_mul(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = mul , """ + return self._build_binop("mul", lhs, rhs) + + + def build_sdiv(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = sdiv , """ + return self._build_binop("sdiv", lhs, rhs) + + + def build_udiv(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = udiv , """ + return self._build_binop("udiv", lhs, rhs) + + + def build_srem(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = srem , """ + return self._build_binop("srem", lhs, rhs) + + + def build_urem(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = urem , """ + return self._build_binop("urem", lhs, rhs) + + + def build_and(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = and , """ + return self._build_binop("and", lhs, rhs) + + + def build_or(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = or , """ + return self._build_binop("or", lhs, rhs) + + + def build_xor(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = xor , """ + return self._build_binop("xor", lhs, rhs) + + + def build_shl(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = shl , """ + return self._build_binop("shl", lhs, rhs) + + + def build_lshr(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = lshr , """ + return self._build_binop("lshr", lhs, rhs) + + + def build_ashr(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = ashr , """ + return self._build_binop("ashr", lhs, rhs) + + + # ============================================================ + # 浮点二元运算指令 + # ============================================================ + def build_fadd(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fadd , """ + return self._build_binop("fadd", lhs, rhs) + + + def build_fsub(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fsub , """ + return self._build_binop("fsub", lhs, rhs) + + + def build_fmul(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fmul , """ + return self._build_binop("fmul", lhs, rhs) + + + def build_fdiv(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fdiv , """ + return self._build_binop("fdiv", lhs, rhs) + + + def build_frem(self, lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = frem , """ + return self._build_binop("frem", lhs, rhs) + + + def build_fneg(self, val: rawptr[Value]) -> rawptr[Value]: + """%N = fneg """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(val.Ty) + line: str = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = fneg %s %s", name, ty_s, val.Name) + self._emit(line) + return SSAValue(pool, val.Ty, name) + + + # ============================================================ + # 比较指令 + # ============================================================ + def build_icmp(self, pred: int, + lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: + """%N = icmp , + + 返回类型为 i1 的 SSA 值 + """ + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(lhs.Ty) + pred_s: str = _icmp_pred_str(pred) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = icmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name) + self._emit(line) + + # 结果类型是 i1 + i1_ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if i1_ty is not None: + string.memset(i1_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i1_ty, LLVMType.Int(1)) + return SSAValue(pool, i1_ty, name) + + + def build_fcmp(self, pred: int, + lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fcmp , + + 返回类型为 i1 的 SSA 值 + """ + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(lhs.Ty) + pred_s: str = _fcmp_pred_str(pred) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fcmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name) + self._emit(line) + + # 结果类型是 i1 + i1_ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if i1_ty is not None: + string.memset(i1_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i1_ty, LLVMType.Int(1)) + return SSAValue(pool, i1_ty, name) + + + # ============================================================ + # 终止指令 + # ============================================================ + def build_br(self, target: rawptr[BasicBlock]): + """br label %""" + if self is None or target is None: return + pool: memhub.MemBuddy* = self.Pool + line: str = pool.alloc(64) + if line is None: return + viperlib.snprintf(line, 64, "br label %%%s", target.Name) + self._emit(line) + self._mark_terminated() + + + def build_cond_br(self, cond: rawptr[Value], + then_blk: rawptr[BasicBlock], else_blk: rawptr[BasicBlock]): + """br i1 , label %, label %""" + if self is None or cond is None or then_blk is None or else_blk is None: return + pool: memhub.MemBuddy* = self.Pool + line: str = pool.alloc(128) + if line is None: return + viperlib.snprintf(line, 128, "br i1 %s, label %%%s, label %%%s", + cond.Name, then_blk.Name, else_blk.Name) + self._emit(line) + self._mark_terminated() + + + def build_ret(self, val: rawptr[Value]): + """ret """ + if self is None or val is None: return + pool: memhub.MemBuddy* = self.Pool + ty_s: str = self._type_str(val.Ty) + line: str = pool.alloc(128) + if line is None: return + viperlib.snprintf(line, 128, "ret %s %s", ty_s, val.Name) + self._emit(line) + self._mark_terminated() + + + def build_ret_void(self): + """ret void""" + if self is None: return + pool: memhub.MemBuddy* = self.Pool + line: str = pool.alloc(16) + if line is None: return + string.strcpy(line, "ret void") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # 调用指令 + # ============================================================ + def build_call(self, callee: str, + args: rawptr[Value], arg_count: int, + ret_ty: rawptr[LLVMType], + is_variadic: int = 0) -> rawptr[Value]: + """%N = call @() + + args 是 Value 链表头,arg_count 是参数数量。 + 若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。 + is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 + """ + if self is None: return None + pool: memhub.MemBuddy* = self.Pool + + # 判断返回类型是否为 void + is_void: int = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: str = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: str = self._type_str(ret_ty) + + # 构建参数列表文本 + 变参函数类型签名 + args_buf: str = pool.alloc(1024) + if args_buf is None: return None + args_buf[0] = '\0' + func_ty_buf: str = pool.alloc(1024) + if func_ty_buf is None: return None + func_ty_buf[0] = '\0' + cur: rawptr[Value] = args + first: int = 1 + while cur is not None: + if first == 0: + _append_cstr(args_buf, 1024, ", ") + _append_cstr(func_ty_buf, 1024, ", ") + arg_ty_s: str = self._type_str(cur.Ty) + _append_cstr(args_buf, 1024, arg_ty_s) + _append_cstr(args_buf, 1024, " ") + if cur.Name is not None: + _append_cstr(args_buf, 1024, cur.Name) + _append_cstr(func_ty_buf, 1024, arg_ty_s) + cur = cur.Next + first = 0 + if is_variadic == 1: + if first == 0: + _append_cstr(func_ty_buf, 1024, ", ") + _append_cstr(func_ty_buf, 1024, "...") + + # 构造带引号的 callee 名字(SHA1 前缀名含 '.' 或以数字开头需要加引号) + callee_buf: str = pool.alloc(128) + if callee_buf is None: return None + callee_buf[0] = '\0' + if _ll_name_needs_quote(callee) != 0: + _append_cstr(callee_buf, 128, "\"") + _append_cstr(callee_buf, 128, callee) + _append_cstr(callee_buf, 128, "\"") + else: + _append_cstr(callee_buf, 128, callee) + + line: str = pool.alloc(2048) + if line is None: return None + if is_variadic == 1: + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf) + else: + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + + # ============================================================ + # 间接调用指令: call %callee() + # + # callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*) + # ============================================================ + def build_call_indirect(self, callee_val: rawptr[Value], + args: rawptr[Value], arg_count: int, + ret_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = call %callee() + + 间接调用:callee_val 是函数指针 SSA 值。 + """ + if self is None or callee_val is None: return None + pool: memhub.MemBuddy* = self.Pool + + is_void: int = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: str = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: str = self._type_str(ret_ty) + + # 构建参数列表文本 + args_buf: str = pool.alloc(1024) + if args_buf is None: return None + args_buf[0] = '\0' + cur: rawptr[Value] = args + first: int = 1 + while cur is not None: + if first == 0: + _append_cstr(args_buf, 1024, ", ") + arg_ty_s: str = self._type_str(cur.Ty) + _append_cstr(args_buf, 1024, arg_ty_s) + _append_cstr(args_buf, 1024, " ") + if cur.Name is not None: + _append_cstr(args_buf, 1024, cur.Name) + cur = cur.Next + first = 0 + + line: str = pool.alloc(2048) + if line is None: return None + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + + # ============================================================ + # 类型转换指令 + # ============================================================ + def build_bitcast(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = bitcast to """ + if self is None or val is None: + return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + if val.Name is None: + return None + viperlib.snprintf(line, 256, "%s = bitcast %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + ret: rawptr[Value] = SSAValue(pool, to_ty, name) + return ret + + + def build_sext(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = sext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = sext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_trunc(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = trunc to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = trunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_zext(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = zext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = zext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_ptrtoint(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = ptrtoint to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = ptrtoint %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_inttoptr(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = inttoptr to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = inttoptr %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + # ============================================================ + # 浮点转换指令 + # ============================================================ + def build_fpext(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fpext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fpext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fptrunc(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fptrunc to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptrunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fp2si(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fptosi to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptosi %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_si2fp(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = sitofp to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = sitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fp2ui(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fptoui to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptoui %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_ui2fp(self, val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = uitofp to """ + if self is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + from_ty_s: str = self._type_str(val.Ty) + to_ty_s: str = self._type_str(to_ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = uitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + # ============================================================ + # GEP 指令 + # ============================================================ + def build_gep(self, elem_ty: rawptr[LLVMType], + ptr: rawptr[Value], idx: rawptr[Value]) -> rawptr[Value]: + """%N = getelementptr , , """ + if self is None or ptr is None or idx is None: return None + # 防御性检查: ptr.Ty 必须是指针类型,否则 llc 报错 + # "base of getelementptr must be a pointer" + # 当 translate_value 返回非指针值(如 i32 常量 0)时, + # 直接 GEP 会导致 llc 编译失败 + if _is_ptr_type(ptr.Ty) == 0: + return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + elem_ty_s: str = self._type_str(elem_ty) + ptr_ty_s: str = self._type_str(ptr.Ty) + idx_ty_s: str = self._type_str(idx.Ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, %s %s", + name, elem_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name) + self._emit(line) + + # GEP 结果类型是 elem_ty* + result_ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if result_ty is not None: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(elem_ty)) + return SSAValue(pool, result_ty, name) + + + # ============================================================ + # build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx + # ============================================================ + def build_gep_array(self, array_ty: rawptr[LLVMType], + elem_ty: rawptr[LLVMType], + ptr: rawptr[Value], idx: rawptr[Value]) -> rawptr[Value]: + """%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx + + 结果类型是 elem_ty* + """ + if self is None or ptr is None or idx is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + array_ty_s: str = self._type_str(array_ty) + ptr_ty_s: str = self._type_str(ptr.Ty) + idx_ty_s: str = self._type_str(idx.Ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, i32 0, %s %s", + name, array_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name) + self._emit(line) + + # GEP 结果类型是 elem_ty* + result_ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if result_ty is not None: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(elem_ty)) + return SSAValue(pool, result_ty, name) + + + # ============================================================ + # build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + # ============================================================ + def build_gep_struct(self, struct_ty: rawptr[LLVMType], + field_ty: rawptr[LLVMType], + ptr: rawptr[Value], field_idx: int) -> rawptr[Value]: + """%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + + 结果类型是 field_ty* + """ + if self is None or ptr is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + struct_ty_s: str = self._type_str(struct_ty) + ptr_ty_s: str = self._type_str(ptr.Ty) + line: str = pool.alloc(2048) + if line is None: + stdio.printf("[BGS] line alloc None\n") + return None + viperlib.snprintf(line, 2048, "%s = getelementptr %s, %s %s, i32 0, i32 %d", + name, struct_ty_s, ptr_ty_s, ptr.Name, field_idx) + self._emit(line) + + # GEP 结果类型是 field_ty* + result_ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if result_ty is None: + stdio.printf("[BGS] result_ty alloc None\n") + else: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(field_ty)) + rv: rawptr[Value] = SSAValue(pool, result_ty, name) + if rv is None: + stdio.printf("[BGS] SSAValue None\n") + return rv + + + # ============================================================ + # Phi 指令 + # ============================================================ + def build_phi(self, ty: rawptr[LLVMType], + incoming_head: rawptr[PhiIncoming], count: int) -> rawptr[Value]: + """%N = phi [val1, %blk1], [val2, %blk2], ... + + incoming_head 是 PhiIncoming 链表头,count 是入边数量。 + """ + if self is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(ty) + + # 构建入边列表文本: [val, %blk], [val, %blk], ... + # 入边可能很多(如 30+ 个 or 链的 bool.merge),需要大缓冲区 + parts: str = pool.alloc(4096) + if parts is None: return None + parts[0] = '\0' + cur: rawptr[PhiIncoming] = incoming_head + first: int = 1 + while cur is not None: + if first == 0: + _append_cstr(parts, 4096, ", ") + _append_cstr(parts, 4096, "[") + # 使用中间变量避免链式结构体成员访问被编译器丢弃 + inc_val: rawptr[Value] = cur.Val + if inc_val is not None: + inc_val_name: str = inc_val.Name + if inc_val_name is not None: + _append_cstr(parts, 4096, inc_val_name) + _append_cstr(parts, 4096, ", %") + inc_blk: rawptr[BasicBlock] = cur.Block + if inc_blk is not None: + inc_blk_name: str = inc_blk.Name + if inc_blk_name is not None: + _append_cstr(parts, 4096, inc_blk_name) + _append_cstr(parts, 4096, "]") + cur = cur.Next + first = 0 + + line: str = pool.alloc(8192) + if line is None: return None + viperlib.snprintf(line, 8192, "%s = phi %s %s", name, ty_s, parts) + self._emit(line) + return SSAValue(pool, ty, name) + + + # ============================================================ + # Switch 指令 + # ============================================================ + def build_switch(self, val: rawptr[Value], + default_blk: rawptr[BasicBlock], + cases_head: rawptr[SwitchCase], case_count: int): + """switch , label % [, label % ...]""" + if self is None or val is None or default_blk is None: return + pool: memhub.MemBuddy* = self.Pool + ty_s: str = self._type_str(val.Ty) + + # 构建主体: switch , label %default + line: str = pool.alloc(512) + if line is None: return + viperlib.snprintf(line, 512, "switch %s %s, label %%%s", + ty_s, val.Name, default_blk.Name) + _append_cstr(line, 512, " [") + _append_cstr(line, 512, "\n") + + # 遍历 case 列表 + cur: rawptr[SwitchCase] = cases_head + case_ty_s: str = self._type_str(val.Ty) + while cur is not None: + case_line: str = pool.alloc(128) + if case_line is not None: + # 使用中间变量避免链式结构体成员访问被编译器丢弃 + cv: rawptr[Value] = cur.CaseVal + cb: rawptr[BasicBlock] = cur.Block + if cv is not None and cb is not None: + cv_name: str = cv.Name + cb_name: str = cb.Name + if cv_name is not None and cb_name is not None: + viperlib.snprintf(case_line, 128, " %s %s, label %%%s\n", + case_ty_s, cv_name, cb_name) + _append_cstr(line, 512, case_line) + cur = cur.Next + + _append_cstr(line, 512, "]") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # Select 指令 + # ============================================================ + def build_select(self, cond: rawptr[Value], + true_val: rawptr[Value], false_val: rawptr[Value]) -> rawptr[Value]: + """%N = select i1 , , """ + if self is None or cond is None or true_val is None or false_val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ty_s: str = self._type_str(true_val.Ty) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = select i1 %s, %s %s, %s %s", + name, cond.Name, ty_s, true_val.Name, ty_s, false_val.Name) + self._emit(line) + return SSAValue(pool, true_val.Ty, name) + + + # ============================================================ + # Unreachable 指令 + # ============================================================ + def build_unreachable(self): + """unreachable""" + if self is None: return + pool: memhub.MemBuddy* = self.Pool + line: str = pool.alloc(16) + if line is None: return + string.strcpy(line, "unreachable") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # 原子指令 (Phase 3) + # ============================================================ + def build_atomicrmw(self, op: int, + ptr: rawptr[Value], val: rawptr[Value], + order: int) -> rawptr[Value]: + """%N = atomicrmw , """ + if self is None or ptr is None or val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ptr_ty_s: str = self._type_str(ptr.Ty) + val_ty_s: str = self._type_str(val.Ty) + op_s: str = _atomic_op_str(op) + ord_s: str = _atomic_order_str(order) + line: str = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = atomicrmw %s %s %s, %s %s %s", + name, op_s, ptr_ty_s, ptr.Name, val_ty_s, val.Name, ord_s) + self._emit(line) + return SSAValue(pool, val.Ty, name) + + + def build_cmpxchg(self, ptr: rawptr[Value], + cmp_val: rawptr[Value], new_val: rawptr[Value], + succ_order: int, fail_order: int) -> rawptr[Value]: + """%N = cmpxchg , , + + 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) + """ + if self is None or ptr is None or cmp_val is None or new_val is None: return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + ptr_ty_s: str = self._type_str(ptr.Ty) + cmp_ty_s: str = self._type_str(cmp_val.Ty) + new_ty_s: str = self._type_str(new_val.Ty) + succ_s: str = _atomic_order_str(succ_order) + fail_s: str = _atomic_order_str(fail_order) + line: str = pool.alloc(384) + if line is None: return None + viperlib.snprintf(line, 384, "%s = cmpxchg %s %s, %s %s, %s %s %s %s", + name, ptr_ty_s, ptr.Name, cmp_ty_s, cmp_val.Name, + new_ty_s, new_val.Name, succ_s, fail_s) + self._emit(line) + # 返回原始值的类型 + return SSAValue(pool, new_val.Ty, name) + + + # ============================================================ + # va_arg 指令: 从 va_list 读取下一个变长参数 + # ============================================================ + def build_va_arg(self, + va_list_ptr: rawptr[Value], + arg_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = va_arg , """ + if self is None or va_list_ptr is None or arg_ty is None: + return None + pool: memhub.MemBuddy* = self.Pool + name: str = self._alloc_ssa_name() + va_list_ty_s: str = self._type_str(va_list_ptr.Ty) + arg_ty_s: str = self._type_str(arg_ty) + line: str = pool.alloc(256) + if line is None: return None + if va_list_ptr.Name is None: + return None + viperlib.snprintf(line, 256, "%s = va_arg %s %s, %s", + name, va_list_ty_s, va_list_ptr.Name, arg_ty_s) + self._emit(line) + return SSAValue(pool, arg_ty, name) + + + # ============================================================ + # 内联汇编 (Phase 3) + # ============================================================ + def build_inline_asm(self, ret_ty: rawptr[LLVMType], + asm_text: str, constraints: str, + has_side_effects: int) -> rawptr[Value]: + """%N = call asm [sideeffect] "" ""() + + 简化的内联汇编调用,无参数版本。 + """ + if self is None: return None + pool: memhub.MemBuddy* = self.Pool + + # 判断返回类型是否为 void + is_void: int = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: str = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: str = self._type_str(ret_ty) + line: str = pool.alloc(512) + if line is None: return None + + if has_side_effects != 0: + if is_void == 1: + viperlib.snprintf(line, 512, "call %s asm sideeffect \"%s\", \"%s\"()", + ret_ty_s, asm_text, constraints) + else: + viperlib.snprintf(line, 512, "%s = call %s asm sideeffect \"%s\", \"%s\"()", + name, ret_ty_s, asm_text, constraints) + else: + if is_void == 1: + viperlib.snprintf(line, 512, "call %s asm \"%s\", \"%s\"()", + ret_ty_s, asm_text, constraints) + else: + viperlib.snprintf(line, 512, "%s = call %s asm \"%s\", \"%s\"()", + name, ret_ty_s, asm_text, constraints) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) = 32 字节 +BUILDER_SIZE: t.CDefine = 32 + +def new_builder(pool: memhub.MemBuddy*, func: rawptr[Function]) -> rawptr[IRBuilder]: + """创建 IRBuilder,关联到函数 func""" + ptr: rawptr[IRBuilder] = pool.alloc(BUILDER_SIZE) + if ptr is None: return None + string.memset(ptr, 0, BUILDER_SIZE) + ptr.Pool = pool + ptr.Func = func + ptr.CurBlock = None + ptr.Counter = 0 + return ptr + + +# ============================================================ +# 块定位 +# ============================================================ +def position_at_end(builder: rawptr[IRBuilder], block: rawptr[BasicBlock]): + """将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。 + + 移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致, + 避免 SSA 名在文本中非单调递增导致 llc 编译失败。 + """ + builder.position_at_end(block) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _alloc_ssa_name(builder: rawptr[IRBuilder]) -> str: + """分配一个 SSA 名字符串 "%N" 并递增计数器""" + return builder._alloc_ssa_name() + + +def _type_str(builder: rawptr[IRBuilder], ty: rawptr[LLVMType]) -> str: + """获取类型的 IR 文本(从 pool 分配 512 字节缓冲区) + + 注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节, + 必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。 + """ + return builder._type_str(ty) + + +def _emit(builder: rawptr[IRBuilder], text: str): + """将指令文本追加到当前块""" + builder._emit(text) + + +def _mark_terminated(builder: rawptr[IRBuilder]): + """标记当前块已终止""" + builder._mark_terminated() + + +def builder_cur_block_is_terminated(builder: rawptr[IRBuilder]) -> int: + """检查当前块的 IsTerminated 标志 + + 通过 block_get_terminated 辅助函数访问,避免链式属性 + builder.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque + 导致的 GEP 静默跳过问题。 + """ + return builder.builder_cur_block_is_terminated() + + +# ============================================================ +# 内存指令 +# ============================================================ +def build_alloca(builder: rawptr[IRBuilder], ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = alloca + + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 + """ + return builder.build_alloca(ty) + + +def build_alloca_aligned(builder: rawptr[IRBuilder], ty: rawptr[LLVMType], + align: int) -> rawptr[Value]: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + return builder.build_alloca_aligned(ty, align) + + +def build_alloca_at_entry(builder: rawptr[IRBuilder], ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = alloca (在函数入口块生成,确保支配性) + + 在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca + 导致的支配性违规(Instruction does not dominate all uses)。 + """ + return builder.build_alloca_at_entry(ty) + + +def build_load(builder: rawptr[IRBuilder], ty: rawptr[LLVMType], + ptr: rawptr[Value], + is_volatile: int = 0) -> rawptr[Value]: + """%N = load [volatile ], """ + return builder.build_load(ty, ptr, is_volatile) + + +def build_store(builder: rawptr[IRBuilder], val: rawptr[Value], ptr: rawptr[Value], + is_volatile: int = 0): + """store [volatile ] , """ + builder.build_store(val, ptr, is_volatile) + + +# ============================================================ +# 二元运算指令 +# ============================================================ +def build_add(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = add , """ + return builder.build_add(lhs, rhs) + + +def build_sub(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = sub , """ + return builder.build_sub(lhs, rhs) + + +def build_mul(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = mul , """ + return builder.build_mul(lhs, rhs) + + +def build_sdiv(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = sdiv , """ + return builder.build_sdiv(lhs, rhs) + + +def build_udiv(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = udiv , """ + return builder.build_udiv(lhs, rhs) + + +def build_srem(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = srem , """ + return builder.build_srem(lhs, rhs) + + +def build_urem(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = urem , """ + return builder.build_urem(lhs, rhs) + + +def build_and(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = and , """ + return builder.build_and(lhs, rhs) + + +def build_or(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = or , """ + return builder.build_or(lhs, rhs) + + +def build_xor(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = xor , """ + return builder.build_xor(lhs, rhs) + + +def build_shl(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = shl , """ + return builder.build_shl(lhs, rhs) + + +def build_lshr(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = lshr , """ + return builder.build_lshr(lhs, rhs) + + +def build_ashr(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = ashr , """ + return builder.build_ashr(lhs, rhs) + + +# ============================================================ +# 浮点二元运算指令 +# ============================================================ +def build_fadd(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fadd , """ + return builder.build_fadd(lhs, rhs) + + +def build_fsub(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fsub , """ + return builder.build_fsub(lhs, rhs) + + +def build_fmul(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fmul , """ + return builder.build_fmul(lhs, rhs) + + +def build_fdiv(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fdiv , """ + return builder.build_fdiv(lhs, rhs) + + +def build_frem(builder: rawptr[IRBuilder], lhs: rawptr[Value], + rhs: rawptr[Value]) -> rawptr[Value]: + """%N = frem , """ + return builder.build_frem(lhs, rhs) + + +def build_fneg(builder: rawptr[IRBuilder], val: rawptr[Value]) -> rawptr[Value]: + """%N = fneg """ + return builder.build_fneg(val) + + +def _build_binop(builder: rawptr[IRBuilder], op: str, + lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: + """二元运算通用实现""" + return builder._build_binop(op, lhs, rhs) + + +# ============================================================ +# 比较指令 +# ============================================================ +# ICMP 谓词常量 +ICMP_EQ: t.CDefine = 0 +ICMP_NE: t.CDefine = 1 +ICMP_SGT: t.CDefine = 2 +ICMP_SGE: t.CDefine = 3 +ICMP_SLT: t.CDefine = 4 +ICMP_SLE: t.CDefine = 5 +ICMP_UGT: t.CDefine = 6 +ICMP_UGE: t.CDefine = 7 +ICMP_ULT: t.CDefine = 8 +ICMP_ULE: t.CDefine = 9 + +# FCMP 谓词常量 +FCMP_FALSE: t.CDefine = 0 +FCMP_OEQ: t.CDefine = 1 +FCMP_OGT: t.CDefine = 2 +FCMP_OGE: t.CDefine = 3 +FCMP_OLT: t.CDefine = 4 +FCMP_OLE: t.CDefine = 5 +FCMP_ONE: t.CDefine = 6 +FCMP_ORD: t.CDefine = 7 +FCMP_UNO: t.CDefine = 8 +FCMP_UEQ: t.CDefine = 9 +FCMP_UGT: t.CDefine = 10 +FCMP_UGE: t.CDefine = 11 +FCMP_ULT: t.CDefine = 12 +FCMP_ULE: t.CDefine = 13 +FCMP_UNE: t.CDefine = 14 +FCMP_TRUE: t.CDefine = 15 + + +def _icmp_pred_str(pred: int) -> str: + if pred == ICMP_EQ: return "eq" + if pred == ICMP_NE: return "ne" + if pred == ICMP_SGT: return "sgt" + if pred == ICMP_SGE: return "sge" + if pred == ICMP_SLT: return "slt" + if pred == ICMP_SLE: return "sle" + if pred == ICMP_UGT: return "ugt" + if pred == ICMP_UGE: return "uge" + if pred == ICMP_ULT: return "ult" + if pred == ICMP_ULE: return "ule" + return "eq" + + +def _fcmp_pred_str(pred: int) -> str: + if pred == FCMP_FALSE: return "false" + if pred == FCMP_OEQ: return "oeq" + if pred == FCMP_OGT: return "ogt" + if pred == FCMP_OGE: return "oge" + if pred == FCMP_OLT: return "olt" + if pred == FCMP_OLE: return "ole" + if pred == FCMP_ONE: return "one" + if pred == FCMP_ORD: return "ord" + if pred == FCMP_UNO: return "uno" + if pred == FCMP_UEQ: return "ueq" + if pred == FCMP_UGT: return "ugt" + if pred == FCMP_UGE: return "uge" + if pred == FCMP_ULT: return "ult" + if pred == FCMP_ULE: return "ule" + if pred == FCMP_UNE: return "une" + if pred == FCMP_TRUE: return "true" + return "oeq" + + +def build_icmp(builder: rawptr[IRBuilder], pred: int, + lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: + """%N = icmp , + + 返回类型为 i1 的 SSA 值 + """ + return builder.build_icmp(pred, lhs, rhs) + + +def build_fcmp(builder: rawptr[IRBuilder], pred: int, + lhs: rawptr[Value], rhs: rawptr[Value]) -> rawptr[Value]: + """%N = fcmp , + + 返回类型为 i1 的 SSA 值 + """ + return builder.build_fcmp(pred, lhs, rhs) + + +# ============================================================ +# 终止指令 +# ============================================================ +def build_br(builder: rawptr[IRBuilder], target: rawptr[BasicBlock]): + """br label %""" + builder.build_br(target) + + +def build_cond_br(builder: rawptr[IRBuilder], cond: rawptr[Value], + then_blk: rawptr[BasicBlock], else_blk: rawptr[BasicBlock]): + """br i1 , label %, label %""" + builder.build_cond_br(cond, then_blk, else_blk) + + +def build_ret(builder: rawptr[IRBuilder], val: rawptr[Value]): + """ret """ + builder.build_ret(val) + + +def build_ret_void(builder: rawptr[IRBuilder]): + """ret void""" + builder.build_ret_void() + + +# ============================================================ +# 调用指令 +# ============================================================ +def build_call(builder: rawptr[IRBuilder], callee: str, + args: rawptr[Value], arg_count: int, + ret_ty: rawptr[LLVMType], + is_variadic: int = 0) -> rawptr[Value]: + """%N = call @() + + args 是 Value 链表头,arg_count 是参数数量。 + 若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。 + is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 + """ + return builder.build_call(callee, args, arg_count, ret_ty, is_variadic) + + +# ============================================================ +# 间接调用指令: call %callee() +# +# callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*) +# ============================================================ +def build_call_indirect(builder: rawptr[IRBuilder], callee_val: rawptr[Value], + args: rawptr[Value], arg_count: int, + ret_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = call %callee() + + 间接调用:callee_val 是函数指针 SSA 值。 + """ + return builder.build_call_indirect(callee_val, args, arg_count, ret_ty) + + +# ============================================================ +# 类型转换指令 +# ============================================================ +def build_bitcast(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = bitcast to """ + return builder.build_bitcast(val, to_ty) + + +def build_sext(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = sext to """ + return builder.build_sext(val, to_ty) + + +def build_trunc(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = trunc to """ + return builder.build_trunc(val, to_ty) + + +def build_zext(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = zext to """ + return builder.build_zext(val, to_ty) + + +def build_ptrtoint(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = ptrtoint to """ + return builder.build_ptrtoint(val, to_ty) + + +def build_inttoptr(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = inttoptr to """ + return builder.build_inttoptr(val, to_ty) + + +# ============================================================ +# 浮点转换指令 +# ============================================================ +def build_fpext(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fpext to """ + return builder.build_fpext(val, to_ty) + + +def build_fptrunc(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fptrunc to """ + return builder.build_fptrunc(val, to_ty) + + +def build_fp2si(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fptosi to """ + return builder.build_fp2si(val, to_ty) + + +def build_si2fp(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = sitofp to """ + return builder.build_si2fp(val, to_ty) + + +def build_fp2ui(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = fptoui to """ + return builder.build_fp2ui(val, to_ty) + + +def build_ui2fp(builder: rawptr[IRBuilder], val: rawptr[Value], + to_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = uitofp to """ + return builder.build_ui2fp(val, to_ty) + + +# ============================================================ +# GEP 指令 +# ============================================================ +def _is_ptr_type(ty: rawptr[LLVMType]) -> int: + """检查 ty 是否是 Ptr 类型(独立函数,避免嵌套 match 的编译器 BUG)""" + if ty is None: + return 0 + match ty: + case LLVMType.Ptr(pointee): + return 1 + case _: + return 0 + + +def build_gep(builder: rawptr[IRBuilder], elem_ty: rawptr[LLVMType], + ptr: rawptr[Value], idx: rawptr[Value]) -> rawptr[Value]: + """%N = getelementptr , , """ + return builder.build_gep(elem_ty, ptr, idx) + + +# ============================================================ +# build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx +# ============================================================ +def build_gep_array(builder: rawptr[IRBuilder], array_ty: rawptr[LLVMType], + elem_ty: rawptr[LLVMType], + ptr: rawptr[Value], idx: rawptr[Value]) -> rawptr[Value]: + """%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx + + 结果类型是 elem_ty* + """ + return builder.build_gep_array(array_ty, elem_ty, ptr, idx) + + +# ============================================================ +# build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx +# ============================================================ +def build_gep_struct(builder: rawptr[IRBuilder], struct_ty: rawptr[LLVMType], + field_ty: rawptr[LLVMType], + ptr: rawptr[Value], field_idx: int) -> rawptr[Value]: + """%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + + 结果类型是 field_ty* + """ + return builder.build_gep_struct(struct_ty, field_ty, ptr, field_idx) + + +# ============================================================ +# PhiIncoming: phi 节点的入边 (value, block) 对 +# 继承 GSListNode[PhiIncoming] 获取强类型 Next +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +novirtual class PhiIncoming(GSListNode[PhiIncoming]): + Val: rawptr[Value] + Block: rawptr[BasicBlock] + + +# PhiIncoming 硬编码大小: Next(8) + Val(8) + Block(8) = 24 字节 +PHIINC_SIZE: t.CDefine = 24 + +def new_phi_incoming(pool: memhub.MemBuddy*, + val: rawptr[Value], block: rawptr[BasicBlock]) -> rawptr[PhiIncoming]: + ptr: rawptr[PhiIncoming] = pool.alloc(PHIINC_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PHIINC_SIZE) + ptr.Val = val + ptr.Block = block + return ptr + + +# ============================================================ +# Phi 指令 +# ============================================================ +def build_phi(builder: rawptr[IRBuilder], ty: rawptr[LLVMType], + incoming_head: rawptr[PhiIncoming], count: int) -> rawptr[Value]: + """%N = phi [val1, %blk1], [val2, %blk2], ... + + incoming_head 是 PhiIncoming 链表头,count 是入边数量。 + """ + return builder.build_phi(ty, incoming_head, count) + + +# ============================================================ +# SwitchCase: switch 指令的 case 分支 +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +novirtual class SwitchCase(GSListNode[SwitchCase]): + CaseVal: rawptr[Value] + Block: rawptr[BasicBlock] + + +# SwitchCase 硬编码大小: Next(8) + CaseVal(8) + Block(8) = 24 字节 +SWCASE_SIZE: t.CDefine = 24 + +def new_switch_case(pool: memhub.MemBuddy*, + case_val: rawptr[Value], block: rawptr[BasicBlock]) -> rawptr[SwitchCase]: + ptr: rawptr[SwitchCase] = pool.alloc(SWCASE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, SWCASE_SIZE) + ptr.CaseVal = case_val + ptr.Block = block + return ptr + + +# ============================================================ +# Switch 指令 +# ============================================================ +def build_switch(builder: rawptr[IRBuilder], val: rawptr[Value], + default_blk: rawptr[BasicBlock], + cases_head: rawptr[SwitchCase], case_count: int): + """switch , label % [, label % ...]""" + builder.build_switch(val, default_blk, cases_head, case_count) + + +# ============================================================ +# Select 指令 +# ============================================================ +def build_select(builder: rawptr[IRBuilder], cond: rawptr[Value], + true_val: rawptr[Value], false_val: rawptr[Value]) -> rawptr[Value]: + """%N = select i1 , , """ + return builder.build_select(cond, true_val, false_val) + + +# ============================================================ +# Unreachable 指令 +# ============================================================ +def build_unreachable(builder: rawptr[IRBuilder]): + """unreachable""" + builder.build_unreachable() + + +# ============================================================ +# 原子指令 (Phase 3) +# ============================================================ +# AtomicRMW 操作常量 +ATOMIC_XCHG: t.CDefine = 0 +ATOMIC_ADD: t.CDefine = 1 +ATOMIC_SUB: t.CDefine = 2 +ATOMIC_AND: t.CDefine = 3 +ATOMIC_NAND: t.CDefine = 4 +ATOMIC_OR: t.CDefine = 5 +ATOMIC_XOR: t.CDefine = 6 +ATOMIC_MAX: t.CDefine = 7 +ATOMIC_MIN: t.CDefine = 8 +ATOMIC_UMAX: t.CDefine = 9 +ATOMIC_UMIN: t.CDefine = 10 + +# 内存序常量 +ATOMIC_ORDER_NOTATOMIC: t.CDefine = 0 +ATOMIC_ORDER_UNORDERED: t.CDefine = 1 +ATOMIC_ORDER_MONOTONIC: t.CDefine = 2 +ATOMIC_ORDER_ACQUIRE: t.CDefine = 3 +ATOMIC_ORDER_RELEASE: t.CDefine = 4 +ATOMIC_ORDER_ACQ_REL: t.CDefine = 5 +ATOMIC_ORDER_SEQ_CST: t.CDefine = 6 + + +def _atomic_op_str(op: int) -> str: + if op == ATOMIC_XCHG: return "xchg" + if op == ATOMIC_ADD: return "add" + if op == ATOMIC_SUB: return "sub" + if op == ATOMIC_AND: return "and" + if op == ATOMIC_NAND: return "nand" + if op == ATOMIC_OR: return "or" + if op == ATOMIC_XOR: return "xor" + if op == ATOMIC_MAX: return "max" + if op == ATOMIC_MIN: return "min" + if op == ATOMIC_UMAX: return "umax" + if op == ATOMIC_UMIN: return "umin" + return "xchg" + + +def _atomic_order_str(ord: int) -> str: + if ord == ATOMIC_ORDER_UNORDERED: return "unordered" + if ord == ATOMIC_ORDER_MONOTONIC: return "monotonic" + if ord == ATOMIC_ORDER_ACQUIRE: return "acquire" + if ord == ATOMIC_ORDER_RELEASE: return "release" + if ord == ATOMIC_ORDER_ACQ_REL: return "acq_rel" + if ord == ATOMIC_ORDER_SEQ_CST: return "seq_cst" + return "monotonic" + + +def build_atomicrmw(builder: rawptr[IRBuilder], op: int, + ptr: rawptr[Value], val: rawptr[Value], + order: int) -> rawptr[Value]: + """%N = atomicrmw , """ + return builder.build_atomicrmw(op, ptr, val, order) + + +def build_cmpxchg(builder: rawptr[IRBuilder], ptr: rawptr[Value], + cmp_val: rawptr[Value], new_val: rawptr[Value], + succ_order: int, fail_order: int) -> rawptr[Value]: + """%N = cmpxchg , , + + 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) + """ + return builder.build_cmpxchg(ptr, cmp_val, new_val, succ_order, fail_order) + + +# ============================================================ +# va_arg 指令: 从 va_list 读取下一个变长参数 +# ============================================================ +def build_va_arg(builder: rawptr[IRBuilder], + va_list_ptr: rawptr[Value], + arg_ty: rawptr[LLVMType]) -> rawptr[Value]: + """%N = va_arg , """ + return builder.build_va_arg(va_list_ptr, arg_ty) + + +# ============================================================ +# 内联汇编 (Phase 3) +# ============================================================ +def build_inline_asm(builder: rawptr[IRBuilder], ret_ty: rawptr[LLVMType], + asm_text: str, constraints: str, + has_side_effects: int) -> rawptr[Value]: + """%N = call asm [sideeffect] "" ""() + + 简化的内联汇编调用,无参数版本。 + """ + return builder.build_inline_asm(ret_ty, asm_text, constraints, has_side_effects) + + +# ============================================================ +# 内部辅助 +# ============================================================ +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: sizet = 0 + +def _append_cstr(dst: str, dst_size: sizet, src: str): + """将 C 字符串 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos + if dst is None or src is None: return + dlen: sizet = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + # 缓存一致性校验(同 __module/__function 版):缓存 pos 过期会追加到首个 NUL + # 之后使内容不可见,校验失败回退 strlen;正常热路径仍 O(1)。 + if dlen == 0: + if dst[0] != '\0': + dlen = string.strlen(dst) + elif dst[dlen] != '\0' or dst[dlen - 1] == '\0': + dlen = string.strlen(dst) + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen + if remain <= 0: return + i: sizet = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + _g_last_pos = dlen + i diff --git a/mlirlite/__function.vp b/mlirlite/__function.vp new file mode 100644 index 0000000..e0f178c --- /dev/null +++ b/mlirlite/__function.vp @@ -0,0 +1,2877 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import stdio +import stdlib +from linkedlist import GSListNode, GSList +from .__types import ( + LLVMType, ParamNode, TypePrint, + MlirTypeText, MlirTypeTextIsPointer, MlirFail, +) + + +# dump 哨兵:IR 链表遍历步数上限(成环检测,fail-fast,与 __module.vp 对齐)。 +# 函数/基本块/指令行链的 Next 被越界写破坏成环时,遍历无限循环挂起; +# 超过上限即打印链表名并 exit(1),把"卡死"变成"确定性报错定位"。 +IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000 + +# 窥孔优化总开关(T2 转发/ret 归零、T3 no-op bitcast 消除)。 +# TPV 命令行 --no-llvmpeephole 会将其置 0:FunctionPrint 序列化时跳过全部本地窥孔, +# 便于与关闭窥孔的 IR 对比调试(RenumberSSA 仍保留,保证输出 SSA 编号合法)。 +G_PeepEnable: bool = True + + +# ============================================================ +# Line: 指令文本行 +# +# 每条 LLVM IR 指令序列化为一行文本,通过链表组织。 +# 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr +# +# 注意: 必须加 @t.NoVTable。否则 TransPyC 为子类添加 vtable 指针(T*), +# 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位, +# 所有字段访问读取垃圾值(见续 XV 会话根因分析)。 +# ============================================================ +novirtual class Line(GSListNode[Line]): + Buf: str # 行文本(NUL 结尾) + Len: sizet # 文本长度(不含 NUL) + + +# ============================================================ +# BasicBlock: 基本块 +# +# 持有名称 + 指令行链表 + 终止指令标志。 +# 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr +# Lines 为 GSList[Line] 指针,提供 O(1) 追加。 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +novirtual class BasicBlock(GSListNode[BasicBlock]): + Name: str # 块名(如 "entry"/"if.then") + Lines: rawptr[GSList[Line]] # 指令行链表容器(Head/Tail/Count) + IsTerminated: int # 1=已有终止指令(br/ret) + + +# ============================================================ +# Param: 函数参数 +# +# 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr +# Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"),None=无属性 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +novirtual class Param(GSListNode[Param]): + Ty: rawptr[LLVMType] # 参数类型 + Name: str # 参数名(如 "%0"/"%a") + Attrs: str # 参数属性文本(None=无属性) + + +# ============================================================ +# Function: 函数 +# +# 持有名称 + 返回类型 + 参数链表 + 基本块链表。 +# 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr +# Params/Blocks 为 GSList 指针,提供 O(1) 追加。 +# Attrs 存储函数级属性文本(如 "nounwind"/"noinline"),None=无属性 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +novirtual class Function(GSListNode[Function]): + Name: str # 函数名 + RetTy: rawptr[LLVMType] # 返回类型 + Params: rawptr[GSList[Param]] # 参数链表容器 + Blocks: rawptr[GSList[BasicBlock]] # 基本块链表容器 + IsDeclared: int # 1=仅声明(declare), 0=定义(define) + IsVarArg: int # 1=变参函数(...) + Attrs: str # 函数属性文本(None=无属性) + AttrGroup: str # 字符串属性组内容(如 '"section"=".text.startup"',None=无) + AttrGroupId: int # 属性组编号(>0 时函数行输出 #N,模块尾输出 attributes #N) + NameLen: sizet # 函数名长度(创建时一次算好,恒等于 strlen(Name);追加在末尾,既有字段偏移不变) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节 +LINE_SIZE: t.CDefine = 24 + +def new_line(pool: memhub.MemBuddy*, text: str) -> rawptr[Line]: + """创建一个指令行,复制 text 到新分配的缓冲区""" + ptr: rawptr[Line] = pool.alloc(LINE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, LINE_SIZE) + if text is not None: + slen: sizet = string.strlen(text) + buf: str = 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*, list_size: sizet) -> 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*, name: str) -> rawptr[BasicBlock]: + """创建一个基本块""" + ptr: rawptr[BasicBlock] = 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*, ty: rawptr[LLVMType], + name: str) -> rawptr[Param]: + """创建一个函数参数""" + ptr: rawptr[Param] = 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) + AttrGroup(8) + AttrGroupId(8) + NameLen(8) = 80 字节 +FUNC_SIZE: t.CDefine = 80 + +def new_function(pool: memhub.MemBuddy*, name: str, + ret_ty: rawptr[LLVMType]) -> rawptr[Function]: + """创建一个函数""" + ptr: rawptr[Function] = 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 + ptr.AttrGroup = None + ptr.AttrGroupId = 0 + # NameLen 创建时一次算好:Name 终生不变(本文件仅此处赋值 ptr.Name), + # 故 NameLen 恒等于 strlen(Name),可替代对函数名的反复 strlen 热点。 + # name=None 时置 0,与 new_line 的 "text is not None" 判空约定一致 + # (memset 已归零,此处显式赋值以固定语义、不依赖分配器行为)。 + if name is not None: + ptr.NameLen = string.strlen(name) + else: + ptr.NameLen = 0 + return ptr + + +# ============================================================ +# 链表操作(委托 GSList.append) +# ============================================================ +def function_add_param(func: rawptr[Function], param: rawptr[Param]): + """将参数追加到函数参数链表""" + if func is None or param is None: return + # 注意:必须先用局部变量 + 类型参数(对齐 function_move_block_to_end 注释), + # 链式 func.Params.append() 会被编译器解析成 LinkedNode.append 且 this 前移 + # sizeof(LinkedNode)(兄弟 Mixin 兜底误匹配),写穿容器前 48 字节破坏数据结构。 + params: rawptr[GSList[Param]] = func.Params + if params is None: return + params.append(param) + + +def function_add_block(func: rawptr[Function], block: rawptr[BasicBlock]): + """将基本块追加到函数块链表""" + if func is None or block is None: return + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + if blocks is None: return + blocks.append(block) + + +def function_move_block_to_end(func: rawptr[Function], block: rawptr[BasicBlock]): + """将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。 + + 用于解决 SSA 名非单调问题:BB 按创建顺序排列,但指令按控制流顺序生成, + 导致 SSA 编号在文本输出时非单调递增,llc 报错。 + 在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。 + + 注意:必须使用 GSList[BasicBlock] 带类型参数,否则 TransPyC 创建不完整 + struct 类型,导致 blocks.Head/Tail/Count 字段访问读取垃圾值。 + """ + if func is None or block is None: return + blocks: rawptr[GSList[BasicBlock]] = 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: rawptr[BasicBlock] = 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: rawptr[BasicBlock], line: rawptr[Line]): + """将指令行追加到基本块""" + if block is None or line is None: return + lines: rawptr[GSList[Line]] = block.Lines + if lines is None: return + lines.append(line) + + +def block_set_terminated(block: rawptr[BasicBlock], val: int): + """设置块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)""" + if block is None: return + block.IsTerminated = val + + +def block_get_terminated(block: rawptr[BasicBlock]) -> int: + """获取块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)""" + if block is None: + return 1 + return block.IsTerminated + + +def block_append_text(pool: memhub.MemBuddy*, block: rawptr[BasicBlock], + text: str): + """创建指令行并追加到基本块""" + if block is None or text is None: return + line: rawptr[Line] = new_line(pool, text) + if line is not None: + block_append_line(block, line) + + +def block_insert_text_before_terminator(pool: memhub.MemBuddy*, + block: rawptr[BasicBlock], + text: str): + """创建指令行并插入到基本块终止指令之前 + + 如果块未终止,追加到末尾。 + 如果块已终止(有 br/ret),在终止指令之前插入,确保 alloca 等指令 + 不出现在终止指令之后。 + """ + if block is None or text is None: return + if block.Lines is None: return + line: rawptr[Line] = new_line(pool, text) + if line is None: return + # 块未终止:直接追加 + if block.IsTerminated == 0: + block_append_line(block, line) + return + # 块已终止:在 Tail(终止指令)之前插入 + lines: rawptr[GSList[Line]] = block.Lines + if lines.Head is None: + block_append_line(block, line) + return + # 只有一个节点:在 Head 之前插入 + if lines.Head is lines.Tail: + line.Next = lines.Head + lines.Head = line + lines.Count += 1 + return + # 找到 Tail 的前驱节点 + prev: rawptr[Line] = lines.Head + while prev is not None and prev.Next is not lines.Tail: + prev = prev.Next + if prev is None: + # 找不到前驱,回退到追加 + block_append_line(block, line) + return + # 在 prev 和 Tail 之间插入 line + line.Next = lines.Tail + prev.Next = line + lines.Count += 1 + + +# ============================================================ +# 属性设置 +# ============================================================ +def function_set_attrs(func: rawptr[Function], attrs: str): + """设置函数级属性文本(如 "nounwind"/"noinline")""" + if func is None: return + func.Attrs = attrs + + +_g_attr_group_counter: int = 0 + +def function_set_attr_group(func: rawptr[Function], group: str): + """设置函数字符串属性组(如 '"section"=".text.startup"')并分配组编号 #N。 + + LLVM 字符串属性(带值的,如 section)不能内联在函数签名行, + 必须用属性组:函数行输出 #N,组定义输出在函数尾。 + """ + global _g_attr_group_counter + if func is None or group is None: + return + func.AttrGroup = group + _g_attr_group_counter += 1 + func.AttrGroupId = _g_attr_group_counter + + +def param_set_attrs(param: rawptr[Param], attrs: str): + """设置参数属性文本(如 "noundef"/"nocapture"/"readonly")""" + if param is None: return + param.Attrs = attrs + + +# ============================================================ +# _ll_name_needs_quote - 检查符号名在 MLIR 中是否需要 @"…" 引号形式 +# +# ⚠ 判据与 LLVM **不同**(实测 mlir-opt 22.1.8): +# - 裸标识符**首字符必须是字母或 '_'**:数字、'.'、'$' 开头都必须加引号。 +# ⇒ TPV 的 {sha1}.{name} 全部以十六进制数字开头,**一律需要引号**; +# ⇒ 字符串常量全局 @.str 以 '.' 开头,也需要引号。 +# - 后续字符仅允许 [A-Za-z0-9_$] 与 '.'; +# - '-' 在 MLIR 裸名中**非法**(LLVM 允许),实测报 "expected '('"。 +# - 含 '['/']'(泛型特化名)同样非法。 +# 本判据取保守方向:拿不准就加引号(@"…" 对任意名字都合法)。 +# ============================================================ +def _ll_name_needs_quote(name: str) -> int: + """MLIR 符号名裸写判据:不满足 [A-Za-z_][A-Za-z0-9_$.]* 即返回 1(需引号)""" + if name is None: + return 0 + name_len: sizet = string.strlen(name) + if name_len == 0: + return 1 + c0: char = name[0] + if not ((c0 >= 'a' and c0 <= 'z') or (c0 >= 'A' and c0 <= 'Z') or c0 == '_'): + return 1 + i: sizet = 1 + while i < name_len: + ch: char = name[i] + if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or + (ch >= '0' and ch <= '9') or ch == '_' or ch == '$' or ch == '.'): + return 1 + i += 1 + return 0 + + +# ============================================================ +# _MlirSymRefAppend - 输出符号引用(统一引号口径) +# +# name **不含** 前导 '@';已引号形式(首字符 '"')原样输出。 +# 用于 llvm.mlir.addressof 等"操作数里出现符号"的位置,与 +# _MlirFuncSig / 调用目标 / 全局名 三处共用同一判据。 +# ============================================================ +def _MlirSymRefAppend(out: str, outsz: sizet, name: str): + if name is None or name[0] == '\0': + MlirFail("MLIR 渲染: 空符号名") + if name[0] == '"': + _append_cstr(out, outsz, "@") + _append_cstr(out, outsz, name) + return + if _ll_name_needs_quote(name) != 0: + _append_cstr(out, outsz, "@\"") + _append_cstr(out, outsz, name) + _append_cstr(out, outsz, "\"") + return + _append_cstr(out, outsz, "@") + _append_cstr(out, outsz, name) + + +# ============================================================ +# RenumberSSA: 重编号函数内数字 SSA 名 +# +# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致 +# SSA 名在文本输出中非单调递增的问题(llc 报错: +# "instruction expected to be numbered '%N' or greater")。 +# +# 现象: entry 块原指令 %0-%6 + br,alloca_at_entry 插入 %28/%41 到 br 之前, +# 文本输出顺序为 entry(%0..%6, %28, %41) → if.then(%7..%27), +# 导致 %28 出现在 %7 之前,llc 拒绝编译。 +# +# 算法: +# 1. 扫描所有 BB 指令行,按文本输出顺序收集数字 SSA 名 %N +# 2. 按首次出现顺序建立 old→new 映射(从 0 递增) +# 3. 替换所有指令行文本中的 %N 为新编号 +# +# 注意: +# - 仅重编号纯数字 SSA 名(%0, %1, ...) +# - 命名 SSA 名(%entry, %.tmp, %self)、块标签、全局符号 @N 不重编号 +# - 仅对 define(有函数体)调用,declare 无函数体无需处理 +# - 当前 TransPyV 参数多为命名(%self/%env/%n),非数字,无需重编号参数 +# ============================================================ + +# 判定字符是否为十进制数字 +def _is_digit_ch(ch: char) -> int: + """判断字符是否是 '0'-'9' + + ch 是值类型 (char = i8),TPC 已修复值类型 is None 处理: + 值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。 + """ + if ch is None: + return 0 + if ch >= '0' and ch <= '9': + return 1 + return 0 + + +# ============================================================ +# i32 数组的安全访问(显式字节偏移) +# +# TransPyC 的 ptr[i] 指针索引可能被当作字节索引(i8*)而非 i32* 索引, +# 导致内存损坏。必须显式计算字节偏移:addr = base + idx * 4,再转型为 i32*。 +# 参见 HandlesTranslator.py:358 的 t.CUInt64T(ptr) + offset * sizeof 用法。 +# ============================================================ +def _map_get_i32(map_arr: str, idx: int) -> int: + """读取 i32 数组 map_arr[idx](显式字节偏移 idx*4) + + 使用 (rawptr[int])(uint64) 强转将字节偏移转为 i32*,再用 c.Deref 解引用。 + TPC 已修复类型联合强转(_HandleTypeUnionCastLlvm 添加 fallback),此写法可用。 + """ + if map_arr is None: + return -1 + byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4 + elem_ptr: rawptr[int] = (rawptr[int])(byte_off) + return c.Deref(elem_ptr) + + +def _map_set_i32(map_arr: str, idx: int, val: int): + """写入 map_arr[idx] = val(i32 数组,显式字节偏移 idx*4) + + 使用 (rawptr[int])(uint64) 强转 + c.DerefAs 解引用赋值。 + TPC 已修复类型联合强转,此写法可用。 + """ + if map_arr is None: + return + byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4 + elem_ptr: rawptr[int] = (rawptr[int])(byte_off) + c.DerefAs(elem_ptr, val) + + +def _scan_max_ssa_in_text(text: str, cur_max: int) -> int: + """扫描文本,找出 %N(N 为数字)中最大的 N,与 cur_max 比较返回更大值 + + 仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。 + """ + result: int = cur_max + p: str = text + while p is not None and p[0] != '\0': + if p[0] == '%': + nxt: str = p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: int = string.atoi(nxt) + if num > result: + result = num + p = p + 1 + return result + + +def _find_max_ssa_number(func: rawptr[Function]) -> int: + """遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1""" + max_n: int = -1 + if func is None or func.Blocks is None: + return max_n + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + blk: rawptr[BasicBlock] = blocks.Head + blk_steps: sizet = 0 + while blk is not None: + blk_steps += 1 + if blk_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 扫描终止)\n", func.Name) + stdlib.exit(1) + if blk.Lines is not None: + lines: rawptr[GSList[Line]] = blk.Lines + line: rawptr[Line] = lines.Head + line_steps: sizet = 0 + while line is not None: + line_steps += 1 + if line_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 扫描终止)\n", + func.Name, blk.Name) + stdlib.exit(1) + if line.Buf is not None: + max_n = _scan_max_ssa_in_text(line.Buf, max_n) + line = line.Next + blk = blk.Next + return max_n + + +def _assign_new_numbers(text: str, + map_arr: str, + max_n: int, next_new: int) -> int: + """扫描文本,对每个 %N(数字),若 map_arr[N]==-1 则分配 next_new + + 返回更新后的 next_new。按文本首次出现顺序建立映射。 + """ + result: int = next_new + p: str = text + while p is not None and p[0] != '\0': + if p[0] == '%': + nxt: str = p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: int = string.atoi(nxt) + if num >= 0 and num <= max_n: + if _map_get_i32(map_arr, num) == -1: + _map_set_i32(map_arr, num, result) + result += 1 + p = p + 1 + return result + + +def _replace_ssa_numbers(text: str, + pool: memhub.MemBuddy*, + map_arr: str, + max_n: int) -> str: + """构建新文本,将 %N 替换为映射后的新编号 + + 逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。 + 返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。 + """ + src_len: sizet = string.strlen(text) + # 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64 + new_size: sizet = src_len * 2 + 64 + new_buf: str = pool.alloc(new_size) + if new_buf is None: + return None + # 一次性分配数字缓冲区(循环中复用) + num_buf: str = pool.alloc(16) + if num_buf is None: + new_buf[0] = '\0' + return new_buf + + dst_idx: sizet = 0 + src_p: str = text + while src_p is not None and src_p[0] != '\0': + if dst_idx + 16 >= new_size: + # 缓冲区不足,截断 + break + if src_p[0] == '%': + nxt: str = src_p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: int = string.atoi(nxt) + # 先做范围检查再读 map_arr:num 超 max_n 时 map_arr 只有 + # (max_n+1)*4 字节,先读后查会越界读远端内存 + if num >= 0 and num <= max_n: + new_num: int = _map_get_i32(map_arr, num) + if new_num != -1: + # 写入 '%' + new_buf[dst_idx] = '%' + dst_idx += 1 + # 写入新编号 + num_buf[0] = '\0' + viperlib.snprintf(num_buf, 16, "%d", new_num) + k: sizet = 0 + while num_buf[k] != '\0' and dst_idx + 1 < new_size: + new_buf[dst_idx] = num_buf[k] + dst_idx += 1 + k += 1 + # 跳过旧数字字符 + src_p = src_p + 1 + while src_p is not None and _is_digit_ch(src_p[0]) != 0: + src_p = src_p + 1 + continue + # 普通字符:直接复制 + new_buf[dst_idx] = src_p[0] + dst_idx += 1 + src_p = src_p + 1 + + new_buf[dst_idx] = '\0' + return new_buf + + +def RenumberSSA(func: rawptr[Function], pool: memhub.MemBuddy*): + """重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增 + + 在 FunctionPrint 序列化函数体之前调用。 + 仅对 define(IsDeclared==0)且 Blocks 非空 的函数生效。 + """ + if func is None or pool is None: + return + if func.IsDeclared == 1: + return # declare 无函数体 + if func.Blocks is None: + return + + # 1. 第一遍扫描:找出最大 SSA 编号 + max_n: int = _find_max_ssa_number(func) + if max_n < 0: + return # 无数字 SSA 名 + + # 2. 分配并初始化映射数组 map_arr[0..max_n] = -1 + # 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。 + # 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。 + # 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。 + map_bytes: sizet = (max_n + 1) * 4 # int = 4 字节 + map_arr: str = pool.alloc(map_bytes) + if map_arr is None: + return + string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1 + + # 3. 第二遍扫描:按文本顺序分配新编号 + next_new: int = 0 + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + blk: rawptr[BasicBlock] = blocks.Head + blk_steps: sizet = 0 + while blk is not None: + blk_steps += 1 + if blk_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 重编号终止)\n", func.Name) + stdlib.exit(1) + if blk.Lines is not None: + lines: rawptr[GSList[Line]] = blk.Lines + line: rawptr[Line] = lines.Head + line_steps: sizet = 0 + while line is not None: + line_steps += 1 + if line_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 重编号终止)\n", + func.Name, blk.Name) + stdlib.exit(1) + if line.Buf is not None: + next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new) + line = line.Next + blk = blk.Next + + # 4. 检查是否有需要重编号的(old != new) + need_renumber: int = 0 + i: int = 0 + while i <= max_n: + v: int = _map_get_i32(map_arr, i) + if v != -1 and v != i: + need_renumber = 1 + break + i += 1 + if need_renumber == 0: + return # 编号已单调,无需替换 + + # 5. 第三遍扫描:替换所有指令行文本 + blk = blocks.Head + blk_steps = 0 + while blk is not None: + blk_steps += 1 + if blk_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 替换终止)\n", func.Name) + stdlib.exit(1) + if blk.Lines is not None: + lines: rawptr[GSList[Line]] = blk.Lines + line: rawptr[Line] = lines.Head + line_steps = 0 + while line is not None: + line_steps += 1 + if line_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 替换终止)\n", + func.Name, blk.Name) + stdlib.exit(1) + if line.Buf is not None: + new_buf: str = _replace_ssa_numbers( + line.Buf, pool, map_arr, max_n) + if new_buf is not None: + line.Buf = new_buf + line.Len = string.strlen(new_buf) + line = line.Next + blk = blk.Next + + +# ============================================================ +# 本地窥孔优化(文本层,输出前执行,保持语义) +# T1: ret zeroinitializer → ret 0;ret zeroinitializer → null +# T2: 入口 alloca 槽:唯一一次 store 且值无副作用(形参/%SSA/整数/浮点字面量) +# 时,把 store→load 转发为直接使用该值,删除 alloca/store/load 冗余行 +# ("虚拟寄存器优化",如 printf(i8* %msg) 前不再 alloca+store+load)。 +# 安全性:仅当 alloca 与唯一 store 都在 entry、loads 任意、无其它取址/别名用途。 +# ============================================================ +def _peep_is_startwith(s: str, pfx: str) -> int: + if s is None or pfx is None: + return 0 + pl: sizet = string.strlen(pfx) + if pl == 0: + return 1 + if string.strlen(s) < pl: + return 0 + return 1 if string.strncmp(s, pfx, pl) == 0 else 0 + + +def _peep_replace_token(pool: memhub.MemBuddy*, + line_buf: str, tok: str, repl: str, + tlen: sizet, rlen: sizet) -> str: + """将 line_buf 中独立记号 % 替换为 repl,返回新缓冲(无变化返回原指针) + + tlen/rlen = strlen(tok)/strlen(repl):由调用方在行循环外预先求好(同一 + ltok/safe_val 会作用于本函数处理的所有行),避免每行重复求长。 + """ + if line_buf is None or tok is None or repl is None: + return line_buf + if tlen == 0: + return line_buf + # 预扫是否命中:不依赖 strlen,以 NUL 为界单趟扫描(绝大多数调用无命中即返回, + # 从而省去逐行 strlen)。逐输入等价:tok 无 NUL(tlen=strlen(tok)),故 + # strncmp 判等必蕴含记号完整落在串内(i+tlen 处仍非 NUL);凡 i+tlen>ln 的 + # 位置 strncmp 必先遇到 line_buf 的 NUL 而与 tok 的非 NUL 字节不等,故原 + # 上界 i+tlen<=ln 从未排除任一可能命中,去掉后命中判定不变。 + hit: int = 0 + i: sizet = 0 + while line_buf[i] != '\0': + if line_buf[i] == '%' and line_buf[i + 1] == tok[0] \ + and string.strncmp(line_buf + i + 1, tok, tlen) == 0: + nxt: int = 0 + if line_buf[i + 1 + tlen] != '\0': + cc: int = line_buf[i + 1 + tlen] + if (cc >= 48 and cc <= 57) or (cc >= 65 and cc <= 90) or (cc >= 97 and cc <= 122) or cc == 95: + nxt = 1 + if nxt == 0: + hit = 1 + break + i += 1 + if hit == 0: + return line_buf + ln: sizet = string.strlen(line_buf) + # 缓冲大小上界:单行最多 ⌊ln/2⌋ 次替换,每次去掉 ≥2 字节(%+名)换入 rlen 字节; + # 最坏输出 ≤ ln + (ln/2)·rlen + NUL。ln + 1 + rlen·(ln+1) 恒覆盖该上界, + # 避免 K≥2 且替换串更长时把新缓冲写穿(随机内存破坏)。 + out: str = pool.alloc(ln + 1 + rlen * (ln + 1)) + if out is None: + return line_buf + op: sizet = 0 + oq: sizet = 0 + i = 0 + while i < ln: + if line_buf[i] == '%' and i + 1 + tlen <= ln \ + and line_buf[i + 1] == tok[0] \ + and string.strncmp(line_buf + i + 1, tok, tlen) == 0: + nxt2: int = 0 + if i + 1 + tlen < ln: + cc2: int = line_buf[i + 1 + tlen] + if (cc2 >= 48 and cc2 <= 57) or (cc2 >= 65 and cc2 <= 90) or (cc2 >= 97 and cc2 <= 122) or cc2 == 95: + nxt2 = 1 + if nxt2 == 0: + j: sizet = 0 + while j < rlen: + out[oq] = repl[j] + oq += 1 + j += 1 + i += 1 + tlen + continue + out[oq] = line_buf[i] + oq += 1 + i += 1 + out[oq] = '\0' + return out + + +def _peep_last_ref_eq(sb: str, a_name: str, nl: sizet) -> int: + """行内最后一个 '%name' 记号是否等于 a_name(store/load 的指针操作数在行尾) + + nl = strlen(a_name):由调用方在 alloca 槽全量行扫描外预先求好(a_name 在 + 同一次槽扫描中不变),避免每行调用重复 strlen。 + """ + if sb is None or a_name is None: + return 0 + # 单趟定位最后一个 '%'(原实现反复 strchr 逐个跳转,每个 '%' 一次函数调用) + r: str = None + probe: str = sb + while probe[0] != '\0': + if probe[0] == '%': + r = probe + probe += 1 + if r is None: + return 0 + # 先比首字符(廉价拒绝),首字符相同才进入 strncmp + if r[1] == a_name[0] and string.strncmp(r + 1, a_name, nl) == 0: + nxtc: int = r[1 + nl] + if nxtc == 0 or nxtc == 32 or nxtc == 44 or nxtc == 41: + return 1 + return 0 + + +def _peep_alloc_name(eb: str, pool: memhub.MemBuddy*) -> str: + """从 '%name = alloca ...' 提取 name(不含 %),失败返回 None""" + if eb is None or eb[0] != '%': + return None + eqpos: str = string.strstr(eb, " = alloca ") + if eqpos is None: + return None + nlen: sizet = sizet(t.CUInt64T(eqpos) - t.CUInt64T(eb)) - 1 + if nlen == 0: + return None + nm: str = pool.alloc(nlen + 1) + if nm is None: + return None + string.strncpy(nm, eb + 1, nlen) + nm[nlen] = '\0' + return nm + + +def _peep_is_alloc_of(eb: str, a_name: str, nl: sizet) -> int: + """判断 eb 是否为 a_name 的 alloca 定义行,等价于对 _peep_alloc_name(eb) 与 + a_name 做 strcmp 是否为 0(不再分配名字缓冲)。 + + 先比名字(strncmp,名字不同立即拒绝),仅当名字逐字节一致时才做 + " = alloca " 子串定位——把原实现「每一个 '%' 行都调一次 strstr」的 + O(槽数×行数) 次 strstr 降为每槽仅命中行才调用。 + nl = strlen(a_name);nlen==0(名字为空)在原实现返回 None,故此处同样拒绝。 + 等价性:_peep_alloc_name 取第一个 " = alloca " 之前、'%' 之后的字节为名字, + 故名字等长且一致 ⟺ strncmp 相同且该子串恰起于 eb+1+nl。 + """ + if eb is None or a_name is None or nl == 0 or eb[0] != '%': + return 0 + # 首字符预筛:nl>=1,strncmp 判等必然蕴含首字符相等;首字符不同即可廉价拒绝, + # 避免绝大多数行进入 strncmp 调用。逐输入等价:本分支拒绝当且仅当原 strncmp + # 也必返回非 0(首字节不同)。eb[0]=='%' 非 NUL ⇒ eb[1] 读在串内(最多为 NUL)。 + if eb[1] != a_name[0]: + return 0 + if string.strncmp(eb + 1, a_name, nl) != 0: + return 0 + eqpos: str = string.strstr(eb, " = alloca ") + if eqpos is not None and t.CUInt64T(eqpos) == t.CUInt64T(eb) + 1 + nl: + return 1 + return 0 + + +def _peephole_opt(func: rawptr[Function], pool: memhub.MemBuddy*): + """文本层本地窥孔:T1 ret zeroinitializer;T2 入口槽 store→load 转发""" + if func is None or func.Blocks is None or pool is None: + return + # 注:TPC 对 "变量 = 指针.字段.成员" 两级自动解引用链会静默丢弃赋值 + # (编译出的 IR 直接读未初始化栈变量 → 随机栈错误)。必须拆成单级: + # 先取字段到局部 rawptr,再判空后取 .Head(与 FunctionPrint 同一模式)。 + func_blocks: rawptr[GSList[BasicBlock]] = func.Blocks + blk: rawptr[BasicBlock] = None + if func_blocks is not None: + blk = func_blocks.Head + + # ---------- T1: ret zeroinitializer ---------- + blk_t1 = blk + while blk_t1 is not None: + line1: rawptr[Line] = None + if blk_t1.Lines is not None: + t1_lines: rawptr[GSList[Line]] = blk_t1.Lines + line1 = t1_lines.Head + while line1 is not None: + if line1.Buf is not None: + zi: str = string.strstr(line1.Buf, " zeroinitializer") + if zi is not None and _peep_is_startwith(line1.Buf, "ret ") != 0: + ty_len: sizet = sizet(t.CUInt64T(zi) - t.CUInt64T(line1.Buf)) - 4 + if ty_len > 0: + ty_buf: str = pool.alloc(ty_len + 1) + if ty_buf is not None: + string.strncpy(ty_buf, line1.Buf + 4, ty_len) + ty_buf[ty_len] = '\0' + lit: str = None + if ty_buf[0] == 'i': + lit = "0" + elif string.strchr(ty_buf, 42) is not None: # '*' + lit = "null" + if lit is not None: + nb: str = pool.alloc(ty_len + 16) + if nb is not None: + nb[0] = '\0' + string.strcat(nb, "ret ") + string.strcat(nb, ty_buf) + string.strcat(nb, " ") + string.strcat(nb, lit) + line1.Buf = nb + line1 = line1.Next + blk_t1 = blk_t1.Next + + # ---------- T2: entry alloca 槽转发 ---------- + entry_blk: rawptr[BasicBlock] = blk + if entry_blk is None: + return + entry_lines: rawptr[GSList[Line]] = entry_blk.Lines + if entry_lines is None: + return + e_line: rawptr[Line] = entry_lines.Head + while e_line is not None: + eb: str = e_line.Buf + if eb is not None: + a_name: str = _peep_alloc_name(eb, pool) + if a_name is not None: + # a_name 在本槽的全量行扫描中不变,strlen 只求一次(原每行各求一次) + a_name_len: sizet = string.strlen(a_name) + st_val: str = None + st_ok: int = 0 + st_count: int = 0 + st_line_order: int = -1 + load_ltoks: str = pool.alloc(8 * 64) + load_cnt: int = 0 + load_entry_order: t.CInt64T = 0 + alloca_order: int = -1 + order: int = 0 + unsafe: int = 0 + # 第一遍:统计本 alloca 的 store/load/其它引用及行序 + blk_s = blk + while blk_s is not None: + l_s: rawptr[Line] = None + if blk_s.Lines is not None: + scan_lines: rawptr[GSList[Line]] = blk_s.Lines + l_s = scan_lines.Head + while l_s is not None: + sb: str = l_s.Buf + if sb is not None: + is_alloc_def: int = 0 + if sb[0] == '%': + if _peep_is_alloc_of(sb, a_name, a_name_len) != 0: + is_alloc_def = 1 + if is_alloc_def == 0 and _peep_last_ref_eq(sb, a_name, a_name_len) != 0: + if _peep_is_startwith(sb, "store ") != 0: + st_count += 1 + if st_count == 1: + vcomma: str = string.strstr(sb + 6, ", ") + if vcomma is not None: + vlen: sizet = sizet(t.CUInt64T(vcomma) - t.CUInt64T(sb + 6)) + if vlen > 0: + vbuf: str = pool.alloc(vlen + 1) + if vbuf is not None: + string.strncpy(vbuf, sb + 6, vlen) + vbuf[vlen] = '\0' + st_val = vbuf + st_ok = 1 + else: + unsafe = 1 + if blk_s == entry_blk: + st_line_order = order + elif string.strstr(sb, " = load ") is not None: + ls: str = string.strstr(sb, "%") + if ls is not None and load_cnt < 64: + lname_len: sizet = sizet( + t.CUInt64T(string.strstr(sb, " = load ")) - t.CUInt64T(ls)) + lname: str = pool.alloc(lname_len + 1) + if lname is not None: + string.strncpy(lname, ls + 1, lname_len - 1) + lname[lname_len - 1] = '\0' + slotp: str | t.CPtr = t.CPtr(t.CUInt64T(load_ltoks) + load_cnt * 8) + slotp[0] = lname + load_cnt += 1 + if blk_s == entry_blk and st_line_order < 0: + load_entry_order += 1 + else: + # lname 分配失败:该 load 不会进 load_ltoks,但删除阶段 + # 仍会按槽名删其 def 行,use 无法改写为 store 值 → 悬空。 + # 保守放弃本 alloca 槽的 T2 转发。 + unsafe = 1 + else: + # 本 alloca 的 load 超过记录容量(load_ltoks=8*64,上限 64) + # 或行内无 '%' 无法解析 def 名:超出容量的 load 不会被记录, + # 但删除阶段按槽名删除全部 " = load " def 行 → 未记录 load 的 + # use 未改写为 store 值,将悬空引用已删 def(llc: + # "use of undefined value",见 strcmp 短路链 >64 分支场景)。 + # 只有 load 全集都被记录时才能安全删全量 def,故保守放弃 + # 本 alloca 槽的整个 T2 转发(保留 alloca/store/load,IR 仍合法)。 + unsafe = 1 + else: + unsafe = 1 + if sb is not None: + order += 1 + l_s = l_s.Next + blk_s = blk_s.Next + # 判据 + safe_val: str = None + if unsafe == 0 and st_count == 1 and st_ok != 0 and st_line_order >= 0 \ + and load_cnt > 0 and load_entry_order == 0 and st_val is not None: + pct: str = string.strchr(st_val, '%') + if pct is None: + sp1: str = string.strchr(st_val, ' ') + if sp1 is not None and sp1[1] != 0: + safe_val = sp1 + 1 + else: + safe_val = st_val + else: + if string.strchr(pct, ' ') is None and string.strchr(pct, ',') is None: + safe_val = pct + if safe_val is not None: + # 第二遍:替换 load 名引用 + # safe_val 在本槽替换阶段不变,strlen 只求一次(原每行各求一次) + safe_len: sizet = string.strlen(safe_val) + li2: int = 0 + while li2 < load_cnt: + slotsp: str | t.CPtr = t.CPtr(t.CUInt64T(load_ltoks) + li2 * 8) + ltok: str = slotsp[0] + if ltok is not None: + # ltok 在该 load 名的全函数行扫描中不变,strlen 只求一次 + ltok_len: sizet = string.strlen(ltok) + blk_r = blk + while blk_r is not None: + lr: rawptr[Line] = None + if blk_r.Lines is not None: + repl_lines: rawptr[GSList[Line]] = blk_r.Lines + lr = repl_lines.Head + while lr is not None: + if lr.Buf is not None: + nb2: str = _peep_replace_token(pool, lr.Buf, ltok, safe_val, + ltok_len, safe_len) + if nb2 is not None and nb2 is not lr.Buf: + lr.Buf = nb2 + lr = lr.Next + blk_r = blk_r.Next + li2 += 1 + # 删除:alloca def / 唯一 store / 全部 load 行 + blk_d = blk + while blk_d is not None: + ld: rawptr[Line] = None + if blk_d.Lines is not None: + kill_lines: rawptr[GSList[Line]] = blk_d.Lines + ld = kill_lines.Head + while ld is not None: + db: str = ld.Buf + if db is not None: + kill: int = 0 + if db[0] == '%' and db[1] == a_name[0]: + if _peep_is_alloc_of(db, a_name, a_name_len) != 0: + kill = 1 + if kill == 0 and _peep_last_ref_eq(db, a_name, a_name_len) != 0: + if _peep_is_startwith(db, "store ") != 0 \ + or string.strstr(db, " = load ") is not None: + kill = 1 + if kill != 0: + ld.Buf = None + ld = ld.Next + blk_d = blk_d.Next + e_line = e_line.Next + + # ---------- T3: no-op bitcast 消除 ---------- + _peep_noop_bitcast(func, pool) + + +def _peep_noop_bitcast(func: rawptr[Function], pool: memhub.MemBuddy*): + """T3: 消除 no-op bitcast(bitcast %x to ,两侧类型相同)。 + + 生成端(虚调用/联合位宽转换)会产生同类型恒等 bitcast(如 + `%6 = bitcast i8* %ok_msg to i8*`),纯冗余指令。把 %x 的所有引用 + 替换为源操作数(%SSA/@global/常量 token)后删除该行。 + 保守限制:类型与操作数均为不含空格的简单 token。 + """ + if func is None or pool is None or func.Blocks is None: + return + # 单趟前向扫描:命中合法候选 → 全函数替换引用 + 删行,游标从下一行续扫; + # 遇到首个不满足条件的 bitcast 即停止。与原实现"每删一行后从块头整函数 + # 重扫、遇无效候选即 return"的删除结果逐一等价(替换只改操作数 token, + # 不会把游标之前的非候选行变成候选),只是消除了 O(K·C) 的重扫二次方。 + blk: rawptr[BasicBlock] = func.Blocks.Head + while blk is not None: + ln: rawptr[Line] = None + if blk.Lines is not None: + ln = blk.Lines.Head + while ln is not None: + nxt: rawptr[Line] = ln.Next + if ln.Buf is not None: + eqpos: str = string.strstr(ln.Buf, " = bitcast ") + if eqpos is not None: + nlen: sizet = sizet(t.CUInt64T(eqpos) - t.CUInt64T(ln.Buf)) - 1 + nm_buf: str = None + src_buf: str = None + if nlen > 0: + after: str = eqpos + 11 # 跳过 " = bitcast " + sp1: str = string.strchr(after, ' ') + tpos: str = string.strstr(after, " to ") + if sp1 is not None and tpos is not None \ + and t.CUInt64T(sp1) < t.CUInt64T(tpos): + tyA_len: sizet = sizet(t.CUInt64T(sp1) - t.CUInt64T(after)) + src_st: str = sp1 + 1 + src_len: sizet = sizet(t.CUInt64T(tpos) - t.CUInt64T(src_st)) + tyB: str = tpos + 4 + tyB_len: sizet = string.strlen(tyB) + if src_len > 0 and string.strchr(tyB, ' ') is None \ + and t.CUInt64T(string.strchr(src_st, ' ')) == t.CUInt64T(tpos) \ + and tyA_len == tyB_len \ + and string.strncmp(after, tyB, tyA_len) == 0: + nm_buf = pool.alloc(nlen + 1) + if nm_buf is not None: + string.strncpy(nm_buf, ln.Buf + 1, nlen) + nm_buf[nlen] = '\0' + src_buf = pool.alloc(src_len + 1) + if src_buf is not None: + string.strncpy(src_buf, src_st, src_len) + src_buf[src_len] = '\0' + if nm_buf is None or src_buf is None: + # 首个不满足条件的 bitcast:停止(与原语义一致) + return + # 全函数把 %nm 的引用替换为源操作数 + # nm_buf/src_buf 在全函数行扫描中不变,strlen 只求一次(原每行各求一次) + nm_buf_len: sizet = string.strlen(nm_buf) + src_buf_len: sizet = string.strlen(src_buf) + blk_r: rawptr[BasicBlock] = func.Blocks.Head + while blk_r is not None: + if blk_r.Lines is not None: + ln2: rawptr[Line] = blk_r.Lines.Head + while ln2 is not None: + if ln2.Buf is not None: + rb: str = _peep_replace_token(pool, ln2.Buf, nm_buf, src_buf, + nm_buf_len, src_buf_len) + if rb is not None and rb is not ln2.Buf: + ln2.Buf = rb + ln2.Len = string.strlen(rb) + ln2 = ln2.Next + blk_r = blk_r.Next + ln.Buf = None + ln = nxt + blk = blk.Next + + +# ============================================================ +# MLIR(llvm 方言) 渲染阶段 +# +# 位置:FunctionPrint 内部。builders 一行不改,仍按 LLVM 语法把指令文本写进 +# Line;本阶段把中间文本重新解析,把 MLIR 特有的三类差异集中在此解决: +# 1) 常量物化 —— MLIR 操作数不能是字面量:非 SSA 操作数(整数/浮点/ +# null/zeroinitializer/@符号)在 entry 块开头生成 +# llvm.mlir.constant / llvm.mlir.zero / llvm.mlir.addressof +# op 并分配 %cN 名(同函数内同 (类型,文本) 只物化一次) +# 2) phi→块参数 —— 块首连续 phi 变成块参数 ^blk(%0: i32),phi 行不再输出; +# 跳转到该块的 br/cond_br 按源块匹配入边追加实参 +# 3) 不透明指针 —— 所有指针统一 !llvm.ptr(TypePrint/MlirTypeText 已收敛) +# +# 两遍扫描:pass1 只登记(常量表 / bitcast no-op 别名表)+ 形态校验; +# pass2 才真正写文本(此时常量表已完整,entry 开头的常量 op 可先输出)。 +# ============================================================ + +# 表格容量 +MLIR_CONST_CAP: t.CDefine = 512 +MLIR_ALIAS_CAP: t.CDefine = 512 + +# 渲染阶段:1=扫描(登记) 2=发射(写文本) +_MLIR_Pass: int = 0 +_MLIR_Pool: memhub.MemBuddy* = None +_MLIR_Func: rawptr[Function] = None +_MLIR_SrcBlk: rawptr[BasicBlock] = None + +# 常量表:(MLIR 类型文本, 常量文本) -> 物化出的 SSA 名 +_MLIR_ConstTy: t.CPtr = None +_MLIR_ConstVal: t.CPtr = None +_MLIR_ConstName: t.CPtr = None +_MLIR_ConstCount: int = 0 + +# bitcast no-op 别名表:结果名 -> 源操作数(ptr→ptr bitcast 在 MLIR 无意义) +_MLIR_AliasFrom: t.CPtr = None +_MLIR_AliasTo: t.CPtr = None +_MLIR_AliasCount: int = 0 + +# 解析期 scratch 缓冲(每次 FunctionPrint 分配一次,全程复用; +# 所有需要跨行存活的文本在入表/入别名表时都会 dup,见 _mlir_dup) +_SC_Op: str = None +_SC_Tb: str = None +_SC_Ty: str = None +_SC_Ty2: str = None +_SC_V1: str = None +_SC_V2: str = None +_SC_V3: str = None +_SC_Callee: str = None +_SC_Args: str = None +_SC_ArgTs: str = None +_SC_IdxV: str = None +_SC_IdxT: str = None +_SC_Mt: str = None +_SC_Tmp: str = None +_SC_Tmp2: str = None +_SC_P1: str = None +_SC_P2: str = None +_SC_B1: str = None +_SC_B2: str = None +_SC_Buf: str = None + + +def _mlir_slotp(buf: t.CPtr, idx: int) -> str | t.CPtr: + """表格槽位地址(buf + idx*8)""" + return t.CPtr(t.CUInt64T(buf) + idx * 8) + + +def _mlir_dup(s: str) -> str: + """把文本复制到池(用于需要跨行存活的表项)""" + if s is None: + return None + n: sizet = string.strlen(s) + b: str = _MLIR_Pool.alloc(n + 1) + if b is None: + MlirFail("MLIR 渲染: 文本 dup 分配失败") + string.strncpy(b, s, n) + b[n] = '\0' + return b + + +def _MlirTablesInit(pool: memhub.MemBuddy*): + """初始化两个表和解析用 scratch 缓冲""" + global _MLIR_Pool, _MLIR_Pass, _MLIR_ConstTy, _MLIR_ConstVal, _MLIR_ConstName, _MLIR_ConstCount, _MLIR_AliasFrom, _MLIR_AliasTo, _MLIR_AliasCount, _SC_Op, _SC_Tb, _SC_Ty, _SC_Ty2, _SC_V1, _SC_V2, _SC_V3, _SC_Callee, _SC_Args, _SC_ArgTs, _SC_IdxV, _SC_IdxT, _SC_Mt, _SC_Tmp, _SC_Tmp2, _SC_P1, _SC_P2, _SC_B1, _SC_B2, _SC_Buf + if pool is None: + MlirFail("MLIR 渲染: 内存池为空") + _MLIR_Pool = pool + _MLIR_Pass = 0 + _MLIR_ConstCount = 0 + _MLIR_AliasCount = 0 + _MLIR_ConstTy = pool.alloc(MLIR_CONST_CAP * 8) + _MLIR_ConstVal = pool.alloc(MLIR_CONST_CAP * 8) + _MLIR_ConstName = pool.alloc(MLIR_CONST_CAP * 8) + _MLIR_AliasFrom = pool.alloc(MLIR_ALIAS_CAP * 8) + _MLIR_AliasTo = pool.alloc(MLIR_ALIAS_CAP * 8) + if _MLIR_ConstTy is None or _MLIR_ConstVal is None or _MLIR_ConstName is None \ + or _MLIR_AliasFrom is None or _MLIR_AliasTo is None: + MlirFail("MLIR 渲染: 常量/别名表分配失败") + string.memset(_MLIR_ConstTy, 0, MLIR_CONST_CAP * 8) + string.memset(_MLIR_ConstVal, 0, MLIR_CONST_CAP * 8) + string.memset(_MLIR_ConstName, 0, MLIR_CONST_CAP * 8) + string.memset(_MLIR_AliasFrom, 0, MLIR_ALIAS_CAP * 8) + string.memset(_MLIR_AliasTo, 0, MLIR_ALIAS_CAP * 8) + _SC_Op = pool.alloc(64) + _SC_Tb = pool.alloc(512) + _SC_Ty = pool.alloc(512) + _SC_Ty2 = pool.alloc(512) + _SC_V1 = pool.alloc(512) + _SC_V2 = pool.alloc(512) + _SC_V3 = pool.alloc(512) + _SC_Callee = pool.alloc(512) + _SC_Args = pool.alloc(2048) + _SC_ArgTs = pool.alloc(2048) + _SC_IdxV = pool.alloc(1024) + _SC_IdxT = pool.alloc(1024) + _SC_Mt = pool.alloc(512) + _SC_Tmp = pool.alloc(4096) + _SC_Tmp2 = pool.alloc(1024) + _SC_P1 = pool.alloc(512) + _SC_P2 = pool.alloc(512) + _SC_B1 = pool.alloc(512) + _SC_B2 = pool.alloc(512) + _SC_Buf = pool.alloc(512) + if _SC_Op is None or _SC_Ty is None or _SC_Mt is None or _SC_Tmp is None: + MlirFail("MLIR 渲染: 解析 scratch 分配失败") + _SC_Op[0] = '\0' + _SC_Ty[0] = '\0' + _SC_Mt[0] = '\0' + _SC_Tmp[0] = '\0' + + +# ============================================================ +# 常量表 / 别名表 +# ============================================================ +def _MlirAliasLookup(name: str) -> str: + """查别名表,未命中返回 None""" + if name is None: + return None + i: int = 0 + while i < _MLIR_AliasCount: + sp: str | t.CPtr = _mlir_slotp(_MLIR_AliasFrom, i) + if sp[0] is not None and string.strcmp(sp[0], name) == 0: + st: str | t.CPtr = _mlir_slotp(_MLIR_AliasTo, i) + return st[0] + i += 1 + return None + + +def _MlirAliasAdd(from_name: str, to_name: str): + """登记 no-op bitcast 别名(from 由 to 取代)""" + global _MLIR_AliasCount + if from_name is None or to_name is None: + return + if _MLIR_AliasCount >= MLIR_ALIAS_CAP: + MlirFail("MLIR 渲染: bitcast 别名表溢出") + sp: str | t.CPtr = _mlir_slotp(_MLIR_AliasFrom, _MLIR_AliasCount) + st: str | t.CPtr = _mlir_slotp(_MLIR_AliasTo, _MLIR_AliasCount) + sp[0] = _mlir_dup(from_name) + st[0] = _mlir_dup(to_name) + _MLIR_AliasCount += 1 + + +def _MlirResolve(name: str) -> str: + """别名链解析(bitcast no-op 的结果名 -> 真实操作数)""" + if name is None: + return None + cur: str = name + g: int = 0 + while g < 64: + nx: str = _MlirAliasLookup(cur) + if nx is None: + return cur + cur = nx + g += 1 + return cur + + +def _MlirConstGet(tytext: str, valtext: str) -> str: + """取(或新建)常量的物化名 %cN""" + global _MLIR_ConstCount + i: int = 0 + while i < _MLIR_ConstCount: + sp: str | t.CPtr = _mlir_slotp(_MLIR_ConstTy, i) + if sp[0] is not None and string.strcmp(sp[0], tytext) == 0: + sv: str | t.CPtr = _mlir_slotp(_MLIR_ConstVal, i) + if sv[0] is not None and string.strcmp(sv[0], valtext) == 0: + sn: str | t.CPtr = _mlir_slotp(_MLIR_ConstName, i) + return sn[0] + i += 1 + if _MLIR_Pass == 2: + # pass1 已遍历全部指令行,此处不应出现新常量 + MlirFail("MLIR 渲染: 发射阶段出现未物化常量(扫描遗漏)") + if _MLIR_ConstCount >= MLIR_CONST_CAP: + MlirFail("MLIR 渲染: 常量表溢出") + nm: str = _MLIR_Pool.alloc(32) + if nm is None: + MlirFail("MLIR 渲染: 常量名分配失败") + viperlib.snprintf(nm, 32, "%%c%d", _MLIR_ConstCount) + sp2: str | t.CPtr = _mlir_slotp(_MLIR_ConstTy, _MLIR_ConstCount) + sv2: str | t.CPtr = _mlir_slotp(_MLIR_ConstVal, _MLIR_ConstCount) + sn2: str | t.CPtr = _mlir_slotp(_MLIR_ConstName, _MLIR_ConstCount) + sp2[0] = _mlir_dup(tytext) + sv2[0] = _mlir_dup(valtext) + sn2[0] = nm + _MLIR_ConstCount += 1 + return nm + + +def _MlirParseHexU64(s: str) -> t.CUInt64T: + """解析 0x 十六进制字面量为 u64""" + p: str = s + if p[0] == '0' and (p[1] == 'x' or p[1] == 'X'): + p = p + 2 + v: t.CUInt64T = 0 + g: int = 0 + while p[0] != '\0' and g < 32: + ch: int = p[0] + d: int = -1 + if ch >= '0' and ch <= '9': + d = ch - 48 + elif ch >= 'a' and ch <= 'f': + d = ch - 87 + elif ch >= 'A' and ch <= 'F': + d = ch - 55 + else: + break + v = v * 16 + t.CUInt64T(d) + p = p + 1 + g += 1 + return v + + +def _MlirFloatLiteral(val: str, mt: str) -> str: + """浮点常量文本 → MLIR 十进制科学计数法文本(f16/f128 不支持)""" + if val[0] == '0' and (val[1] == 'x' or val[1] == 'X'): + bits: t.CUInt64T = _MlirParseHexU64(val) + buf: str = _MLIR_Pool.alloc(64) + if buf is None: + MlirFail("MLIR 渲染: 浮点常量缓冲分配失败") + if mt[1] == '3' and mt[2] == '2': + f32v: t.CFloat = 0.0 + c.DerefAs((rawptr[t.CUInt32T])(c.Addr(f32v)), t.CUInt32T(bits)) + dv32: t.CDouble = t.CDouble(f32v) + viperlib.snprintf(buf, 64, "%e", dv32) + return buf + if mt[1] == '6' and mt[2] == '4': + f64v: t.CDouble = 0.0 + c.DerefAs((rawptr[t.CUInt64T])(c.Addr(f64v)), bits) + viperlib.snprintf(buf, 64, "%e", f64v) + return buf + MlirFail("MLIR 渲染: v1 不支持 f16/f128 十六进制浮点常量物化") + # 已是十进制文本:原样使用 + return val + + +def _MlirEmitOneConst(out: str, outsz: sizet, mt: str, val: str, nm: str): + """发射一条常量物化 op""" + _append_cstr(out, outsz, " ") + _append_cstr(out, outsz, nm) + if val[0] == '@': + # 符号引用(全局/函数地址):走统一引号口径 + # (LLVM 与 MLIR 裸名判据不同:MLIR 不允许数字/'.'开头,也不允许 '-') + _append_cstr(out, outsz, " = llvm.mlir.addressof ") + _MlirSymRefAppend(out, outsz, val + 1) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, mt) + elif string.strcmp(val, "null") == 0 or string.strcmp(val, "zeroinitializer") == 0: + _append_cstr(out, outsz, " = llvm.mlir.zero : ") + _append_cstr(out, outsz, mt) + else: + lit: str = val + if mt[0] == 'f': + lit = _MlirFloatLiteral(val, mt) + elif mt[0] != 'i': + MlirFail("MLIR 渲染: 不支持的常量操作数形态") + _append_cstr(out, outsz, " = llvm.mlir.constant(") + _append_cstr(out, outsz, lit) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, ") : ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, "\n") + + +def _MlirEmitConsts(out: str, outsz: sizet): + """按登记顺序在 entry 块开头发射全部常量物化 op""" + i: int = 0 + while i < _MLIR_ConstCount: + st: str | t.CPtr = _mlir_slotp(_MLIR_ConstTy, i) + sv: str | t.CPtr = _mlir_slotp(_MLIR_ConstVal, i) + sn: str | t.CPtr = _mlir_slotp(_MLIR_ConstName, i) + _MlirEmitOneConst(out, outsz, st[0], sv[0], sn[0]) + i += 1 + + +# ============================================================ +# 中间指令文本的解析原语 +# ============================================================ +def _mlir_ws(p: str) -> str: + """跳过空白(空格/制表/换行)""" + if p is None: + return None + while p[0] == ' ' or p[0] == '\t' or p[0] == '\n' or p[0] == '\r': + p = p + 1 + return p + + +def _mlir_delim(ch: int) -> int: + """判断字符是否结束一个记号""" + if ch == 0 or ch == 32 or ch == 9 or ch == 10 or ch == 13: + return 1 + if ch == ',' or ch == '(' or ch == ')' or ch == '[' or ch == ']' \ + or ch == ':' or ch == '=': + return 1 + return 0 + + +def _mlir_read_value(p: str, out: str, outsz: sizet) -> str: + """读一个值记号(%name / @"name" / %"name" / 字面量),返回新的游标""" + p = _mlir_ws(p) + n: sizet = 0 + if p[0] == '\0': + out[0] = '\0' + return p + if p[0] == '%' or p[0] == '@': + if n + 1 < outsz: + out[n] = p[0] + n += 1 + p = p + 1 + if p[0] == '"': + if n + 1 < outsz: + out[n] = '"' + n += 1 + p = p + 1 + while p[0] != '\0' and p[0] != '"': + if n + 1 < outsz: + out[n] = p[0] + n += 1 + p = p + 1 + if p[0] == '"': + if n + 1 < outsz: + out[n] = '"' + n += 1 + p = p + 1 + out[n] = '\0' + return p + while p[0] != '\0' and _mlir_delim(p[0]) == 0: + if n + 1 < outsz: + out[n] = p[0] + n += 1 + p = p + 1 + out[n] = '\0' + return p + + +def _mlir_read_type(p: str, out: str, outsz: sizet) -> str: + """读一个类型记号(MLIR 形态 !llvm.… 或标量 iN/fN,兼容 LLVM 聚合形态) + + 括号平衡覆盖 `[] {} () <>`:MLIR 的 !llvm.array<…>/!llvm.struct<(…)> 里含 + 空格与逗号,必须靠深度计数整体读出;无括号类型(!llvm.ptr)遇到顶层分隔符结束。 + """ + p = _mlir_ws(p) + n: sizet = 0 + if p[0] == '\0': + out[0] = '\0' + return p + c0: int = p[0] + if c0 == '!' or c0 == '[' or c0 == '{' or c0 == '(': + d: int = 0 + while p[0] != '\0': + ch: int = p[0] + if ch == '[' or ch == '{' or ch == '(' or ch == '<': + d += 1 + elif ch == ']' or ch == '}' or ch == ')' or ch == '>': + if n + 1 < outsz: + out[n] = ch + n += 1 + p = p + 1 + d -= 1 + if d <= 0: + break + continue + elif d == 0 and (ch == ' ' or ch == ',' or ch == '\t' + or ch == '\n' or ch == '\r'): + # 顶层分隔符:无括号类型(如 !llvm.ptr)到此结束 + break + if n + 1 < outsz: + out[n] = ch + n += 1 + p = p + 1 + while p[0] == '*': + if n + 1 < outsz: + out[n] = '*' + n += 1 + p = p + 1 + out[n] = '\0' + return p + if c0 == '%': + p = _mlir_read_value(p, out, outsz) + n = string.strlen(out) + while p[0] == '*': + if n + 1 < outsz: + out[n] = '*' + n += 1 + p = p + 1 + out[n] = '\0' + return p + # 普通词(i32 / i8* / void / double …) + while p[0] != '\0' and _mlir_delim(p[0]) == 0: + if n + 1 < outsz: + out[n] = p[0] + n += 1 + p = p + 1 + # 函数类型后缀 " ( … )" + q: str = _mlir_ws(p) + if q[0] == '(': + if n + 1 < outsz: + out[n] = ' ' + n += 1 + p = q + d2: int = 0 + while p[0] != '\0': + ch2: int = p[0] + if ch2 == '(': + d2 += 1 + elif ch2 == ')': + if n + 1 < outsz: + out[n] = ch2 + n += 1 + p = p + 1 + d2 -= 1 + if d2 <= 0: + break + continue + if n + 1 < outsz: + out[n] = ch2 + n += 1 + p = p + 1 + while p[0] == '*': + if n + 1 < outsz: + out[n] = '*' + n += 1 + p = p + 1 + out[n] = '\0' + return p + + +def _mlir_in_set(ob: str, setstr: str) -> int: + """判断 opcode 是否属于 "|a|b|c|" 形式的集合""" + tb: str = _SC_Tb + tb[0] = '\0' + string.strcat(tb, "|") + string.strcat(tb, ob) + string.strcat(tb, "|") + if string.strstr(setstr, tb) is not None: + return 1 + return 0 + + +def _MlirBlkRef(t: str) -> str: + """块引用文本:去掉前导 '%'(MLIR 块用 ^name)""" + if t is None: + return "" + if t[0] == '%': + return t + 1 + return t + + +def _MlirFindBlock(func: rawptr[Function], name: str) -> rawptr[BasicBlock]: + """按块名(不含 %)在函数内查找基本块""" + if func is None or func.Blocks is None or name is None: + return None + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + blk: rawptr[BasicBlock] = blocks.Head + steps: int = 0 + while blk is not None: + steps += 1 + if steps > IR_DUMP_CHAIN_LIMIT: + MlirFail("MLIR 渲染: 块链疑似成环") + if blk.Name is not None and string.strcmp(blk.Name, name) == 0: + return blk + blk = blk.Next + return None + + +def _MlirIsPhiLine(text: str) -> int: + """判断是否为 phi 行""" + if text is None: + return 0 + if string.strstr(text, " = phi ") is not None: + return 1 + return 0 + + +# ============================================================ +# 操作数渲染(含常量物化) +# ============================================================ +def _MlirOperand(val: str, tyllvm: str, out: str, outsz: sizet) -> str: + """渲染一个操作数,返回其最终文本 + + SSA 值 → 别名解析后的 %name; + 非 SSA(字面量/符号引用)→ 物化后的 %cN(scan 阶段顺带登记)。 + """ + if val is None or val[0] == '\0': + MlirFail("MLIR 渲染: 操作数为空") + if val[0] == '%': + r: str = _MlirResolve(val) + _append_cstr(out, outsz, r) + return r + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, tyllvm, _MLIR_Pool) + nm: str = _MlirConstGet(mt, val) + _append_cstr(out, outsz, nm) + return nm + + +# ============================================================ +# phi 解析 +# ============================================================ +def _MlirPhiScan(text: str): + """扫描 phi 行:登记所有入边常量(scan 阶段专用)""" + p: str = _mlir_ws(text) + tb: str = _SC_Buf + p = _mlir_read_value(p, tb, 512) + p = _mlir_ws(p) + if p[0] == '=': + p = _mlir_ws(p + 1) + ob: str = _SC_Op + p = _mlir_read_value(p, ob, 64) + if string.strcmp(ob, "phi") != 0: + return + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + g: int = 0 + while p[0] != '\0': + g += 1 + if g > 512: + MlirFail("MLIR 渲染: phi 入边过多") + p = _mlir_ws(p) + if p[0] != '[': + break + p = _mlir_ws(p + 1) + vb: str = _SC_P1 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + bb: str = _SC_P2 + p = _mlir_read_value(p, bb, 512) + p = _mlir_ws(p) + if p[0] == ']': + p = p + 1 + p = _mlir_ws(p) + if p[0] == ',': + p = p + 1 + # 登记该入边值(常量/符号引用需要物化) + _MlirOperand(vb, tyb, None, 0) + + +def _MlirPhiParam(text: str) -> int: + """取 phi 的结果名与类型作为块参数;成功写 _SC_B1(名)/_SC_B2(类型) 返回 1""" + p: str = _mlir_ws(text) + nm: str = _SC_B1 + p = _mlir_read_value(p, nm, 512) + p = _mlir_ws(p) + if p[0] != '=': + return 0 + p = _mlir_ws(p + 1) + ob: str = _SC_Op + p = _mlir_read_value(p, ob, 64) + if string.strcmp(ob, "phi") != 0: + return 0 + tyb: str = _SC_B2 + _mlir_read_type(p, tyb, 512) + return 1 + + +def _MlirPhiFindIncoming(text: str, src: rawptr[BasicBlock]) -> int: + """找与源块匹配的 phi 入边;成功写 _SC_B1(值)/_SC_B2(类型) 返回 1""" + p: str = _mlir_ws(text) + tb: str = _SC_Buf + p = _mlir_read_value(p, tb, 512) + p = _mlir_ws(p) + if p[0] == '=': + p = _mlir_ws(p + 1) + ob: str = _SC_Op + p = _mlir_read_value(p, ob, 64) + if string.strcmp(ob, "phi") != 0: + return 0 + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + srcn: str = None + if src is not None: + srcn = src.Name + g: int = 0 + while p[0] != '\0': + g += 1 + if g > 512: + MlirFail("MLIR 渲染: phi 入边过多") + p = _mlir_ws(p) + if p[0] != '[': + break + p = _mlir_ws(p + 1) + vb: str = _SC_P1 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + bb: str = _SC_P2 + p = _mlir_read_value(p, bb, 512) + p = _mlir_ws(p) + if p[0] == ']': + p = p + 1 + p = _mlir_ws(p) + if p[0] == ',': + p = p + 1 + if srcn is not None: + bn: str = bb + if bn[0] == '%': + bn = bn + 1 + if string.strcmp(bn, srcn) == 0: + string.strcpy(_SC_B1, vb) + string.strcpy(_SC_B2, tyb) + return 1 + return 0 + + +# ============================================================ +# 块参数 / 块实参 +# ============================================================ +def _MlirBlockHasPhi(blk: rawptr[BasicBlock]) -> int: + """判断块首是否有 phi(即该块是否带块参数)""" + if blk is None or blk.Lines is None: + return 0 + lines: rawptr[GSList[Line]] = blk.Lines + ln: rawptr[Line] = lines.Head + while ln is not None: + if ln.Buf is not None: + if _MlirIsPhiLine(ln.Buf) != 0: + return 1 + return 0 + ln = ln.Next + return 0 + + +def _MlirBlockOperands(out: str, outsz: sizet, + target: rawptr[BasicBlock], src: rawptr[BasicBlock]): + """跳转到 target 时按其块参数生成实参: (%v : ty, …) + + 入边按源块匹配 phi;匹配不到 → 响亮报错(绝不静默丢实参)。 + """ + if target is None or src is None: + return + if _MlirBlockHasPhi(target) == 0: + return + tmp: str = _SC_Tmp + tmp[0] = '\0' + lines: rawptr[GSList[Line]] = target.Lines + ln: rawptr[Line] = lines.Head + cnt: int = 0 + while ln is not None: + if ln.Buf is None: + ln = ln.Next + continue + if _MlirIsPhiLine(ln.Buf) == 0: + break + if _MlirPhiFindIncoming(ln.Buf, src) == 0: + MlirFail("MLIR 渲染: 跳转目标块带 phi,但找不到与源块匹配的入边") + if cnt > 0: + _append_cstr(tmp, 4096, ", ") + _MlirOperand(_SC_B1, _SC_B2, tmp, 4096) + _append_cstr(tmp, 4096, " : ") + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, _SC_B2, _MLIR_Pool) + _append_cstr(tmp, 4096, mt) + cnt += 1 + ln = ln.Next + if cnt == 0: + MlirFail("MLIR 渲染: 目标块带 phi 但未生成块实参") + _append_cstr(out, outsz, "(") + _append_cstr(out, outsz, tmp) + _append_cstr(out, outsz, ")") + + +def _MlirEmitBlockHeader(out: str, outsz: sizet, blk: rawptr[BasicBlock]): + """输出非 entry 块头: ^name(%p: ty, …):""" + _append_cstr(out, outsz, "^") + if blk.Name is not None: + _append_cstr(out, outsz, blk.Name) + if _MlirBlockHasPhi(blk) != 0: + tmp: str = _SC_Tmp + tmp[0] = '\0' + lines: rawptr[GSList[Line]] = blk.Lines + ln: rawptr[Line] = lines.Head + cnt: int = 0 + while ln is not None: + if ln.Buf is None: + ln = ln.Next + continue + if _MlirIsPhiLine(ln.Buf) == 0: + break + if _MlirPhiParam(ln.Buf) != 0: + if cnt > 0: + _append_cstr(tmp, 4096, ", ") + _append_cstr(tmp, 4096, _SC_B1) + _append_cstr(tmp, 4096, ": ") + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, _SC_B2, _MLIR_Pool) + _append_cstr(tmp, 4096, mt) + cnt += 1 + ln = ln.Next + if cnt == 0: + MlirFail("MLIR 渲染: 块首 phi 解析失败") + _append_cstr(out, outsz, "(") + _append_cstr(out, outsz, tmp) + _append_cstr(out, outsz, ")") + _append_cstr(out, outsz, ":\n") + + +def _MlirEmitBlockLines(out: str, outsz: sizet, blk: rawptr[BasicBlock]): + """输出块内指令(跳过块首连续 phi —— 它们已成为块参数)""" + if blk is None or blk.Lines is None: + return + lines: rawptr[GSList[Line]] = blk.Lines + ln: rawptr[Line] = lines.Head + skipping: int = 1 + steps: int = 0 + while ln is not None: + steps += 1 + if steps > IR_DUMP_CHAIN_LIMIT: + MlirFail("MLIR 渲染: 块指令链疑似成环") + if ln.Buf is not None: + if skipping != 0 and _MlirIsPhiLine(ln.Buf) != 0: + ln = ln.Next + continue + skipping = 0 + _MlirRenderLine(ln.Buf, out, outsz) + ln = ln.Next + + +def _MlirCheckEntryNoPhi(blk: rawptr[BasicBlock]): + """entry 块不允许 phi(无前驱,无法成为块参数)""" + if _MlirBlockHasPhi(blk) != 0: + MlirFail("MLIR 渲染: entry 块不允许 phi(MLIR entry 块不接受块参数)") + + +# ============================================================ +# 各指令的 MLIR 渲染 +# ============================================================ +def _MlirEmitRes(out: str, outsz: sizet, resname: str): + """输出 " [%N = ]" 前缀""" + _append_cstr(out, outsz, " ") + if resname is not None: + _append_cstr(out, outsz, resname) + _append_cstr(out, outsz, " = ") + + +def _MlirBinop(p: str, resname: str, ob: str, out: str, outsz: sizet): + """整数/浮点二元运算: llvm. %a, %b : ty""" + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + lb: str = _SC_V1 + p = _mlir_read_value(p, lb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + rb: str = _SC_V2 + _mlir_read_value(p, rb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.") + _append_cstr(out, outsz, ob) + _append_cstr(out, outsz, " ") + _MlirOperand(lb, tyb, out, outsz) + _append_cstr(out, outsz, ", ") + _MlirOperand(rb, tyb, out, outsz) + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, tyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, "\n") + + +def _MlirFneg(p: str, resname: str, out: str, outsz: sizet): + """fneg: llvm.fneg %a : ty""" + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + vb: str = _SC_V1 + _mlir_read_value(p, vb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.fneg ") + _MlirOperand(vb, tyb, out, outsz) + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, tyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, "\n") + + +def _MlirCmp(p: str, resname: str, ob: str, out: str, outsz: sizet): + """icmp/fcmp: llvm.icmp "sgt" %a, %b : ty + + 中间文本是 LLVM 语法 `icmp <谓词> <类型> , `——**谓词在类型之前**, + 故读取顺序必须是 谓词 → 类型 → 操作数。 + 注意不能先读类型:那样会把谓词(如 `sgt`)当类型文本传给 _MlirTypeAppend, + 直接触发"无法转换为 MLIR 类型文本"而中止(Test 4 首条指令即 icmp 的根因)。 + """ + pb: str = _SC_P1 + p = _mlir_read_value(p, pb, 512) + p = _mlir_ws(p) + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + lb: str = _SC_V1 + p = _mlir_read_value(p, lb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + rb: str = _SC_V2 + _mlir_read_value(p, rb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.") + _append_cstr(out, outsz, ob) + _append_cstr(out, outsz, " \"") + _append_cstr(out, outsz, pb) + _append_cstr(out, outsz, "\" ") + _MlirOperand(lb, tyb, out, outsz) + _append_cstr(out, outsz, ", ") + _MlirOperand(rb, tyb, out, outsz) + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, tyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, "\n") + + +def _MlirAlloca(p: str, resname: str, out: str, outsz: sizet): + """alloca: llvm.alloca %cN x ty : (i32) -> !llvm.ptr""" + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + p = _mlir_ws(p) + if p[0] == ',': + # ", align N" —— MLIR 对齐属性形态未经 mlir-opt 验证,v1 响亮报错 + MlirFail("MLIR 渲染: alloca 对齐(build_alloca_aligned)v1 不支持") + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, tyb, _MLIR_Pool) + cnt: str = _MlirConstGet("i32", "1") + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.alloca ") + _append_cstr(out, outsz, cnt) + _append_cstr(out, outsz, " x ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, " : (i32) -> !llvm.ptr\n") + + +def _MlirLoad(p: str, resname: str, out: str, outsz: sizet): + """load: llvm.load %p : !llvm.ptr -> ty""" + p = _mlir_ws(p) + vol: int = 0 + if string.strncmp(p, "volatile ", 9) == 0: + vol = 1 + p = _mlir_ws(p + 9) + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + ptyb: str = _SC_Ty2 + p = _mlir_read_type(p, ptyb, 512) + p = _mlir_ws(p) + pb: str = _SC_V1 + _mlir_read_value(p, pb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.load ") + if vol != 0: + _append_cstr(out, outsz, "volatile ") + _MlirOperand(pb, ptyb, out, outsz) + tmt: str = _SC_Mt + tmt[0] = '\0' + MlirTypeText(tmt, 512, tyb, _MLIR_Pool) + pmt: str = _SC_Tmp2 + pmt[0] = '\0' + MlirTypeText(pmt, 1024, ptyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, pmt) + _append_cstr(out, outsz, " -> ") + _append_cstr(out, outsz, tmt) + _append_cstr(out, outsz, "\n") + + +def _MlirStore(p: str, out: str, outsz: sizet): + """store: llvm.store %v, %p : ty, !llvm.ptr""" + p = _mlir_ws(p) + vol: int = 0 + if string.strncmp(p, "volatile ", 9) == 0: + vol = 1 + p = _mlir_ws(p + 9) + vtyb: str = _SC_Ty + p = _mlir_read_type(p, vtyb, 512) + p = _mlir_ws(p) + vb: str = _SC_V1 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + ptyb: str = _SC_Ty2 + p = _mlir_read_type(p, ptyb, 512) + p = _mlir_ws(p) + pb: str = _SC_V2 + _mlir_read_value(p, pb, 512) + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.store ") + if vol != 0: + _append_cstr(out, outsz, "volatile ") + _MlirOperand(vb, vtyb, out, outsz) + _append_cstr(out, outsz, ", ") + _MlirOperand(pb, ptyb, out, outsz) + vmt: str = _SC_Mt + vmt[0] = '\0' + MlirTypeText(vmt, 512, vtyb, _MLIR_Pool) + pmt: str = _SC_Tmp2 + pmt[0] = '\0' + MlirTypeText(pmt, 1024, ptyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, vmt) + _append_cstr(out, outsz, ", ") + _append_cstr(out, outsz, pmt) + _append_cstr(out, outsz, "\n") + + +def _MlirBr(p: str, out: str, outsz: sizet): + """br:LLVM 语法里条件跳转的 opcode **也是 `br`**,靠首个记号是否为 `label` 分流 + + br label %x → llvm.br ^x + br i1 %c, label %a, label %b → llvm.cond_br %c, ^a, ^b + + 注意:build_cond_br 产出的中间文本是 `br i1 …`(**不是** `cond_br`), + 故条件形态必须在此转交 _MlirCondBr;否则会被当无条件跳转, + 把类型 `i1` 误当块名(产出 `llvm.br ^i1` 且丢掉条件)。 + """ + p = _mlir_ws(p) + if string.strncmp(p, "label ", 6) != 0: + # 条件跳转:`<类型> , label %a, label %b` + _MlirCondBr(p, out, outsz) + return + p = _mlir_ws(p + 6) + tb: str = _SC_V1 + _mlir_read_value(p, tb, 512) + br: str = _MlirBlkRef(tb) + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.br ^") + _append_cstr(out, outsz, br) + _MlirBlockOperands(out, outsz, _MlirFindBlock(_MLIR_Func, br), _MLIR_SrcBlk) + _append_cstr(out, outsz, "\n") + + +def _MlirCondBr(p: str, out: str, outsz: sizet): + """cond_br: llvm.cond_br %c, ^then(%v : ty), ^else(%v : ty)""" + ctyb: str = _SC_Ty + p = _mlir_read_type(p, ctyb, 512) + p = _mlir_ws(p) + cb: str = _SC_V1 + p = _mlir_read_value(p, cb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + if string.strncmp(p, "label ", 6) == 0: + p = _mlir_ws(p + 6) + tb: str = _SC_V2 + p = _mlir_read_value(p, tb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + if string.strncmp(p, "label ", 6) == 0: + p = _mlir_ws(p + 6) + eb: str = _SC_V3 + _mlir_read_value(p, eb, 512) + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.cond_br ") + _MlirOperand(cb, ctyb, out, outsz) + tr: str = _MlirBlkRef(tb) + _append_cstr(out, outsz, ", ^") + _append_cstr(out, outsz, tr) + _MlirBlockOperands(out, outsz, _MlirFindBlock(_MLIR_Func, tr), _MLIR_SrcBlk) + er: str = _MlirBlkRef(eb) + _append_cstr(out, outsz, ", ^") + _append_cstr(out, outsz, er) + _MlirBlockOperands(out, outsz, _MlirFindBlock(_MLIR_Func, er), _MLIR_SrcBlk) + _append_cstr(out, outsz, "\n") + + +def _MlirRet(p: str, out: str, outsz: sizet): + """ret: llvm.return %v : ty(void 省略操作数与类型)""" + p = _mlir_ws(p) + if string.strncmp(p, "void", 4) == 0 and (p[4] == '\0' or p[4] == ' '): + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.return\n") + return + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + vb: str = _SC_V1 + _mlir_read_value(p, vb, 512) + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.return ") + _MlirOperand(vb, tyb, out, outsz) + mt: str = _SC_Mt + mt[0] = '\0' + MlirTypeText(mt, 512, tyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, mt) + _append_cstr(out, outsz, "\n") + + +def _MlirUnreachable(out: str, outsz: sizet): + """unreachable: llvm.unreachable""" + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.unreachable\n") + + +def _MlirCall(p: str, resname: str, out: str, outsz: sizet): + """call: llvm.call @f(%a) : (i32) -> i32 / 间接 llvm.call %fp(%a) : !llvm.ptr, (i32) -> i32""" + p = _mlir_ws(p) + rtyb: str = _SC_Ty + p = _mlir_read_type(p, rtyb, 512) + p = _mlir_ws(p) + if string.strncmp(p, "asm", 3) == 0: + # 内联汇编按 builder 形态渲染为 "call asm ..." + MlirFail("MLIR 渲染: inline_asm 的 MLIR 形态未固化,v1 不支持") + if p[0] == '(': + MlirFail("MLIR 渲染: 变参 call 的 MLIR 形态未固化,v1 不支持") + calb: str = _SC_Callee + p = _mlir_read_value(p, calb, 512) + p = _mlir_ws(p) + if p[0] != '(': + MlirFail("MLIR 渲染: call 缺少实参列表") + p = p + 1 + args: str = _SC_Args + argts: str = _SC_ArgTs + args[0] = '\0' + argts[0] = '\0' + nargs: int = 0 + g: int = 0 + while p[0] != '\0': + g += 1 + if g > 256: + MlirFail("MLIR 渲染: call 实参过多") + p = _mlir_ws(p) + if p[0] == ')': + break + atyb: str = _SC_Ty2 + p = _mlir_read_type(p, atyb, 512) + p = _mlir_ws(p) + avb: str = _SC_V1 + p = _mlir_read_value(p, avb, 512) + if nargs > 0: + _append_cstr(args, 2048, ", ") + _append_cstr(argts, 2048, ", ") + _MlirOperand(avb, atyb, args, 2048) + amt: str = _SC_Tmp2 + amt[0] = '\0' + MlirTypeText(amt, 1024, atyb, _MLIR_Pool) + _append_cstr(argts, 2048, amt) + nargs += 1 + p = _mlir_ws(p) + if p[0] == ',': + p = p + 1 + rmt: str = _SC_Mt + rmt[0] = '\0' + MlirTypeText(rmt, 512, rtyb, _MLIR_Pool) + if string.strcmp(rmt, "none") == 0: + _MlirEmitRes(out, outsz, None) + else: + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.call ") + _append_cstr(out, outsz, calb) + _append_cstr(out, outsz, "(") + _append_cstr(out, outsz, args) + _append_cstr(out, outsz, ") : ") + if calb[0] != '@': + # 间接调用:被调用者是 !llvm.ptr 操作数 + _append_cstr(out, outsz, "!llvm.ptr, ") + _append_cstr(out, outsz, "(") + _append_cstr(out, outsz, argts) + _append_cstr(out, outsz, ") -> ") + if string.strcmp(rmt, "none") == 0: + _append_cstr(out, outsz, "()") + else: + _append_cstr(out, outsz, rmt) + _append_cstr(out, outsz, "\n") + + +def _MlirCast(p: str, resname: str, ob: str, out: str, outsz: sizet): + """转换指令: llvm.zext %v : i32 to i64""" + ftyb: str = _SC_Ty + p = _mlir_read_type(p, ftyb, 512) + p = _mlir_ws(p) + vb: str = _SC_V1 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + if string.strncmp(p, "to ", 3) == 0: + p = _mlir_ws(p + 3) + ttyb: str = _SC_Ty2 + _mlir_read_type(p, ttyb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.") + _append_cstr(out, outsz, ob) + _append_cstr(out, outsz, " ") + _MlirOperand(vb, ftyb, out, outsz) + fmt: str = _SC_Mt + fmt[0] = '\0' + MlirTypeText(fmt, 512, ftyb, _MLIR_Pool) + tmt: str = _SC_Tmp2 + tmt[0] = '\0' + MlirTypeText(tmt, 1024, ttyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, fmt) + _append_cstr(out, outsz, " to ") + _append_cstr(out, outsz, tmt) + _append_cstr(out, outsz, "\n") + + +def _MlirBitcast(p: str, resname: str, out: str, outsz: sizet): + """bitcast: ptr→ptr 视为 no-op(记录别名);否则 llvm.bitcast %v : T to U""" + ftyb: str = _SC_Ty + p = _mlir_read_type(p, ftyb, 512) + p = _mlir_ws(p) + vb: str = _SC_V1 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + if string.strncmp(p, "to ", 3) == 0: + p = _mlir_ws(p + 3) + ttyb: str = _SC_Ty2 + _mlir_read_type(p, ttyb, 512) + if MlirTypeTextIsPointer(ftyb) != 0 and MlirTypeTextIsPointer(ttyb) != 0: + # MLIR 不透明指针下 ptr→ptr bitcast 无意义 → no-op: + # 把结果名登记为源操作数别名(后续引用自动改写),不输出指令 + if resname is None: + MlirFail("MLIR 渲染: no-op bitcast 缺少结果名") + opnd: str = _MlirOperand(vb, ftyb, None, 0) + _MlirAliasAdd(resname, opnd) + return + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.bitcast ") + _MlirOperand(vb, ftyb, out, outsz) + fmt: str = _SC_Mt + fmt[0] = '\0' + MlirTypeText(fmt, 512, ftyb, _MLIR_Pool) + tmt: str = _SC_Tmp2 + tmt[0] = '\0' + MlirTypeText(tmt, 1024, ttyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, fmt) + _append_cstr(out, outsz, " to ") + _append_cstr(out, outsz, tmt) + _append_cstr(out, outsz, "\n") + + +def _MlirSelect(p: str, resname: str, out: str, outsz: sizet): + """select: llvm.select %c, %a, %b : i1, i32""" + ctyb: str = _SC_Ty + p = _mlir_read_type(p, ctyb, 512) + p = _mlir_ws(p) + cb: str = _SC_V1 + p = _mlir_read_value(p, cb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + ttyb: str = _SC_Ty2 + p = _mlir_read_type(p, ttyb, 512) + p = _mlir_ws(p) + tb: str = _SC_V2 + p = _mlir_read_value(p, tb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + ftyb: str = _SC_Buf + p = _mlir_read_type(p, ftyb, 512) + p = _mlir_ws(p) + fb: str = _SC_V3 + _mlir_read_value(p, fb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.select ") + _MlirOperand(cb, ctyb, out, outsz) + _append_cstr(out, outsz, ", ") + _MlirOperand(tb, ttyb, out, outsz) + _append_cstr(out, outsz, ", ") + _MlirOperand(fb, ttyb, out, outsz) + cmt: str = _SC_Mt + cmt[0] = '\0' + MlirTypeText(cmt, 512, ctyb, _MLIR_Pool) + vmt: str = _SC_Tmp2 + vmt[0] = '\0' + MlirTypeText(vmt, 1024, ttyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, cmt) + _append_cstr(out, outsz, ", ") + _append_cstr(out, outsz, vmt) + _append_cstr(out, outsz, "\n") + + +def _MlirGep(p: str, resname: str, out: str, outsz: sizet): + """getelementptr: llvm.getelementptr %p[i0, i1] : (!llvm.ptr, t0, t1) -> !llvm.ptr, base""" + baseb: str = _SC_Ty2 + p = _mlir_read_type(p, baseb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + ptyb: str = _SC_Buf + p = _mlir_read_type(p, ptyb, 512) + p = _mlir_ws(p) + pb: str = _SC_V3 + p = _mlir_read_value(p, pb, 512) + idxv: str = _SC_IdxV + idxt: str = _SC_IdxT + idxv[0] = '\0' + idxt[0] = '\0' + p = _mlir_ws(p) + nidx: int = 0 + tmpv: str = _SC_Tmp + tmpv[0] = '\0' + g: int = 0 + while p[0] == ',': + g += 1 + if g > 32: + MlirFail("MLIR 渲染: GEP 索引过多") + p = _mlir_ws(p + 1) + ityb: str = _SC_Ty + p = _mlir_read_type(p, ityb, 512) + p = _mlir_ws(p) + ivb: str = _SC_V1 + p = _mlir_read_value(p, ivb, 512) + if nidx > 0: + _append_cstr(idxv, 1024, ", ") + _append_cstr(idxt, 1024, ", ") + _MlirOperand(ivb, ityb, tmpv, 4096) + _append_cstr(idxv, 1024, tmpv) + tmpv[0] = '\0' + imt: str = _SC_Mt + imt[0] = '\0' + MlirTypeText(imt, 512, ityb, _MLIR_Pool) + _append_cstr(idxt, 1024, imt) + nidx += 1 + p = _mlir_ws(p) + if nidx == 0: + MlirFail("MLIR 渲染: GEP 缺少索引") + bmt: str = _SC_Tmp2 + bmt[0] = '\0' + MlirTypeText(bmt, 1024, baseb, _MLIR_Pool) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.getelementptr ") + _MlirOperand(pb, ptyb, out, outsz) + _append_cstr(out, outsz, "[") + _append_cstr(out, outsz, idxv) + _append_cstr(out, outsz, "] : (!llvm.ptr") + # 每个索引一个类型 + _MlirAppendCommaTypes(out, outsz, idxt) + _append_cstr(out, outsz, ") -> !llvm.ptr, ") + _append_cstr(out, outsz, bmt) + _append_cstr(out, outsz, "\n") + + +def _MlirAppendCommaTypes(out: str, outsz: sizet, tylist: str): + """把 ", t0, t1" 追加到 out(tylist 是逗号分隔的类型串)""" + if tylist is None or tylist[0] == '\0': + return + _append_cstr(out, outsz, ", ") + _append_cstr(out, outsz, tylist) + + +def _MlirSwitch(p: str, out: str, outsz: sizet): + """switch: llvm.switch %v, ^default [0: ^case0, 1: ^case1]""" + tyb: str = _SC_Ty + p = _mlir_read_type(p, tyb, 512) + p = _mlir_ws(p) + vb: str = _SC_V1 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + if string.strncmp(p, "label ", 6) == 0: + p = _mlir_ws(p + 6) + db: str = _SC_V2 + p = _mlir_read_value(p, db, 512) + p = _mlir_ws(p) + if p[0] == '[': + p = p + 1 + cases: str = _SC_Tmp2 + cases[0] = '\0' + ncase: int = 0 + g: int = 0 + while p[0] != '\0': + g += 1 + if g > 1024: + MlirFail("MLIR 渲染: switch 分支过多") + p = _mlir_ws(p) + if p[0] == ']' or p[0] == '\0': + break + ctb: str = _SC_P1 + p = _mlir_read_type(p, ctb, 512) + p = _mlir_ws(p) + cvb: str = _SC_P2 + p = _mlir_read_value(p, cvb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + if string.strncmp(p, "label ", 6) == 0: + p = _mlir_ws(p + 6) + cb: str = _SC_Ty2 + p = _mlir_read_value(p, cb, 512) + if cvb[0] == '%': + MlirFail("MLIR 渲染: switch case 值必须是常量(SSA 值不支持)") + if ncase > 0: + _append_cstr(cases, 1024, ", ") + _append_cstr(cases, 1024, cvb) + _append_cstr(cases, 1024, ": ^") + _append_cstr(cases, 1024, _MlirBlkRef(cb)) + ncase += 1 + p = _mlir_ws(p) + if p[0] == ',': + p = p + 1 + dr: str = _MlirBlkRef(db) + if _MlirBlockHasPhi(_MlirFindBlock(_MLIR_Func, dr)) != 0: + MlirFail("MLIR 渲染: switch 目标块带 phi(携带块实参)v1 不支持") + _MlirEmitRes(out, outsz, None) + _append_cstr(out, outsz, "llvm.switch ") + _MlirOperand(vb, tyb, out, outsz) + _append_cstr(out, outsz, ", ^") + _append_cstr(out, outsz, dr) + _append_cstr(out, outsz, " [") + _append_cstr(out, outsz, cases) + _append_cstr(out, outsz, "]\n") + + +def _MlirAtomicRmw(p: str, resname: str, out: str, outsz: sizet): + """atomicrmw: llvm.atomicrmw add %p, %v monotonic : !llvm.ptr, i32""" + aop: str = _SC_P1 + p = _mlir_read_value(p, aop, 512) + p = _mlir_ws(p) + ptyb: str = _SC_Ty + p = _mlir_read_type(p, ptyb, 512) + p = _mlir_ws(p) + pb: str = _SC_V1 + p = _mlir_read_value(p, pb, 512) + p = _mlir_ws(p) + if p[0] == ',': + p = _mlir_ws(p + 1) + vtyb: str = _SC_Ty2 + p = _mlir_read_type(p, vtyb, 512) + p = _mlir_ws(p) + vb: str = _SC_V2 + p = _mlir_read_value(p, vb, 512) + p = _mlir_ws(p) + ordb: str = _SC_P2 + _mlir_read_value(p, ordb, 512) + _MlirEmitRes(out, outsz, resname) + _append_cstr(out, outsz, "llvm.atomicrmw ") + _append_cstr(out, outsz, aop) + _append_cstr(out, outsz, " ") + _MlirOperand(pb, ptyb, out, outsz) + _append_cstr(out, outsz, ", ") + _MlirOperand(vb, vtyb, out, outsz) + _append_cstr(out, outsz, " ") + _append_cstr(out, outsz, ordb) + pmt: str = _SC_Mt + pmt[0] = '\0' + MlirTypeText(pmt, 512, ptyb, _MLIR_Pool) + vmt: str = _SC_Tmp2 + vmt[0] = '\0' + MlirTypeText(vmt, 1024, vtyb, _MLIR_Pool) + _append_cstr(out, outsz, " : ") + _append_cstr(out, outsz, pmt) + _append_cstr(out, outsz, ", ") + _append_cstr(out, outsz, vmt) + _append_cstr(out, outsz, "\n") + + +# ============================================================ +# 指令行 → MLIR 分派 +# ============================================================ +def _MlirRenderLine(text: str, out: str, outsz: sizet): + """解析一条中间指令文本并渲染为 MLIR(out=None 时仅登记/校验)""" + global _MLIR_Pass + if text is None: + return + p: str = _mlir_ws(text) + if p[0] == '\0': + return + resname: str = None + if p[0] == '%': + tb: str = _SC_Tb + q: str = _mlir_read_value(p, tb, 512) + q2: str = _mlir_ws(q) + if q2[0] == '=': + resname = _mlir_dup(tb) + p = _mlir_ws(q2 + 1) + ob: str = _SC_Op + p = _mlir_read_value(p, ob, 64) + if ob[0] == '\0': + MlirFail("MLIR 渲染: 空指令") + if _mlir_in_set(ob, "|add|sub|mul|sdiv|udiv|srem|urem|and|or|xor|shl|lshr|ashr|") != 0: + _MlirBinop(p, resname, ob, out, outsz) + return + if _mlir_in_set(ob, "|fadd|fsub|fmul|fdiv|frem|") != 0: + _MlirBinop(p, resname, ob, out, outsz) + return + if string.strcmp(ob, "fneg") == 0: + _MlirFneg(p, resname, out, outsz) + return + if string.strcmp(ob, "icmp") == 0: + _MlirCmp(p, resname, ob, out, outsz) + return + if string.strcmp(ob, "fcmp") == 0: + _MlirCmp(p, resname, ob, out, outsz) + return + if string.strcmp(ob, "alloca") == 0: + _MlirAlloca(p, resname, out, outsz) + return + if string.strcmp(ob, "load") == 0: + _MlirLoad(p, resname, out, outsz) + return + if string.strcmp(ob, "store") == 0: + _MlirStore(p, out, outsz) + return + if string.strcmp(ob, "br") == 0: + _MlirBr(p, out, outsz) + return + if string.strcmp(ob, "ret") == 0: + _MlirRet(p, out, outsz) + return + if string.strcmp(ob, "unreachable") == 0: + _MlirUnreachable(out, outsz) + return + if string.strcmp(ob, "call") == 0: + _MlirCall(p, resname, out, outsz) + return + if string.strcmp(ob, "select") == 0: + _MlirSelect(p, resname, out, outsz) + return + if string.strcmp(ob, "phi") == 0: + if out is not None: + # 块首 phi 已在 _MlirEmitBlockLines 中跳过;走到这里说明 phi 不在块首 + MlirFail("MLIR 渲染: phi 不在块首(v1 只支持块首连续 phi → 块参数)") + _MlirPhiScan(text) + return + if string.strcmp(ob, "getelementptr") == 0: + _MlirGep(p, resname, out, outsz) + return + if string.strcmp(ob, "bitcast") == 0: + _MlirBitcast(p, resname, out, outsz) + return + if _mlir_in_set(ob, "|sext|trunc|zext|ptrtoint|inttoptr|fpext|fptrunc|fptosi|sitofp|fptoui|uitofp|") != 0: + _MlirCast(p, resname, ob, out, outsz) + return + if string.strcmp(ob, "switch") == 0: + _MlirSwitch(p, out, outsz) + return + if string.strcmp(ob, "atomicrmw") == 0: + _MlirAtomicRmw(p, resname, out, outsz) + return + if string.strcmp(ob, "cmpxchg") == 0: + MlirFail("MLIR 渲染: cmpxchg 的 MLIR 形态未固化,v1 不支持") + if string.strcmp(ob, "va_arg") == 0: + MlirFail("MLIR 渲染: va_arg v1 不支持") + # 注:内联汇编在中间文本里 opcode 是 "call"(call asm ...), + # 由 _MlirCall 内部识别并响亮报错。 + MlirFail("MLIR 渲染: 未知指令 opcode") + + +# ============================================================ +# 函数签名与函数体 +# ============================================================ +def _MlirFuncSig(buf: str, size: sizet, + func: rawptr[Function], pool: memhub.MemBuddy*): + """llvm.func @name(%a: i32, %b: i32) -> i32(void 返回省略 -> ty)""" + _append_cstr(buf, size, "llvm.func @") + 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, "(") + params: rawptr[GSList[Param]] = func.Params + cur: rawptr[Param] = None + if params is not None: + cur = params.Head + first: int = 1 + cur_steps: int = 0 + while cur is not None: + cur_steps += 1 + if cur_steps > IR_DUMP_CHAIN_LIMIT: + MlirFail("MLIR 渲染: 参数链疑似成环") + if first == 0: + _append_cstr(buf, size, ", ") + if cur.Name is not None: + if cur.Name[0] != '%': + _append_cstr(buf, size, "%") + _append_cstr(buf, size, cur.Name) + _append_cstr(buf, size, ": ") + ty_buf: str = _SC_Ty + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, cur.Ty, pool) + _append_cstr(buf, size, ty_buf) + cur = cur.Next + first = 0 + _append_cstr(buf, size, ")") + # 变参函数:MLIR 形态未固化 → 响亮报错(见 README v1 不支持清单) + if func.IsVarArg == 1: + MlirFail("MLIR 渲染: 变参函数(...)的 llvm.func 形态未固化,v1 不支持") + # 返回类型(Void 省略) + is_void: int = 0 + match func.RetTy: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + if is_void == 0: + ret_buf: str = _SC_Ty2 + ret_buf[0] = '\0' + TypePrint(ret_buf, 512, func.RetTy, pool) + _append_cstr(buf, size, " -> ") + _append_cstr(buf, size, ret_buf) + + +def FunctionPrint(buf: str, size: sizet, + func: rawptr[Function], pool: memhub.MemBuddy*): + """将函数 func 序列化为 MLIR(llvm 方言) 文本**追加**写入 buf + + 注意:与 llvmlite 版一致,本函数为追加写(供模块打印连续拼接多个函数), + 调用方若要单函数文本需自行先置 buf[0]='\\0'。 + """ + global _MLIR_Pass, _MLIR_Func, _MLIR_SrcBlk + if func is None or buf is None or size == 0: + return + + # 先本地窥孔(ret zeroinitializer→0/null、入口槽 store→load 转发、 + # no-op bitcast 消除):窥孔按"名称一致性"匹配、删除行置 Buf=None。 + # 窥孔作用在 **builders 生成的中间指令文本** 层,与 MLIR 渲染正交; + # RenumberSSA 内部会跳过 declare 函数(IsDeclared==1)。 + if func.IsDeclared == 0 and G_PeepEnable != 0: + _peephole_opt(func, pool) + RenumberSSA(func, pool) + + _MlirTablesInit(pool) + _MLIR_Func = func + + if func.IsDeclared == 1: + # declare(无函数体) + _MlirFuncSig(buf, size, func, pool) + _append_cstr(buf, size, "\n") + return + + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + if blocks is None: + _MlirFuncSig(buf, size, func, pool) + _append_cstr(buf, size, "\n") + return + + # ---- pass1:扫描(登记常量/别名 + 形态校验)---- + _MLIR_Pass = 1 + blk: rawptr[BasicBlock] = blocks.Head + blk_steps: int = 0 + while blk is not None: + blk_steps += 1 + if blk_steps > IR_DUMP_CHAIN_LIMIT: + MlirFail("MLIR 渲染: 函数块链疑似成环") + _MLIR_SrcBlk = blk + if blk.Lines is not None: + lines: rawptr[GSList[Line]] = blk.Lines + ln: rawptr[Line] = lines.Head + ln_steps: int = 0 + while ln is not None: + ln_steps += 1 + if ln_steps > IR_DUMP_CHAIN_LIMIT: + MlirFail("MLIR 渲染: 块指令链疑似成环") + if ln.Buf is not None: + _MlirRenderLine(ln.Buf, None, 0) + ln = ln.Next + blk = blk.Next + + # ---- pass2:发射 ---- + _MLIR_Pass = 2 + _MlirFuncSig(buf, size, func, pool) + _append_cstr(buf, size, " {\n") + blk = blocks.Head + first: int = 1 + blk_steps = 0 + while blk is not None: + blk_steps += 1 + if blk_steps > IR_DUMP_CHAIN_LIMIT: + MlirFail("MLIR 渲染: 函数块链疑似成环") + _MLIR_SrcBlk = blk + if first != 0: + # entry 块不带标签;常量物化 op 统一插在 entry 块开头 + # (entry 支配全函数 → 常量在所有块内可见,且不破坏 phi 的块首约束) + _MlirCheckEntryNoPhi(blk) + _MlirEmitConsts(buf, size) + else: + _MlirEmitBlockHeader(buf, size, blk) + _MlirEmitBlockLines(buf, size, blk) + blk = blk.Next + first = 0 + _append_cstr(buf, size, "}\n") + + +# ============================================================ +# 内部辅助 +# ============================================================ +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: sizet = 0 + +def _append_cstr(dst: str, dst_size: sizet, src: str): + """将 C 字符串 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos + if dst is None or src is None: return + dlen: sizet = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + # 缓存一致性校验:缓存结尾必须仍是当前文本末端(末端 NUL 且前一字符非 NUL)。 + # 多个模块轮流写同一 buf、或 pool 复用地址残留旧内容时缓存 pos 会过期, + # 追加落到首个 NUL 之后内容"看不见"(LLvmLiteTest Test5/9 根因)。失败回退 strlen。 + if dlen == 0: + if dst[0] != '\0': + dlen = string.strlen(dst) + elif dst[dlen] != '\0' or dst[dlen - 1] == '\0': + dlen = string.strlen(dst) + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen + if remain <= 0: return + i: sizet = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + _g_last_pos = dlen + i + + +# ============================================================ +# 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型 +# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过 +# 字段访问(不生成 GEP,不报错),字段值永远为 null。 +# +# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问 +# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。 +# ============================================================ +def function_get_name(func: rawptr[Function]) -> str: + """获取函数名""" + if func is None: + return None + return func.Name + + +def function_get_name_len(func: rawptr[Function]) -> sizet: + """获取函数名长度(创建时一次算好,恒等于 strlen(Name)) + + 对齐 function_get_name 的跨模块 stub 绕过模式:使用方模块只有 Function + 的 stub 类型(字段不足且字段类型可能错误),直接读 Name/NameLen 字段会被 + TransPyC 静默跳过;本访问器在拥有完整类型定义的本模块内取字段,跨模块经 + 函数调用取得长度,避免对同一函数名反复 strlen(全程序 strlen 热点)。 + """ + if func is None: + return 0 + return func.NameLen + + +def function_get_ret_ty(func: rawptr[Function]) -> rawptr[LLVMType]: + """获取函数返回类型""" + if func is None: + return None + return func.RetTy + + +def function_get_params(func: rawptr[Function]) -> rawptr[GSList[Param]]: + """获取函数参数链表容器""" + if func is None: + return None + return func.Params + + +def function_get_param_head(func: rawptr[Function]) -> rawptr[Param]: + """获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)""" + if func is None: + return None + params: rawptr[GSList[Param]] = func.Params + if params is None: + return None + return params.Head + + +def function_get_next(func: rawptr[Function]) -> rawptr[Function]: + """获取链表下一个函数""" + if func is None: + return None + return func.Next + + +def function_is_declared(func: rawptr[Function]) -> int: + """获取函数是否为声明(1=declare 仅声明, 0=define 定义)""" + if func is None: + return 0 + return func.IsDeclared + + +def param_get_name(param: rawptr[Param]) -> str: + """获取参数名""" + if param is None: + return None + return param.Name + + +def param_get_ty(param: rawptr[Param]) -> rawptr[LLVMType]: + """获取参数类型""" + if param is None: + return None + return param.Ty + + +def param_get_next(param: rawptr[Param]) -> rawptr[Param]: + """获取链表下一个参数""" + if param is None: + return None + return param.Next diff --git a/mlirlite/__init__.vp b/mlirlite/__init__.vp new file mode 100644 index 0000000..8a88bbe --- /dev/null +++ b/mlirlite/__init__.vp @@ -0,0 +1,474 @@ +import t, c +from stdint import * +import memhub +import string +import viperlib + +# ============================================================ +# mlirlite —— 与 llvmlite 逐名同形的 MLIR(llvm 方言) 文本发射库 +# +# 设计原则: +# * 内部模型(LLVMType/Value/Function/BasicBlock/IRBuilder/Module…)与 +# includes/llvmlite **逐名逐签名同形**,因此 TPV 侧只需把 +# `llvmlite.` 重命名为 `mlirlite.` 即可编译; +# * 差异只在"打印"阶段:TypePrint / ValuePrint / FunctionPrint / +# LLVMModulePrint 输出 MLIR 文本,而 builders 仍按原样生成中间指令文本; +# * 名字保留 LLVMxxx(同形优先)。语义差异见 README.md。 +# ============================================================ + +# 导入子模块 +from .__types import ( + LLVMType, ParamNode, LLVMTypeCore, + Int1, Int8, Int16, Int32, Int64, Ptr, Func, Void, Array, Struct, + Half, Float, Double, FP128, Label, + new_param_node, param_list_append, + paramnode_get_ty, paramnode_get_next, paramnode_set_ty, paramnode_set_next, + TypePrint, PrintStructDefinition, get_struct_name, + get_struct_fields, get_struct_fcount, DeepCopyType, +) +from .__values import ( + Value, new_value, ConstInt, ConstNull, ConstZero, ConstFloat, SSAValue, ValuePrint, + value_get_ty, value_get_next, + value_set_ty, value_set_next, value_set_name, value_set_isconst, +) +from .__function import ( + Line, BasicBlock, Param, Function, + new_line, new_basic_block, new_param, new_function, + function_add_param, function_add_block, + block_append_line, block_append_text, + function_set_attrs, param_set_attrs, + function_set_attr_group, + function_get_name, function_get_name_len, 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, G_PeepEnable, +) +from .__module import ( + LLVMModule, GlobalVariable, NamedTypeNode, new_module, new_global_variable, + module_add_function, module_add_global, module_add_named_type, + module_set_named_type_packed, + module_set_target, module_set_datalayout, + global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section, + LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT, + module_ensure_opaque_for_type, +) +from .__builder import ( + IRBuilder, new_builder, position_at_end, + builder_cur_block_is_terminated, + build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store, + build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem, + build_and, build_or, build_xor, build_shl, build_lshr, build_ashr, + build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg, + build_icmp, build_fcmp, + build_br, build_cond_br, build_ret, build_ret_void, + build_call, build_call_indirect, build_bitcast, build_sext, build_trunc, build_zext, + build_ptrtoint, build_inttoptr, + build_fpext, build_fptrunc, build_fp2si, build_si2fp, build_fp2ui, build_ui2fp, + build_gep, build_gep_array, build_gep_struct, + build_phi, build_switch, build_select, build_unreachable, + build_atomicrmw, build_cmpxchg, build_inline_asm, build_va_arg, + PhiIncoming, new_phi_incoming, SwitchCase, new_switch_case, + ICMP_EQ, ICMP_NE, ICMP_SGT, ICMP_SGE, ICMP_SLT, ICMP_SLE, + ICMP_UGT, ICMP_UGE, ICMP_ULT, ICMP_ULE, + FCMP_FALSE, FCMP_OEQ, FCMP_OGT, FCMP_OGE, FCMP_OLT, FCMP_OLE, + FCMP_ONE, FCMP_ORD, FCMP_UNO, FCMP_UEQ, FCMP_UGT, FCMP_UGE, + FCMP_ULT, FCMP_ULE, FCMP_UNE, FCMP_TRUE, + ATOMIC_XCHG, ATOMIC_ADD, ATOMIC_SUB, ATOMIC_AND, ATOMIC_NAND, + ATOMIC_OR, ATOMIC_XOR, ATOMIC_MAX, ATOMIC_MIN, ATOMIC_UMAX, ATOMIC_UMIN, + ATOMIC_ORDER_NOTATOMIC, ATOMIC_ORDER_UNORDERED, ATOMIC_ORDER_MONOTONIC, + ATOMIC_ORDER_ACQUIRE, ATOMIC_ORDER_RELEASE, ATOMIC_ORDER_ACQ_REL, + ATOMIC_ORDER_SEQ_CST, +) +from .__verify import ( + VerifyResult, NameEntry, + verify_function, verify_module, + VERIFY_OK, VERIFY_ERR_NO_TERMINATOR, VERIFY_ERR_DUPLICATE_DEF, + VERIFY_ERR_UNDEFINED_USE, VERIFY_ERR_PHI_NOT_FIRST, + _new_verify_result, +) + + +# ============================================================ +# 便捷工厂: 字符串复制 +# ============================================================ +def _str_dup(pool: memhub.MemBuddy*, src: str) -> str: + """从 pool 分配并复制一个 C 字符串""" + if src is None: return None + slen: sizet = string.strlen(src) + buf: str = pool.alloc(slen + 1) + if buf is None: return None + string.strcpy(buf, src) + return buf + + +# ============================================================ +# 便捷工厂: 创建带名称的基本块 +# ============================================================ +def create_block(pool: memhub.MemBuddy*, func: rawptr[Function], + name: str) -> rawptr[BasicBlock]: + """创建基本块并添加到函数""" + # 块名与函数参数值名冲突防护:LLVM 中块标签 "entry:" 即值 %entry, + # 与参数 %entry 重名 → llc "unable to create block named 'entry'" + # (CallGenCall._field_byte_offset(self, pool, entry, ...) 根因)。 + # 冲突时追加 .1/.2/... 后缀去重(Param.Name 可能带 % 前缀,剥离比较)。 + use_name: str = name + if func is not None and func.Params is not None and name is not None \ + and name[0] != '\0': + cb_len: sizet = string.strlen(name) + 16 + cb_buf: str = pool.alloc(cb_len) + if cb_buf is not None: + cb_k: int = 1 + cb_collide: int = 1 + while cb_collide != 0: + cb_collide = 0 + cb_p: rawptr[Param] = function_get_param_head(func) + while cb_p is not None: + cb_pnm: str = param_get_name(cb_p) + if cb_pnm is not None: + cb_pv: str = cb_pnm + if cb_pv[0] == '%': + cb_pv = cb_pv + 1 + if string.strcmp(cb_pv, use_name) == 0: + cb_collide = 1 + break + cb_p = param_get_next(cb_p) + if cb_collide != 0: + viperlib.snprintf(cb_buf, cb_len, "%s.%d", name, cb_k) + use_name = cb_buf + cb_k += 1 + name_dup: str = _str_dup(pool, use_name) + blk: rawptr[BasicBlock] = new_basic_block(pool, name_dup) + if blk is not None: + function_add_block(func, blk) + return blk + + +# ============================================================ +# 便捷工厂: 创建整数常量值 +# ============================================================ +def const_int(pool: memhub.MemBuddy*, bits: int, + val: int64) -> rawptr[Value]: + """创建整数常量值(自动创建类型 + 名字文本) + + 参数: + bits: 位宽 (1/8/16/32/64) + val: 整数值 + """ + # 创建类型 + ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if ty is None: return None + string.memset(ty, 0, LLVMType.__sizeof__()) + c.DerefAs(ty, LLVMType.Int(bits)) + + # 创建名字文本 + name: str = pool.alloc(32) + if name is None: return None + # LLVM i64 字面量范围不含 INT64_MIN(-9223372036854775808):该值必须 + # 用无符号位模式 9223372036854775808 表示(LLVM 接受),否则 opt 解析 + # "-9223372036854775808" 报 expected value token(二代编 viperlib.vp + # u_num=0x8000000000000000 崩溃根因;gen1/TPC 即输出无符号位模式)。 + if bits == 64 and val == -9223372036854775807 - 1: + viperlib.snprintf(name, 32, "9223372036854775808") + else: + viperlib.snprintf(name, 32, "%lld", val) + + return ConstInt(pool, ty, val, name) + + +def const_int32(pool: memhub.MemBuddy*, val: int64) -> rawptr[Value]: + """便捷: 创建 i32 整数常量""" + return const_int(pool, 32, val) + + +def const_int64(pool: memhub.MemBuddy*, val: int64) -> rawptr[Value]: + """便捷: 创建 i64 整数常量""" + return const_int(pool, 64, val) + + +# ============================================================ +# 便捷工厂: 创建函数并添加到模块 +# ============================================================ +def create_function(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], + name: str, ret_ty: rawptr[LLVMType]) -> rawptr[Function]: + """创建函数并添加到模块""" + name_dup: str = _str_dup(pool, name) + func: rawptr[Function] = 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*, func: rawptr[Function], + ty: rawptr[LLVMType], name: str) -> rawptr[Param]: + """创建参数并添加到函数""" + name_dup: str = _str_dup(pool, name) + param: rawptr[Param] = 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*, mod: rawptr[LLVMModule], + name: str, ret_ty: rawptr[LLVMType]) -> rawptr[Function]: + """创建函数声明(declare,无函数体)并添加到模块 + + 与 create_function 不同,声明不生成函数体,仅生成: + declare @() + """ + name_dup: str = _str_dup(pool, name) + func: rawptr[Function] = new_function(pool, name_dup, ret_ty) + if func is not None: + func.IsDeclared = 1 + module_add_function(mod, func) + return func + + +# ============================================================ +# 便捷工厂: 创建字符串常量全局变量 +# +# 初值以 llvmlite 同形的 **LLVM 语法文本** 存入 gv.Initializer +# (c"contents\00"),MLIR 渲染阶段(__module.vp/_MlirGlobalInit) +# 再转成 MLIR attribute 形态 "contents"。 +# ============================================================ +def create_global_string(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], + name: str, text: str) -> rawptr[GlobalVariable]: + """创建字符串常量全局变量并添加到模块 + + 参数: + name: 全局变量名(如 ".str") + text: 字符串内容(C 字符串,不含末尾 NUL,NUL 由本函数自动添加) + + 返回: GlobalVariable 指针,其类型为 [len+1 x i8] + """ + if text is None: return None + slen: sizet = string.strlen(text) + count: int = slen + 1 # 含末尾 NUL + + # 创建 i8 类型 + i8_ty: rawptr[LLVMType] = 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: rawptr[LLVMType] = 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: str = _str_dup(pool, name) + gv: rawptr[GlobalVariable] = new_global_variable(pool, name_dup, arr_ty) + if gv is None: return None + + # 设置属性: private + unnamed_addr + constant + global_set_linkage(gv, "private") + global_set_unnamed_addr(gv, 1) + global_set_constant(gv, 1) + + # 构造初始化值文本: c"contents\00" + # LLVM IR 字符串字面量格式: c"" 其中 " 和 \ 及非打印字符用 \xx 转义 + # 缓冲区大小: 最坏情况每个字符4字节(\xx)+ c"..." + \00 + " + init_buf: str = pool.alloc(slen * 4 + 8) + if init_buf is None: return None + pos: sizet = 0 + init_buf[pos] = 'c' + pos += 1 + init_buf[pos] = '"' + pos += 1 + i: sizet = 0 + while i < slen: + ch: t.CUInt8T = text[i] + if ch == 0x22 or ch == 0x5C or ch < 0x20 or ch >= 0x7F: + # 需要转义: " → \22, \ → \5c, 非打印字符 → \xx + init_buf[pos] = '\\' + pos += 1 + hi: int = (ch >> 4) & 0x0F + lo: int = ch & 0x0F + if hi < 10: + init_buf[pos] = 0x30 + hi + else: + init_buf[pos] = 0x61 + hi - 10 + pos += 1 + if lo < 10: + init_buf[pos] = 0x30 + lo + else: + init_buf[pos] = 0x61 + lo - 10 + pos += 1 + else: + init_buf[pos] = ch + pos += 1 + i += 1 + # 末尾 NUL 字节 + init_buf[pos] = '\\' + pos += 1 + init_buf[pos] = '0' + pos += 1 + init_buf[pos] = '0' + pos += 1 + init_buf[pos] = '"' + pos += 1 + init_buf[pos] = '\0' + gv.Initializer = init_buf + + module_add_global(mod, gv) + return gv + + +# ============================================================ +# 便捷工厂: 创建带初始化值的整数全局变量 +# ============================================================ +def create_global_int(pool: memhub.MemBuddy*, mod: rawptr[LLVMModule], + name: str, bits: int, val: int64) -> rawptr[GlobalVariable]: + """创建整数全局变量并添加到模块 + + MLIR 渲染结果: + llvm.mlir.global @( : i) : i + """ + # 创建整数类型 + ty: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if ty is None: return None + string.memset(ty, 0, LLVMType.__sizeof__()) + c.DerefAs(ty, LLVMType.Int(bits)) + + name_dup: str = _str_dup(pool, name) + gv: rawptr[GlobalVariable] = new_global_variable(pool, name_dup, ty) + if gv is None: return None + + # 构造初始化值文本: "42" (类型由全局渲染阶段单独打印) + init_buf: str = 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: rawptr[LLVMModuleCore] = LLVMModuleCore(pool) +# mod: rawptr[LLVMModule] = mcore.NewModule("test") +# func: rawptr[Function] = mcore.CreateFunction(mod, "add", ty_i32) +# val: rawptr[Value] = mcore.ConstInt32(42) +# ============================================================ +@t.NoVTable +class LLVMModuleCore: + """模块/函数/值创建核心,封装 pool 避免每次创建都传 pool""" + Pool: memhub.MemBuddy* + + def __init__(self, pool: memhub.MemBuddy*): + self.Pool = pool + + # ---- 模块操作 ---- + def NewModule(self, name: str) -> rawptr[LLVMModule]: + return new_module(self.Pool, name) + + def CreateFunction(self, mod: rawptr[LLVMModule], name: str, + ret_ty: rawptr[LLVMType]) -> rawptr[Function]: + return create_function(self.Pool, mod, name, ret_ty) + + def CreateDeclare(self, mod: rawptr[LLVMModule], name: str, + ret_ty: rawptr[LLVMType]) -> rawptr[Function]: + """创建函数声明(declare,无函数体)""" + return create_declare(self.Pool, mod, name, ret_ty) + + def AddParam(self, func: rawptr[Function], ty: rawptr[LLVMType], + name: str) -> rawptr[Param]: + return add_param(self.Pool, func, ty, name) + + def FunctionSetAttrs(self, func: rawptr[Function], attrs: str): + """设置函数级属性文本""" + function_set_attrs(func, attrs) + + def ParamSetAttrs(self, param: rawptr[Param], attrs: str): + """设置参数属性文本""" + param_set_attrs(param, attrs) + + def CreateBlock(self, func: rawptr[Function], + name: str) -> rawptr[BasicBlock]: + return create_block(self.Pool, func, name) + + def NewBuilder(self, func: rawptr[Function]) -> rawptr[IRBuilder]: + return new_builder(self.Pool, func) + + # ---- 全局变量 ---- + def NewGlobal(self, mod: rawptr[LLVMModule], name: str, + ty: rawptr[LLVMType]) -> rawptr[GlobalVariable]: + """创建全局变量并添加到模块""" + name_dup: str = _str_dup(self.Pool, name) + gv: rawptr[GlobalVariable] = new_global_variable(self.Pool, name_dup, ty) + if gv is not None: + module_add_global(mod, gv) + return gv + + def CreateGlobalString(self, mod: rawptr[LLVMModule], name: str, + text: str) -> rawptr[GlobalVariable]: + """创建字符串常量全局变量""" + return create_global_string(self.Pool, mod, name, text) + + def CreateGlobalInt(self, mod: rawptr[LLVMModule], name: str, + bits: int, val: int64) -> rawptr[GlobalVariable]: + """创建带初始化值的整数全局变量""" + return create_global_int(self.Pool, mod, name, bits, val) + + def GlobalSetConstant(self, gv: rawptr[GlobalVariable], is_const: int): + global_set_constant(gv, is_const) + + def GlobalSetLinkage(self, gv: rawptr[GlobalVariable], linkage: str): + global_set_linkage(gv, linkage) + + def GlobalSetUnnamedAddr(self, gv: rawptr[GlobalVariable], level: int): + global_set_unnamed_addr(gv, level) + + def GlobalSetSection(self, gv: rawptr[GlobalVariable], section: str): + global_set_section(gv, section) + + # ---- 值创建 ---- + def ConstInt(self, bits: int, val: int64) -> rawptr[Value]: + return const_int(self.Pool, bits, val) + + def ConstInt32(self, val: int64) -> rawptr[Value]: + return const_int32(self.Pool, val) + + def ConstInt64(self, val: int64) -> rawptr[Value]: + return const_int64(self.Pool, val) + + def ConstFloat(self, ty: rawptr[LLVMType], val: t.CDouble) -> rawptr[Value]: + return ConstFloat(self.Pool, ty, val) + + def SSAValue(self, ty: rawptr[LLVMType], name: str) -> rawptr[Value]: + return SSAValue(self.Pool, ty, name) + + def ConstNull(self, ty: rawptr[LLVMType], name: str) -> rawptr[Value]: + return ConstNull(self.Pool, ty, name) + + # ---- 打印 ---- + def PrintValue(self, buf: str, size: sizet, val: rawptr[Value]): + ValuePrint(buf, size, val, self.Pool) + + def PrintFunction(self, buf: str, size: sizet, func: rawptr[Function]): + FunctionPrint(buf, size, func, self.Pool) + + def PrintModule(self, buf: str, size: sizet, mod: rawptr[LLVMModule]): + LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL) + + # ---- SSA 验证 ---- + def NewVerifyResult(self, buf_size: sizet) -> rawptr[VerifyResult]: + """创建验证结果对象(buf_size 为错误消息缓冲区大小)""" + return _new_verify_result(self.Pool, buf_size) + + def VerifyFunction(self, func: rawptr[Function], + result: rawptr[VerifyResult]) -> int: + """验证单个函数的 SSA 正确性,返回错误数(0=通过)""" + return verify_function(self.Pool, func, result) + + def VerifyModule(self, mod: rawptr[LLVMModule], + result: rawptr[VerifyResult]) -> int: + """验证模块中所有函数的 SSA 正确性,返回错误数(0=通过)""" + return verify_module(self.Pool, mod, result) diff --git a/mlirlite/__module.vp b/mlirlite/__module.vp new file mode 100644 index 0000000..e406b00 --- /dev/null +++ b/mlirlite/__module.vp @@ -0,0 +1,820 @@ +import t, c +from stdint import * +import string +import stdio +import stdlib +import viperlib +import memhub +from linkedlist import GSList, GSListNode +from .__types import ( + LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, + ParamNode, MlirFail, MlirTypeText, +) +from .__function import ( + Function, FunctionPrint, _ll_name_needs_quote, Param, param_get_next, + param_get_ty, _mlir_read_type, _mlir_read_value, _mlir_ws, +) + + +# ============================================================ +# GlobalVariable: LLVM IR 全局变量 +# +# 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。 +# 继承 GSListNode[GlobalVariable] 获取强类型 Next。 +# ============================================================ +@t.NoVTable +class GlobalVariable(GSListNode[GlobalVariable]): + Name: str # 全局变量名(如 ".str" / "my_global") + Ty: rawptr[LLVMType] # 变量类型 + Initializer: rawptr # 初始化值 Value*(None = 无初始化) + IsConstant: int # 1=constant, 0=variable + Linkage: str # 链接类型("private"/"internal"/"external"/...) + Section: str # 段名(None = 默认) + UnnamedAddr: int # 1=unnamed_addr, 2=local_unnamed_addr, 0=none + Align: int # 对齐字节数(0=默认对齐,如 @c.Attribute(t.attr.aligned(16))) + + +# ============================================================ +# NamedTypeNode: 命名结构体类型链表节点 +# +# 持有 LLVMType* 指针(必须是命名 Struct 类型)。 +# 继承 GSListNode[NamedTypeNode] 获取强类型 Next。 +# ============================================================ +@t.NoVTable +class NamedTypeNode(GSListNode[NamedTypeNode]): + Ty: rawptr[LLVMType] # 命名结构体类型指针 + IsPacked: int # 1=packed 结构体(输出 <{...}>,无字段填充) + + +# ============================================================ +# LLVMModule: LLVM IR 模块容器 +# +# 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针, +# 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。 +# LLVMModulePrint 输出完整 .ll 文件内容。 +# 注意: 类名必须为 LLVMModule 而非 Module,避免与 ast.Module 命名冲突 +# ============================================================ +@t.NoVTable +class LLVMModule: + Name: str # 模块名 + FuncHead: rawptr[Function] # 函数链表头 + FuncTail: rawptr[Function] # 函数链表尾 + FuncCount: sizet # 函数计数 + GlobalHead: rawptr[GlobalVariable] # 全局变量链表头 + GlobalTail: rawptr[GlobalVariable] # 全局变量链表尾 + GlobalCount: sizet # 全局变量计数 + TargetTriple: str # 目标三元组(如 "x86_64-pc-linux-gnu") + DataLayout: str # 数据布局(如 "e-m:e-p270:32:32-...") + NamedTypeHead: rawptr[NamedTypeNode] # 命名结构体类型链表头 + NamedTypeTail: rawptr[NamedTypeNode] # 命名结构体类型链表尾 + NamedTypeCount: sizet # 命名结构体类型计数 + # 总计: 12 字段 * 8 = 96 字节(无 vtable) + + # ============================================================ + # 实例方法(对象化重构:原 module_* 顶层函数改写为方法, + # 原顶层函数保留为一行委托) + # ============================================================ + + # ---- 链表操作 ---- + def add_function(self, func: rawptr[Function]): + """将函数追加到模块函数链表(O(1))""" + if self is None or func is None: return + func.Next = None + if self.FuncHead is None: + self.FuncHead = func + else: + self.FuncTail.Next = func + self.FuncTail = func + self.FuncCount += 1 + + def add_global(self, gv: rawptr[GlobalVariable]): + """将全局变量追加到模块全局变量链表(O(1))""" + if self is None or gv is None: return + gv.Next = None + if self.GlobalHead is None: + self.GlobalHead = gv + else: + self.GlobalTail.Next = gv + self.GlobalTail = gv + self.GlobalCount += 1 + + # ---- 目标属性 ---- + def set_target(self, triple: str): + """设置目标三元组""" + if self is None: return + self.TargetTriple = triple + + def set_datalayout(self, layout: str): + """设置数据布局""" + if self is None: return + self.DataLayout = layout + + # ---- 命名结构体类型管理 ---- + def add_named_type(self, pool: memhub.MemBuddy*, ty: rawptr[LLVMType]): + """登记命名结构体类型到模块(MLIR 侧仅保留模型,不产生输出) + + 非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。 + 按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。 + MLIR 无独立类型定义语法:结构体类型在使用处内联为 !llvm.struct<(…)>, + 故本方法不再产生输出文本,命名类型链表(NamedTypeHead)仅作为模型保留, + 供 module_set_named_type_packed / ensure_opaque_for_type 等原有 API 使用。 + """ + if self is None or pool is None or ty is None: + return + name: str = get_struct_name(ty) + if name is None: + return + # 去重检查(opaque 声明可被完整定义替换) + cur: rawptr[NamedTypeNode] = self.NamedTypeHead + cnt_dedup: int = 0 + while cur is not None: + # 步数守卫:NamedTypeHead 链表成环(内存损坏/插入 bug)会导致 + # 无限遍历挂起(G3 编译 LinkedNode.prepend 挂起根因)。 + # 正常链表节点数远小于此上限,超限即链表损坏 → 立即报错终止。 + cnt_dedup += 1 + if cnt_dedup > 100000: + stdio.printf("[ANT-LOOP] NamedTypeHead 链表疑似成环, name=%s, 遍历节点=%d, 强制终止\n", + name if name is not None else "(null)", cnt_dedup) + stdlib.exit(1) + if cur.Ty is not None: + existing_name: str = get_struct_name(cur.Ty) + if existing_name is not None: + if string.strcmp(existing_name, name) == 0: + # 已有完整定义则无需替换 + if _is_opaque_struct(cur.Ty) == 0: + return + # 已有 opaque,新类型也是 opaque 则不重复 + if _is_opaque_struct(ty) != 0: + return + # 用完整定义替换 opaque 声明(原地替换 Ty 指针) + cur.Ty = ty + return + cur = cur.Next + # 创建新节点 + node: rawptr[NamedTypeNode] = pool.alloc(NAMED_TYPE_NODE_SIZE) + if node is None: + return + string.memset(node, 0, NAMED_TYPE_NODE_SIZE) + node.Ty = ty + node.IsPacked = 0 + # opaque 类型插入链表头部,确保在引用它的完整定义之前声明。 + # 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明 + # 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。 + # 完整定义追加到链表尾部,保持原有顺序。 + if _is_opaque_struct(ty) != 0: + node.Next = self.NamedTypeHead + if self.NamedTypeHead is None: + self.NamedTypeTail = node + self.NamedTypeHead = node + else: + node.Next = None + if self.NamedTypeHead is None: + self.NamedTypeHead = node + else: + self.NamedTypeTail.Next = node + self.NamedTypeTail = node + self.NamedTypeCount += 1 + + def _is_type_defined_in_module(self, name: str) -> int: + """检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义""" + if self is None or name is None: + return 0 + cur: rawptr[NamedTypeNode] = self.NamedTypeHead + cnt_tdm: int = 0 + while cur is not None: + # 步数守卫:同上,防 NamedTypeHead 链表成环无限遍历 + cnt_tdm += 1 + if cnt_tdm > 100000: + stdio.printf("[TDM-LOOP] NamedTypeHead 链表疑似成环, name=%s, 强制终止\n", + name if name is not None else "(null)") + stdlib.exit(1) + if cur.Ty is not None: + existing_name: str = get_struct_name(cur.Ty) + if existing_name is not None: + # 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp。 + if existing_name[0] == name[0] and string.strcmp(existing_name, name) == 0: + return 1 + cur = cur.Next + return 0 + + def ensure_opaque_for_type(self, pool: memhub.MemBuddy*, + ty: rawptr[LLVMType]): + """为类型中的跨模块结构体引用添加 opaque 声明 + + 当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, + 如果该名称未在模块中定义,则添加 opaque 声明。 + """ + _scan_type_for_cross_module_refs(pool, self, ty) + + # ---- 打印 ---- + def PrintModule(self, buf: str, size: sizet, + pool: memhub.MemBuddy*, mode: int): + """将模块序列化为 MLIR(llvm 方言) 文本写入 buf + + 输出骨架: module { <全局> <函数> } + MLIR 没有 stub/text 二分,用注释标明模式映射: + OUTPUT_FULL → 全量;OUTPUT_STUB → 仅全局/函数声明;OUTPUT_TEXT → 仅带体函数。 + target triple / datalayout 不属于 MLIR 模块,记录但不输出(见注释与 README)。 + """ + if self is None or buf is None or size == 0: return + + _append_cstr(buf, size, "module {\n") + + # 模式说明注释(MLIR 无 stub/text 二分) + if mode == OUTPUT_STUB: + _append_cstr(buf, size, " // MLIR-STUB: 仅全局声明与函数声明\n") + elif mode == OUTPUT_TEXT: + _append_cstr(buf, size, " // MLIR-TEXT: 仅带体函数与含初值全局\n") + # target triple / datalayout:MLIR 模块不携带,由 mlir-translate/llc 阶段提供 + if self.TargetTriple is not None or self.DataLayout is not None: + _append_cstr(buf, size, + " // target triple / datalayout 由 mlir-translate / llc 阶段提供\n") + + # 行缩进辅助缓冲(模块成员统一缩进 2 空格) + tmp: str = pool.alloc(65536) + + # 全局变量(MLIR 无独立类型定义行:命名结构体类型在使用处内联, + # 故这里不再输出 NamedTypeHead 类型定义,仅登记供类型文本回查) + gv: rawptr[GlobalVariable] = self.GlobalHead + gv_steps: sizet = 0 + while gv is not None: + gv_steps += 1 + if gv_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: module globals(GlobalCount=%zu,dump 终止)\n", + self.GlobalCount) + stdlib.exit(1) + if mode == OUTPUT_TEXT and gv.Initializer is None: + # text 模式跳过无初值的全局变量(纯声明) + gv = gv.Next + continue + if tmp is not None: + tmp[0] = '\0' + if mode == OUTPUT_STUB: + _MlirGlobalLine(tmp, 65536, pool, gv, 1) + else: + _MlirGlobalLine(tmp, 65536, pool, gv, 0) + _MlirAppendIndented(buf, size, tmp, 2, pool) + gv = gv.Next + + # 遍历函数(按模式过滤 declare/define) + func: rawptr[Function] = self.FuncHead + func_steps: sizet = 0 + while func is not None: + func_steps += 1 + if func_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: module funcs print(FuncCount=%zu,dump 终止)\n", + self.FuncCount) + stdlib.exit(1) + emit: int = 0 + if mode == OUTPUT_STUB: + if func.IsDeclared == 1: + emit = 1 + elif mode == OUTPUT_TEXT: + if func.IsDeclared == 0: + emit = 1 + else: + emit = 1 + if emit != 0 and tmp is not None: + tmp[0] = '\0' + FunctionPrint(tmp, 65536, func, pool) + _MlirAppendIndented(buf, size, tmp, 2, pool) + func = func.Next + + _append_cstr(buf, size, "}\n") + + +# ============================================================ +# 工厂函数 +# ============================================================ +def new_module(pool: memhub.MemBuddy*, name: str) -> rawptr[LLVMModule]: + """创建一个模块""" + # 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable) + ptr: rawptr[LLVMModule] = 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) + Align(4) = 72 字节 +GV_SIZE: t.CDefine = 72 + +# NamedTypeNode 硬编码大小: Next(8) + Ty(8) + IsPacked(8) = 24 字节 +NAMED_TYPE_NODE_SIZE: t.CDefine = 24 + +def new_global_variable(pool: memhub.MemBuddy*, + name: str, ty: rawptr[LLVMType]) -> rawptr[GlobalVariable]: + """创建一个全局变量""" + ptr: rawptr[GlobalVariable] = 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 + ptr.Align = 0 + return ptr + + +# ============================================================ +# 链表操作(嵌入式 Head/Tail/Count,O(1) 追加) +# ============================================================ +def module_add_function(mod: rawptr[LLVMModule], func: rawptr[Function]): + mod.add_function(func) + + +def module_get_func_head(mod: rawptr[LLVMModule]) -> rawptr[Function]: + """获取模块函数链表头(跨模块访问器,绕 stub 字段访问陷阱)""" + if mod is None: + return None + return mod.FuncHead + + +def module_add_global(mod: rawptr[LLVMModule], gv: rawptr[GlobalVariable]): + mod.add_global(gv) + + +def module_set_target(mod: rawptr[LLVMModule], triple: str): + mod.set_target(triple) + + +def module_set_datalayout(mod: rawptr[LLVMModule], layout: str): + mod.set_datalayout(layout) + + +# ============================================================ +# 命名结构体类型管理 +# ============================================================ + +# ============================================================ +# _is_opaque_struct - 检查类型是否是 opaque 结构体 +# +# opaque 结构体特征: Struct 类型,fcount == -1(哨兵标记,跨模块前向 +# 声明,仅名称无字段定义)。通过 Struct(pool, None, -1, name) 创建, +# IR 输出为 %"name" = type opaque。注意区分空结构体(fcount==0, +# fields==None,无字段类)——它是合法完整定义(= type {},可 alloca)。 +# 用于在 module_add_named_type 中区分 opaque 声明和完整定义, +# 确保 opaque 声明插入链表头部(在使用之前声明)。 +# +# Returns: 1=是 opaque / 0=否 +# ============================================================ +def _is_opaque_struct(ty: rawptr[LLVMType]) -> int: + """检查类型是否是 opaque 结构体 + + opaque 是跨模块前向声明(仅名称无字段定义),由 + _scan_type_for_cross_module_refs 创建,fcount=-1 哨兵标记。 + 空结构体(fcount==0, fields==None,无字段类)是合法完整定义 + (LLVM {} 类型,可 alloca),必须与 opaque 区分——此前混淆导致 + 空类结构体被输出为 "= type opaque",alloca 报 Cannot allocate + unsized type。 + """ + if ty is None: + return 0 + match ty: + case LLVMType.Struct(fields, fcount, name): + # opaque: fcount == -1(哨兵) + if fcount < 0: + return 1 + return 0 + case _: + return 0 + + +def module_add_named_type(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, + ty: rawptr[LLVMType]): + mod.add_named_type(pool, ty) + + +def module_set_named_type_packed(mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, + ty: rawptr[LLVMType], is_packed: int): + """按名称设置命名结构体的 packed 标记(输出 %"name" = type <{...}>)。 + + 编译器解析 @c.Attribute(t.attr.packed) 后调用,使 llc 按 packed 布局 + (无字段填充)计算字段偏移/GEP。ty 为命名 Struct 类型(按 get_struct_name + 定位已注册节点);未找到则静默跳过(opaque/跨模块 stub 场景无布局需求)。 + """ + if mod is None or ty is None: + return + name: str = get_struct_name(ty) + if name is None: + return + cur: rawptr[NamedTypeNode] = mod.NamedTypeHead + cnt_p: int = 0 + while cur is not None: + cnt_p += 1 + if cnt_p > 100000: + return + if cur.Ty is not None: + existing_name: str = get_struct_name(cur.Ty) + if existing_name is not None and string.strcmp(existing_name, name) == 0: + cur.IsPacked = is_packed + return + cur = cur.Next + + +# ============================================================ +# 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: rawptr[LLVMModule], name: str) -> int: + return mod._is_type_defined_in_module(name) + + +def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy*, + mod: rawptr[LLVMModule], + ty: rawptr[LLVMType], + depth: int = 0): + """递归扫描类型树,为跨模块结构体引用添加 opaque 声明""" + if ty is None or mod is None or pool is None: + return + # 深度守卫:自引用结构体(链表/树节点,如 Node{...; Ptr(Node) next}) + # 会无限递归栈溢出,与其他递归(TypePrint/DeepCopyType)一致设上限 + if depth >= 100: + return + match ty: + case LLVMType.Ptr(pointee): + if pointee is not None: + match pointee: + case LLVMType.Struct(sfields, sfcount, sname): + if sname is not None: + # 检查是否为跨模块引用(名称包含 '.') + if string.strchr(sname, 46) is not None: + # 检查是否已在模块中定义 + if _is_type_defined_in_module(mod, sname) == 0: + # 创建 opaque 类型并添加到模块 + # fcount=-1 哨兵标记 opaque(区别于空结构体 {}, + # 后者 fcount==0 是合法完整定义,可 alloca) + opaque_ty: rawptr[LLVMType] = Struct(pool, None, -1, sname) + if opaque_ty is not None: + module_add_named_type(mod, pool, opaque_ty) + # 递归扫描结构体字段中的跨模块引用 + # 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用 + if sfields is not None: + fld: rawptr[ParamNode] = sfields + fld_steps: sizet = 0 + while fld is not None: + fld_steps += 1 + if fld_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: struct fields(sname=%s,dump 终止)\n", + sname) + stdlib.exit(1) + if fld.Ty is not None: + _scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1) + fld = fld.Next + case _: + _scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1) + case LLVMType.Struct(sfields2, sfcount2, sname2): + # 顶层结构体(非指针):递归扫描字段 + if sfields2 is not None: + fld2: rawptr[ParamNode] = sfields2 + fld2_steps: sizet = 0 + while fld2 is not None: + fld2_steps += 1 + if fld2_steps > IR_DUMP_CHAIN_LIMIT: + stdio.printf("[IR-DUMP] 链表成环: struct fields2(sname=%s,dump 终止)\n", + sname2) + stdlib.exit(1) + if fld2.Ty is not None: + _scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1) + fld2 = fld2.Next + case LLVMType.Array(elem_ty, acount): + if elem_ty is not None: + _scan_type_for_cross_module_refs(pool, mod, elem_ty, depth + 1) + case _: + pass + + +def module_ensure_opaque_for_type(mod: rawptr[LLVMModule], + pool: memhub.MemBuddy*, + ty: rawptr[LLVMType]): + mod.ensure_opaque_for_type(pool, ty) + + +# ============================================================ +# 全局变量属性设置 +# ============================================================ +def global_set_constant(gv: rawptr[GlobalVariable], is_const: int): + """设置全局变量是否为常量""" + if gv is None: return + gv.IsConstant = is_const + + +def global_set_linkage(gv: rawptr[GlobalVariable], linkage: str): + """设置链接类型 (private/internal/external/... )""" + if gv is None: return + gv.Linkage = linkage + + +def global_set_unnamed_addr(gv: rawptr[GlobalVariable], level: int): + """设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)""" + if gv is None: return + gv.UnnamedAddr = level + + +def global_set_section(gv: rawptr[GlobalVariable], section: str): + """设置段名""" + 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 带初值) + +# dump 哨兵:IR 链表遍历步数上限(成环检测,fail-fast)。 +# 任何一条链(函数/全局/命名类型/结构体字段)的 Next 被越界写破坏成环时, +# 遍历会无限循环导致 tpv.exe 挂起(builtins.vp dump 卡死根因排查)。 +# 超过上限即打印链表名并 exit(1),把"卡死"变成"确定性报错定位" +# (对齐 memhub.self_check 的 max_steps 哲学)。 +IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000 + + +# ============================================================ +# LLVMModulePrint: 将模块序列化为 .ll 文本 +# +# mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码 +# ============================================================ +def LLVMModulePrint(buf: str, size: sizet, + mod: rawptr[LLVMModule], pool: memhub.MemBuddy*, + mode: int): + mod.PrintModule(buf, size, pool, mode) + + +# ============================================================ +# 全局变量渲染(MLIR) +# +# 形态: +# llvm.mlir.global internal constant @.str("hello") : !llvm.array<6 x i8> +# llvm.mlir.global @counter(0 : i32) : i32 +# llvm.mlir.global external @x : i32 +# linkage/constant/unnamed_addr/section 映射为对应关键字/属性。 +# v1 支持的初值文本形态: 整数字面量、浮点、null、zeroinitializer、cstring、 +# 整型数组;其它形态(尤其 { … } 结构体/vtable 初始化串)**响亮报错**。 +# ============================================================ +def _MlirGlobalLine(buf: str, size: sizet, + pool: memhub.MemBuddy*, gv: rawptr[GlobalVariable], + stub: int): + """渲染一条 llvm.mlir.global(stub=1 时输出 external 声明形态)""" + if gv is None: + return + _append_cstr(buf, size, "llvm.mlir.global ") + # 链接类型 + if stub != 0: + _append_cstr(buf, size, "external ") + elif gv.Linkage is not None: + # external + 初值是非法 IR,去掉 external + 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, " ") + if stub == 0: + # 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(MLIR 中非 constant 无需关键字) + if gv.IsConstant == 1: + _append_cstr(buf, size, "constant ") + # 名字 + _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) + # 初值 + if stub == 0 and gv.Initializer is not None: + _append_cstr(buf, size, "(") + _MlirGlobalInit(buf, size, pool, gv) + _append_cstr(buf, size, ")") + # 属性(section / alignment 按属性字典输出;形态未经 mlir-opt 验证,见 README) + if stub == 0 and (gv.Section is not None or gv.Align > 0): + _append_cstr(buf, size, " {") + if gv.Section is not None: + _append_cstr(buf, size, "section = \"") + _append_cstr(buf, size, gv.Section) + _append_cstr(buf, size, "\"") + if gv.Align > 0: + _append_cstr(buf, size, ", ") + if gv.Align > 0: + ab: str = pool.alloc(48) + if ab is not None: + viperlib.snprintf(ab, 48, "alignment = %d : i64", gv.Align) + _append_cstr(buf, size, ab) + _append_cstr(buf, size, "}") + # 类型 + _append_cstr(buf, size, " : ") + ty_buf: str = pool.alloc(512) + if ty_buf is not None: + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, gv.Ty, pool) + _append_cstr(buf, size, ty_buf) + _append_cstr(buf, size, "\n") + + +def _MlirGlobalInit(buf: str, size: sizet, + pool: memhub.MemBuddy*, gv: rawptr[GlobalVariable]): + """渲染全局初值(MLIR attribute 文本)""" + x: str = gv.Initializer + if x is None: + return + if x[0] == 'c' and x[1] == '"': + _MlirCStringToMlir(buf, size, x, pool) + return + if x[0] == '"': + # 已是字符串字面量 + _append_cstr(buf, size, x) + return + if x[0] == '[': + # 整型/浮点数组: [i8 1, i8 2] → [1 : i8, 2 : i8] + # ⚠ 实测 mlir-opt 22.1.8: + # - `dense<[...] : !llvm.array<…>>` **非法**("elements literal must be + # a shaped type":dense 只接受 builtin shaped 类型 tensor/vector); + # - `[1, 2]`(元素无类型注解)仅在元素类型等于默认 i64 时可用; + # - 正确形态 = 数组属性直接放进 value 括号,元素带 `值 : 类型` 注解。 + # 全局类型由 _MlirGlobalLine 在括号后统一输出,此处不再重复。 + _MlirArrayDenseAt(buf, size, x, pool) + return + if string.strcmp(x, "null") == 0 or string.strcmp(x, "zeroinitializer") == 0: + _append_cstr(buf, size, "zeroinitializer") + return + if x[0] == '@': + # 符号引用初值 + _append_cstr(buf, size, x) + return + c0: int = x[0] + if c0 == '-' or (c0 >= '0' and c0 <= '9'): + # 整数/浮点字面量: "<文本> : " + _append_cstr(buf, size, x) + _append_cstr(buf, size, " : ") + ty_buf: str = pool.alloc(512) + if ty_buf is not None: + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, gv.Ty, pool) + _append_cstr(buf, size, ty_buf) + return + # { … } 结构体/vtable 初始化串等:响亮报错,绝不静默输出错误 MLIR + MlirFail("MLIR 渲染: 全局初值形态 v1 不支持(结构体/vtable 初始化串需改用结构化初始化)") + + +def _MlirCStringToMlir(buf: str, size: sizet, src: str, pool: memhub.MemBuddy*): + """c"hello\\00" → "hello\\00"(仅去掉 'c' 前缀,转义内容原样保留) + + ⚠ 实测 mlir-opt 22.1.8:`llvm.mlir.global` 的字符串属性**长度必须等于** + 声明的 i8 数组长度,否则报 + "op requires an i8 array type of the length equal to that of the string attribute"。 + TPV 的字符串常量类型含尾随 NUL([N+1 x i8]),故属性里**必须保留 \\00**。 + 绝不能改为剥掉类型里的 NUL —— 那会丢掉 C 字符串终止符、破坏 ABI。 + """ + p: str = src + 1 # 跳过 'c',指向 '"' + if p[0] != '"': + MlirFail("MLIR 渲染: 全局 c 字符串初值形态非法") + _append_cstr(buf, size, p) + + +def _MlirArrayDenseAt(buf: str, size: sizet, src: str, + pool: memhub.MemBuddy*) -> str: + """LLVM 数组字面量 → MLIR dense 内容(嵌套递归),返回新游标""" + if src is None or src[0] != '[': + MlirFail("MLIR 渲染: 全局数组初值形态 v1 不支持") + p: str = src + 1 + _append_cstr(buf, size, "[") + n: int = 0 + g: int = 0 + while p[0] != '\0': + g += 1 + if g > 4096: + MlirFail("MLIR 渲染: 全局数组元素过多") + p = _mlir_ws(p) + if p[0] == ']': + p = p + 1 + break + if p[0] == '\0': + break + if n > 0: + _append_cstr(buf, size, ", ") + if p[0] == '[': + p = _MlirArrayDenseAt(buf, size, p, pool) + else: + tb: str = pool.alloc(512) + if tb is None: + MlirFail("MLIR 渲染: 数组元素类型缓冲分配失败") + p = _mlir_read_type(p, tb, 512) + p = _mlir_ws(p) + vb: str = pool.alloc(512) + if vb is None: + MlirFail("MLIR 渲染: 数组元素值缓冲分配失败") + p = _mlir_read_value(p, vb, 512) + _append_cstr(buf, size, vb) + # 元素必须带类型注解:MLIR 数组属性元素默认按 i64 解释, + # i8/i32/指针等元素不注解会与全局类型不匹配(实测通过形态: + # `[1 : i8, 2 : i8] : !llvm.array<2 x i8>`)。 + _append_cstr(buf, size, " : ") + mtb: str = pool.alloc(512) + if mtb is None: + MlirFail("MLIR 渲染: 数组元素 MLIR 类型缓冲分配失败") + mtb[0] = '\0' + MlirTypeText(mtb, 512, tb, pool) + _append_cstr(buf, size, mtb) + n += 1 + p = _mlir_ws(p) + if p[0] == ',': + p = p + 1 + _append_cstr(buf, size, "]") + return p + + +def _MlirAppendIndented(dst: str, dst_size: sizet, src: str, + indent: int, pool: memhub.MemBuddy*): + """把 src 的每一行前加 indent 个空格后追加到 dst(模块成员缩进)""" + if dst is None or src is None: + return + cb: str = pool.alloc(2) + if cb is None: + _append_cstr(dst, dst_size, src) + return + p: str = src + while p[0] != '\0': + i: int = 0 + while i < indent: + _append_cstr(dst, dst_size, " ") + i += 1 + while p[0] != '\0' and p[0] != '\n': + cb[0] = p[0] + cb[1] = '\0' + _append_cstr(dst, dst_size, cb) + p = p + 1 + if p[0] == '\n': + _append_cstr(dst, dst_size, "\n") + p = p + 1 + + +# ============================================================ +# 内部辅助 +# ============================================================ +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: sizet = 0 + +def _append_cstr(dst: str, dst_size: sizet, src: str): + """将 C 字符串 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos + if dst is None or src is None: return + dlen: sizet = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + # 缓存一致性校验:缓存结尾必须仍是当前文本末端(末端 NUL 且前一字符非 NUL)。 + # 多个模块(__module/__function 各自一份 _append_cstr 缓存)轮流写同一 buf、 + # 或 pool 复用地址残留旧内容时,缓存 pos 会过期 → 追加落到首个 NUL 之后, + # 内容"看不见"(LLvmLiteTest Test5/9 模块函数链为空根因)。校验失败回退 + # strlen 重定位;正常热路径不受影响(仍 O(1))。 + if dlen == 0: + if dst[0] != '\0': + dlen = string.strlen(dst) + elif dst[dlen] != '\0' or dst[dlen - 1] == '\0': + dlen = string.strlen(dst) + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen + if remain <= 0: return + i: sizet = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + _g_last_pos = dlen + i \ No newline at end of file diff --git a/mlirlite/__types.vp b/mlirlite/__types.vp new file mode 100644 index 0000000..f8332fc --- /dev/null +++ b/mlirlite/__types.vp @@ -0,0 +1,1045 @@ +import t, c +from stdint import * +import viperlib +import string +import memhub +import stdio +import stdlib +from linkedlist import GSListNode + + +# ============================================================ +# ParamNode: 函数参数类型链表节点 +# 继承 GSListNode[ParamNode] 获取强类型 Next: ParamNode|CPtr +# Ty 用 rawptr[t\.CVoid] 前向引用,使用时转型为 (rawptr[LLVMType]) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class ParamNode(GSListNode[ParamNode]): + Ty: rawptr # LLVMType*(前向引用,使用时转型) + + +# ============================================================ +# LLVMType: LLVM IR 类型系统(t.REnum tagged union) +# +# 变体少、无通用字段、操作通过 match 分派 —— 契合 REnum 模型。 +# 布局: { i32 __tag, } +# ============================================================ +class LLVMType(t.REnum): + # 整数类型: i1/i8/i16/i32/i64 + class Int: + Bits: int + + # 指针类型: pointee* + class Ptr: + Pointee: rawptr[LLVMType] + + # 函数类型: ret (params) + class Func: + Ret: rawptr[LLVMType] + Params: rawptr[ParamNode] + PCount: int + + # 数组类型: [N x elem_ty] + class Array: + ElemTy: rawptr[LLVMType] + Count: int + + # 结构体类型: {ty1, ty2, ...} 或 %"name" = type {ty1, ty2, ...} + # Fields 复用 ParamNode 链表(ParamNode.Ty 即字段类型) + # Name 非 None 时为命名结构体,TypePrint 输出 %"name" 而非 {...} + class Struct: + Fields: rawptr[ParamNode] + FCount: int + Name: str + + # 浮点类型: half/float/double/fp128 + class Float: + Bits: int # 16=half, 32=float, 64=double, 128=fp128 + + # 无值类型 + class Void: + pass + + # 标签类型 + class Label: + pass + + # 元数据类型 + class Metadata: + pass + + +# ============================================================ +# 内部分配辅助 +# ============================================================ +def _new_type(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + """从 mpool 分配一个零初始化的 LLVMType""" + ptr: rawptr[LLVMType] = pool.alloc(LLVMType.__sizeof__()) + if ptr: + string.memset(ptr, 0, LLVMType.__sizeof__()) + return ptr + + +# ============================================================ +# 类型工厂函数 +# ============================================================ +def Int1(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(1)) + return ptr + + +def Int8(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(8)) + return ptr + + +def Int16(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(16)) + return ptr + + +def Int32(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(32)) + return ptr + + +def Int64(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(64)) + return ptr + + +def Ptr(pool: memhub.MemBuddy*, pointee: rawptr[LLVMType]) -> rawptr[LLVMType]: + """创建指针类型 Ptr(pointee) + + LLVM IR 中 **不允许 void* 指针**("pointers to void are invalid"), + 因此: + - 若 pointee == None → 回退 Ptr(Int8) + - 若 pointee 是 LLVMType.Void → 回退 Ptr(Int8)(对应 C 的 void* 语法在 TPV 中写 Ptr(t.CVoid)) + 其他类型正常构造 Ptr(pointee)。 + """ + # ============== 前置校验: 拦截 Void / None pointee(void* 非法)============== + safe_pointee: rawptr[LLVMType] = pointee + if safe_pointee is None: + safe_pointee = Int8(pool) + else: + match safe_pointee: + case LLVMType.Void(): + safe_pointee = Int8(pool) + case _: + pass + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Ptr(safe_pointee)) + return ptr + + +def Func(pool: memhub.MemBuddy*, ret: rawptr[LLVMType], + params: rawptr[ParamNode], count: int) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Func(ret, params, count)) + return ptr + + +def Void(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Void()) + return ptr + + +def Array(pool: memhub.MemBuddy*, elem_ty: rawptr[LLVMType], + count: int) -> rawptr[LLVMType]: + """创建数组类型 [count x elem_ty]""" + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Array(elem_ty, count)) + return ptr + + +def Struct(pool: memhub.MemBuddy*, fields: rawptr[ParamNode], + fcount: int, name: str) -> rawptr[LLVMType]: + """创建结构体类型 {ty1, ty2, ...} + + fields 为 ParamNode 链表头,fcount 为字段数量。 + name 非 None 时为命名结构体(如 "sha1.ClassName"),TypePrint 输出 %"name"。 + name 为 None 时为匿名结构体,TypePrint 输出 {ty1, ty2, ...}。 + """ + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Struct(fields, fcount, name)) + return ptr + + +def Half(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + """创建半精度浮点类型 half (16-bit)""" + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(16)) + return ptr + + +def Float(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + """创建单精度浮点类型 float (32-bit)""" + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(32)) + return ptr + + +def Double(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + """创建双精度浮点类型 double (64-bit)""" + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(64)) + return ptr + + +def FP128(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + """创建四精度浮点类型 fp128 (128-bit)""" + ptr: rawptr[LLVMType] = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(128)) + return ptr + + +def Label(pool: memhub.MemBuddy*) -> rawptr[LLVMType]: + """创建标签类型 label""" + ptr: rawptr[LLVMType] = _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*, ty: rawptr[LLVMType]) -> rawptr[ParamNode]: + """创建一个参数节点,Ty 设为给定类型指针""" + ptr: rawptr[ParamNode] = 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: rawptr[ParamNode], tail: rawptr[ParamNode], + node: rawptr[ParamNode]) -> rawptr[ParamNode]: + """将 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: rawptr[ParamNode]) -> rawptr[LLVMType]: + """获取参数节点的类型""" + if node is None: + return None + return (rawptr[LLVMType])(node.Ty) + + +def paramnode_get_next(node: rawptr[ParamNode]) -> rawptr[ParamNode]: + """获取链表下一个参数节点""" + if node is None: + return None + return node.Next + + +def paramnode_set_ty(node: rawptr[ParamNode], ty: rawptr[LLVMType]): + """设置参数节点的类型""" + if node is None: + return + node.Ty = ty + + +def paramnode_set_next(node: rawptr[ParamNode], nxt: rawptr[ParamNode]): + """设置链表下一个参数节点""" + if node is None: + return + node.Next = nxt + + +# ============================================================ +# LLVMTypeCore: 类型创建核心,封装 pool 避免重复传参 +# +# 用法: +# core: rawptr[LLVMTypeCore] = LLVMTypeCore(pool) +# ty_i32: rawptr[LLVMType] = core.Int32() +# ty_ptr: rawptr[LLVMType] = core.Ptr(ty_i32) +# ty_void: rawptr[LLVMType] = core.Void() +# ============================================================ +@t.NoVTable +class LLVMTypeCore: + """类型创建核心,封装 pool 避免每次创建类型都传 pool""" + Pool: memhub.MemBuddy* + + def __init__(self, pool: memhub.MemBuddy*): + self.Pool = pool + + def Int1(self) -> rawptr[LLVMType]: + return Int1(self.Pool) + + def Int8(self) -> rawptr[LLVMType]: + return Int8(self.Pool) + + def Int16(self) -> rawptr[LLVMType]: + return Int16(self.Pool) + + def Int32(self) -> rawptr[LLVMType]: + return Int32(self.Pool) + + def Int64(self) -> rawptr[LLVMType]: + return Int64(self.Pool) + + def Ptr(self, pointee: rawptr[LLVMType]) -> rawptr[LLVMType]: + return Ptr(self.Pool, pointee) + + def Func(self, ret: rawptr[LLVMType], params: rawptr[ParamNode], + count: int) -> rawptr[LLVMType]: + return Func(self.Pool, ret, params, count) + + def Array(self, elem_ty: rawptr[LLVMType], count: int) -> rawptr[LLVMType]: + return Array(self.Pool, elem_ty, count) + + def Struct(self, fields: rawptr[ParamNode], fcount: int, + name: str = None) -> rawptr[LLVMType]: + return Struct(self.Pool, fields, fcount, name) + + def Void(self) -> rawptr[LLVMType]: + return Void(self.Pool) + + def Half(self) -> rawptr[LLVMType]: + return Half(self.Pool) + + def Float(self) -> rawptr[LLVMType]: + return Float(self.Pool) + + def Double(self) -> rawptr[LLVMType]: + return Double(self.Pool) + + def FP128(self) -> rawptr[LLVMType]: + return FP128(self.Pool) + + def Label(self) -> rawptr[LLVMType]: + return Label(self.Pool) + + def NewParamNode(self, ty: rawptr[LLVMType]) -> rawptr[ParamNode]: + return new_param_node(self.Pool, ty) + + # ---- 链表辅助 ---- + def ParamListAppend(self, head: rawptr[ParamNode], tail: rawptr[ParamNode], + node: rawptr[ParamNode]) -> rawptr[ParamNode]: + """将 node 追加到参数/字段链表,返回新的 tail""" + return param_list_append(head, tail, node) + + # ---- 打印 ---- + def PrintType(self, buf: str, size: sizet, ty: rawptr[LLVMType]): + TypePrint(buf, size, ty, self.Pool) + + +# ============================================================ +# MlirFail - MLIR 渲染期"响亮报错" +# +# 本库的设计红线:v1 不支持的形态绝不静默输出错误 MLIR, +# 一律打印定位信息后立即终止(对齐 llvmlite 的 [IR-DUMP]/[IR-FAIL] fail-fast 风格)。 +# ============================================================ +def MlirFail(msg: str): + """打印 MLIR 渲染错误并立即终止""" + if msg is None: + stdio.printf("[MLIR-FAIL] (no message)\n") + else: + stdio.printf("[MLIR-FAIL] %s\n", msg) + stdlib.exit(1) + + +# ============================================================ +# 说明:本库**不需要**命名结构体类型登记表。 +# +# builders 未改,其内嵌类型一律经 _type_str → TypePrint 生成,因此中间指令 +# 文本里出现的结构体类型已经是完整的 MLIR 内联形态(!llvm.struct<(…)>), +# 不含 %"name" 这种"只有名字"的形态;指针也统一收敛为 !llvm.ptr。 +# 若出现 %"name"(手工构造的中间文本),MlirTypeText 会响亮报错。 +# ============================================================ + + +# ============================================================ +# TypePrint: 将 LLVMType 序列化为 MLIR(llvm 方言) 类型文本 +# +# 渲染规则: +# Int1/8/16/32/64 -> i1/i8/i16/i32/i64 +# Half/Float/Double/FP128 -> f16/f32/f64/f128 +# Ptr(_) -> !llvm.ptr(不透明指针;pointee 只保留在内部模型里) +# Array(elem,N) -> !llvm.array +# Struct(fields,N,name) -> !llvm.struct<(f0, f1, …)>;空 -> !llvm.struct<()> +# Func(ret,params) -> !llvm.func +# Void -> none(仅必须打印时;函数返回值位置省略) +# Label / Metadata -> v1 不支持,响亮报错(MLIR 无 label/metadata 类型) +# +# 注意:由于 builders 未改、内嵌类型一律经 _type_str → TypePrint, +# **中间指令文本里的类型已经是 MLIR 文本**(如 `load i32, !llvm.ptr %p`)。 +# pool 用于递归打印子类型时分配临时缓冲区。 +# ============================================================ +def TypePrint(buf: str, size: sizet, + ty: rawptr[LLVMType], pool: memhub.MemBuddy*): + """将类型 ty 序列化为 MLIR 类型文本写入 buf(容量 size) + + pool 用于递归打印子类型时分配临时缓冲区。 + """ + if buf is None or size == 0: + return + buf[0] = '\0' + _MlirTypePrintDepth(buf, size, ty, pool, 0) + + +# ============================================================ +# 类型文本 → MLIR 类型文本转换 +# +# 中间指令文本里的类型是 LLVM 语法(i8*、[4 x i32]、{i32, i8*}、%"name"), +# 需要转换成 MLIR 语法(!llvm.ptr、!llvm.array<4 x i32>、 +# !llvm.struct<(i32, !llvm.ptr)>、!llvm.struct<(…)>)后才能写进 op 行。 +# ============================================================ +def MlirTypeText(dst: str, dstsz: sizet, src: str, pool: memhub.MemBuddy*): + """把 LLVM 语法类型文本转换为 MLIR 类型文本(追加到 dst)""" + if dst is None or dstsz == 0 or src is None: + return + _MlirTypeAppend(dst, dstsz, src, pool, 0) + + +def MlirTypeTextIsPointer(src: str) -> int: + """判断类型文本是否为指针,返回 1/0 + + MLIR 形态:`!llvm.ptr`(builders 内嵌类型的实际形态); + 兼容 LLVM 形态:末字符为 `*`(手工构造中间文本时可能出现)。 + """ + if src is None: + return 0 + p: str = _MlirSkipWs(src) + lt: sizet = _MlirTextLen(p) + if lt == 0: + return 0 + if lt == 9 and string.strncmp(p, "!llvm.ptr", 9) == 0: + return 1 + if p[lt - 1] == '*': + return 1 + return 0 + + +def _MlirSkipWs(p: str) -> str: + """跳过空白(空格/制表/换行)""" + if p is None: + return None + while p[0] == ' ' or p[0] == '\t' or p[0] == '\n' or p[0] == '\r': + p = p + 1 + return p + + +def _MlirTextLen(p: str) -> sizet: + """去除尾部空白后的文本长度""" + if p is None: + return 0 + n: sizet = string.strlen(p) + while n > 0: + ch: int = p[n - 1] + if ch == 32 or ch == 9 or ch == 10 or ch == 13: + n -= 1 + else: + break + return n + + +def _MlirAppendN(dst: str, dstsz: sizet, src: str, n: sizet): + """把 src 的前 n 字节追加到 dst""" + if dst is None or src is None or n == 0: + return + dl: sizet = string.strlen(dst) + if dl >= dstsz: + return + rem: sizet = dstsz - dl + i: sizet = 0 + while i < n and i + 1 < rem: + dst[dl + i] = src[i] + i += 1 + dst[dl + i] = '\0' + + +def _MlirAllDigits(p: str, lt: sizet, start: sizet) -> int: + """判断 p[start..lt) 是否全为十进制数字(且非空),返回 1/0""" + if p is None or start >= lt: + return 0 + i: sizet = start + while i < lt: + ch: int = p[i] + if ch < 48 or ch > 57: + return 0 + i += 1 + return 1 + + +def _MlirTypeAppend(dst: str, dstsz: sizet, src: str, pool: memhub.MemBuddy*, + depth: int): + """LLVM 类型文本 → MLIR 类型文本(递归实现,追加写 dst)""" + if dst is None or dstsz == 0 or src is None: + return + if depth > 64: + MlirFail("类型文本嵌套过深(> 64 层)") + p: str = _MlirSkipWs(src) + lt: sizet = _MlirTextLen(p) + if lt == 0: + MlirFail("空类型文本无法转换为 MLIR 类型") + # ---- MLIR 文本直通(builders 内嵌类型已由 TypePrint 渲染为 MLIR 形态)---- + if p[0] == '!': + _MlirAppendN(dst, dstsz, p, lt) + return + if lt == 4 and string.strncmp(p, "none", 4) == 0: + _strappend(dst, dstsz, "none") + return + # ---- 标量 ---- + if lt == 4 and string.strncmp(p, "void", 4) == 0: + _strappend(dst, dstsz, "none") + return + if lt == 4 and string.strncmp(p, "half", 4) == 0: + _strappend(dst, dstsz, "f16") + return + if lt == 5 and string.strncmp(p, "float", 5) == 0: + _strappend(dst, dstsz, "f32") + return + if lt == 6 and string.strncmp(p, "double", 6) == 0: + _strappend(dst, dstsz, "f64") + return + if lt == 5 and string.strncmp(p, "fp128", 5) == 0: + _strappend(dst, dstsz, "f128") + return + # ---- 不透明指针:任何 '*'(含 * *、结构体指针、命名结构体指针)统一 !llvm.ptr ---- + if p[lt - 1] == '*': + _strappend(dst, dstsz, "!llvm.ptr") + return + # ---- 整数 ---- + if p[0] == 'i' and _MlirAllDigits(p, lt, 1) != 0: + _MlirAppendN(dst, dstsz, p, lt) + return + # ---- 数组 ---- + if p[0] == '[' and p[lt - 1] == ']': + _MlirArrayText(dst, dstsz, p, lt, pool, depth) + return + # ---- 结构体 ---- + if p[0] == '{' and p[lt - 1] == '}': + _MlirStructText(dst, dstsz, p, lt, pool, depth) + return + # ---- 命名结构体 ---- + if p[0] == '%': + _MlirNamedStructText(dst, dstsz, p, lt, pool, depth) + return + # ---- 函数类型: ret (p0, p1) ---- + fp: sizet = _MlirFindFuncParen(p, lt) + if fp != 0: + _MlirFuncText(dst, dstsz, p, lt, fp, pool, depth) + return + # 报文带上原始类型文本(截断到 lt),便于一次定位: + # 若谓词/记号被误当类型,会直接看到 'sgt' 这类内容。 + emb: str = pool.alloc(lt + 1) + if emb is not None: + string.strncpy(emb, p, lt) + emb[lt] = '\0' + emsg: str = pool.alloc(lt + 128) + if emsg is not None: + viperlib.snprintf(emsg, lt + 128, "无法转换为 MLIR 类型文本(v1 未覆盖该形态):'%s'", emb) + MlirFail(emsg) + MlirFail("无法转换为 MLIR 类型文本(v1 未覆盖该形态)") + + +def _MlirArrayText(dst: str, dstsz: sizet, p: str, lt: sizet, + pool: memhub.MemBuddy*, depth: int): + """[N x elem] → !llvm.array""" + inner: str = p + 1 + innerlen: sizet = lt - 2 + xpos: sizet = 0 + d: int = 0 + i: sizet = 0 + while i < innerlen: + ch: int = inner[i] + if ch == '[' or ch == '{' or ch == '(': + d += 1 + elif ch == ']' or ch == '}' or ch == ')': + d -= 1 + elif ch == ' ' and d == 0: + if inner[i + 1] == 'x' and inner[i + 2] == ' ': + xpos = i + i = innerlen + continue + i += 1 + if xpos == 0: + MlirFail("数组类型文本缺少 'N x elem' 形态") + elem_len: sizet = innerlen - xpos - 3 + eb: str = pool.alloc(elem_len + 1) + if eb is None: + MlirFail("数组元素类型缓冲分配失败") + string.strncpy(eb, inner + xpos + 3, elem_len) + eb[elem_len] = '\0' + _strappend(dst, dstsz, "!llvm.array<") + _MlirAppendN(dst, dstsz, inner, xpos) + _strappend(dst, dstsz, " x ") + _MlirTypeAppend(dst, dstsz, eb, pool, depth + 1) + _strappend(dst, dstsz, ">") + + +def _MlirStructText(dst: str, dstsz: sizet, p: str, lt: sizet, + pool: memhub.MemBuddy*, depth: int): + """{f0, f1, …} → !llvm.struct<(f0, f1, …)>;空 → !llvm.struct<()>""" + inner: str = p + 1 + innerlen: sizet = lt - 2 + _strappend(dst, dstsz, "!llvm.struct<(") + if innerlen > 0: + start: sizet = 0 + d: int = 0 + idx: int = 0 + i: sizet = 0 + while i <= innerlen: + ch: int = 0 + if i < innerlen: + ch = inner[i] + if i == innerlen or (ch == ',' and d == 0): + flen: sizet = i - start + # 去掉字段尾随空白 + while flen > 1 and inner[start + flen - 1] == ' ': + flen -= 1 + fb: str = pool.alloc(flen + 1) + if fb is None: + MlirFail("结构体字段类型缓冲分配失败") + string.strncpy(fb, inner + start, flen) + fb[flen] = '\0' + if idx > 0: + _strappend(dst, dstsz, ", ") + _MlirTypeAppend(dst, dstsz, fb, pool, depth + 1) + idx += 1 + start = i + 1 + i += 1 + continue + if ch == '[' or ch == '{' or ch == '(': + d += 1 + elif ch == ']' or ch == '}' or ch == ')': + d -= 1 + i += 1 + if idx == 0: + _MlirTypeAppend(dst, dstsz, inner, pool, depth + 1) + _strappend(dst, dstsz, ")>") + + +def _MlirNamedStructText(dst: str, dstsz: sizet, p: str, lt: sizet, + pool: memhub.MemBuddy*, depth: int): + """命名结构体类型文本(形如 %name):v1 不支持 → 响亮报错 + + builders 内嵌类型由 TypePrint 内联渲染为 !llvm.struct<(…)>, + 中间指令文本不应再出现"只有名字"的结构体类型。 + """ + MlirFail("MLIR 渲染: 命名结构体类型文本 v1 不支持(应使用内联 !llvm.struct<(…)>)") + + +def _MlirFindFuncParen(p: str, lt: sizet) -> sizet: + """定位函数类型文本中顶层 ' (' 的下标,找不到返回 0""" + d: int = 0 + i: sizet = 0 + while i + 1 < lt: + ch: int = p[i] + if ch == '[' or ch == '{' or ch == '(': + d += 1 + elif ch == ']' or ch == '}' or ch == ')': + d -= 1 + elif ch == ' ' and d == 0 and p[i + 1] == '(': + return i + i += 1 + return 0 + + +def _MlirFuncText(dst: str, dstsz: sizet, p: str, lt: sizet, fp: sizet, + pool: memhub.MemBuddy*, depth: int): + """ret (p0, p1) → !llvm.func""" + ret_len: sizet = fp + rbuf: str = pool.alloc(ret_len + 1) + if rbuf is None: + MlirFail("函数返回类型缓冲分配失败") + string.strncpy(rbuf, p, ret_len) + rbuf[ret_len] = '\0' + _strappend(dst, dstsz, "!llvm.func<") + _MlirTypeAppend(dst, dstsz, rbuf, pool, depth + 1) + _strappend(dst, dstsz, " (") + # 参数区:fp+2 .. lt-1(末字符 ')') + if lt >= fp + 3: + inner: str = p + fp + 2 + innerlen: sizet = lt - fp - 3 + start: sizet = 0 + d: int = 0 + idx: int = 0 + i: sizet = 0 + while i <= innerlen: + ch: int = 0 + if i < innerlen: + ch = inner[i] + if i == innerlen or (ch == ',' and d == 0): + flen: sizet = i - start + while flen > 1 and inner[start + flen - 1] == ' ': + flen -= 1 + fb: str = pool.alloc(flen + 1) + if fb is None: + MlirFail("函数参数类型缓冲分配失败") + string.strncpy(fb, inner + start, flen) + fb[flen] = '\0' + if idx > 0: + _strappend(dst, dstsz, ", ") + _MlirTypeAppend(dst, dstsz, fb, pool, depth + 1) + idx += 1 + start = i + 1 + i += 1 + continue + if ch == '[' or ch == '{' or ch == '(': + d += 1 + elif ch == ']' or ch == '}' or ch == ')': + d -= 1 + i += 1 + _strappend(dst, dstsz, ")>") + + +# 递归深度上限:悬空/自引用的 LLVMType 树(reset 后内存被复用)会导致 +# Ptr(pointee)/Struct(fields)/Func(params) 无限递归,每次递归分配临时缓冲 +# 造成 OOM。超过 100 层即停止打印。 +TYPEPRINT_MAX_DEPTH: t.CDefine = 100 + +def _MlirTypePrintDepth(buf: str, size: sizet, + ty: rawptr[LLVMType], pool: memhub.MemBuddy*, + depth: int): + """带递归深度上限的 MLIR 类型打印内部实现(覆盖式写入 buf)""" + if ty is None or buf is None or size == 0: + return + buf[0] = '\0' + if depth >= TYPEPRINT_MAX_DEPTH: + viperlib.snprintf(buf, size, "...") + return + match ty: + case LLVMType.Int(bits): + viperlib.snprintf(buf, size, "i%d", bits) + case LLVMType.Float(bits): + if bits == 16: + viperlib.snprintf(buf, size, "%s", "f16") + elif bits == 32: + viperlib.snprintf(buf, size, "%s", "f32") + elif bits == 64: + viperlib.snprintf(buf, size, "%s", "f64") + elif bits == 128: + viperlib.snprintf(buf, size, "%s", "f128") + else: + MlirFail("TypePrint: 不支持的浮点位宽") + case LLVMType.Ptr(pointee): + # MLIR 使用不透明指针:任何 pointee 一律渲染 !llvm.ptr。 + # pointee 仅保留在内部模型中,供 op 渲染(如 load 的结果类型)使用。 + viperlib.snprintf(buf, size, "%s", "!llvm.ptr") + case LLVMType.Array(elem_ty, count): + viperlib.snprintf(buf, size, "!llvm.array<%d x ", count) + tmp: str = pool.alloc(512) + if tmp is not None: + _MlirTypePrintDepth(tmp, 512, elem_ty, pool, depth + 1) + _strappend(buf, size, tmp) + _strappend(buf, size, ">") + case LLVMType.Struct(fields, fcount, name): + # MLIR 侧不区分匿名/命名:一律渲染字段列表 + # (指针场景已由 Ptr → !llvm.ptr 收敛,名字不参与渲染) + _MlirStructFields(buf, size, fields, pool, depth) + case LLVMType.Func(ret, params, count): + # MLIR 函数类型:!llvm.func + # 与文本→文本的 _MlirFuncText 保持同形外壳。 + # 两个实现要点: + # 1) _MlirTypePrintDepth 是**覆盖式**写入,ret 必须先落临时缓冲再 + # _strappend 进 buf,否则先写的外壳会被 ret 的打印清掉; + # 2) 不用 viperlib.snprintf 拼"字面量 + 类型文本",统一走 _strappend + # (与本文件 _MlirStructFields / _MlirFuncText 同款写法)。 + _strappend(buf, size, "!llvm.func<") + rfb: str = pool.alloc(512) + if rfb is not None: + _MlirTypePrintDepth(rfb, 512, ret, pool, depth + 1) + _strappend(buf, size, rfb) + _strappend(buf, size, " (") + cur2: rawptr[ParamNode] = params + first2: int = 1 + _pc2: int = 0 + tmp3: str = pool.alloc(512) + while cur2 is not None: + # 悬空保护:参数链若被 reset 回收后内容复用,可能成环无限循环 + _pc2 += 1 + if _pc2 > 200: + _strappend(buf, size, "...") + break + if first2 == 0: + _strappend(buf, size, ", ") + if tmp3 is not None: + _MlirTypePrintDepth(tmp3, 512, cur2.Ty, pool, depth + 1) + _strappend(buf, size, tmp3) + cur2 = cur2.Next + first2 = 0 + _strappend(buf, size, ")>") + case LLVMType.Void(): + viperlib.snprintf(buf, size, "%s", "none") + case LLVMType.Label(): + # MLIR 无 label 类型(块用 ^name 引用),v1 不支持 → 响亮报错 + MlirFail("TypePrint(Label): MLIR 无 label 类型,v1 不支持") + case LLVMType.Metadata(): + MlirFail("TypePrint(Metadata): MLIR llvm 方言 v1 不支持 metadata 类型") + case _: + MlirFail("TypePrint: 未知 LLVMType 变体") + + +def _MlirStructFields(buf: str, size: sizet, + fields: rawptr[ParamNode], pool: memhub.MemBuddy*, + depth: int): + """渲染 !llvm.struct<(f0, f1, …)>(覆盖式写入 buf)""" + buf[0] = '\0' + _strappend(buf, size, "!llvm.struct<(") + cur: rawptr[ParamNode] = fields + first: int = 1 + fidx: int = 0 + tmp: str = pool.alloc(512) + while cur is not None: + # 悬空保护:ParamNode 链成环时限制打印字段数,防止 OOM + if fidx >= 200: + _strappend(buf, size, "...") + break + if first == 0: + _strappend(buf, size, ", ") + if tmp is not None and cur.Ty is not None: + _MlirTypePrintDepth(tmp, 512, cur.Ty, pool, depth + 1) + _strappend(buf, size, tmp) + cur = cur.Next + first = 0 + fidx += 1 + _strappend(buf, size, ")>") + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _strappend(dst: str, dst_size: sizet, src: str): + """将 src 追加到 dst 末尾(不超过 dst_size)""" + if dst is None or src is None: return + dlen: sizet = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到 GB 外 + if dlen >= dst_size: + return + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen + if remain <= 0: return + i: sizet = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# PrintStructDefinition - 命名结构体类型定义行(MLIR 侧为空操作) +# +# LLVM IR 需要 "%"name" = type { ty1, ty2, ... } 这样的独立类型定义行; +# MLIR(llvm 方言) 没有独立类型定义语法,结构体类型在使用处内联书写 +# (!llvm.struct<(…)>),指针一律 !llvm.ptr(不透明)。 +# 因此本函数在 MLIR 后端输出空串 —— 保留同名同签名的 API 只为与 llvmlite 同形, +# 调用方(LLVMModulePrint)无需为此分叉。 +# ============================================================ +def PrintStructDefinition(buf: str, size: sizet, + ty: rawptr[LLVMType], pool: memhub.MemBuddy*, + packed: int = 0): + """MLIR 侧无类型定义行:写入空串(保留 API 同形)""" + if buf is None or size == 0: + return + buf[0] = '\0' + + +# ============================================================ +# get_struct_name - 获取命名结构体的名称 +# +# 返回 Name 字段(如 "sha1.ClassName"),非 Struct 类型或匿名 Struct 返回 None +# 供 module_add_named_type 检查是否为命名结构体及去重 +# ============================================================ +def get_struct_name(ty: rawptr[LLVMType]) -> str: + """获取命名结构体的名称,非命名结构体返回 None""" + if ty is None: + return None + match ty: + case LLVMType.Struct(fields, fcount, name): + return name + case _: + return None + + +def get_struct_fields(ty: rawptr[LLVMType]) -> rawptr[ParamNode]: + """获取结构体的字段链表(供跨模块重建 Struct 类型用)""" + if ty is None: + return None + match ty: + case LLVMType.Struct(fields, fcount, name): + return fields + case _: + return None + + +def get_struct_fcount(ty: rawptr[LLVMType]) -> int: + """获取结构体的字段数量(供跨模块重建 Struct 类型用)""" + if ty is None: + return 0 + match ty: + case LLVMType.Struct(fields, fcount, name): + return fcount + case _: + return 0 + + +# ============================================================ +# DeepCopyType - 深拷贝 LLVMType 到 stdlib 区(跨文件 reset 存活) +# +# 背景: 1b 阶段(mark1 之后)新注册的结构体(泛型特化类等),其 +# struct_ty 是 pool 分配的 LLVMType,所在文件翻译完 reset_to(mark1) +# 后指针悬空。_struct_table 中的 entry.Ty 指向它,后续文件遍历 +# _struct_table(find_struct_by_type/lookup_field 等)时解引用悬空 +# 指针导致崩溃(0xC0000005)。 +# +# 本函数递归拷贝整棵 LLVMType 树到 stdlib(含 ParamNode 字段链和 +# 字符串名),保证 entry.Ty 跨文件永久存活。 +# +# 注意: 自引用类型(如 Value 含 Ptr(Value) 字段)会导致无限递归, +# 用深度上限防护(超过即返回浅拷贝副本,后续不再递归)。 +# ============================================================ +DEEPCOPY_MAX_DEPTH: t.CDefine = 64 + +def DeepCopyType(pool: memhub.MemBuddy*, + ty: rawptr[LLVMType]) -> rawptr[LLVMType]: + """深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None""" + return _DeepCopyDepth(pool, ty, 0) + + +def _DeepCopyDepth(pool: memhub.MemBuddy*, + ty: rawptr[LLVMType], depth: int) -> rawptr[LLVMType]: + """带深度上限的深拷贝实现 + + 分配源用传入的 pool 参数(调用方决定):传主 pool 为瞬时拷贝 + (随 mark/reset 回收),传永久 pool(CompilerFactory.get_perm_pool()) + 为跨 mark 持久拷贝(代替 stdlib.malloc,buddy 分配更快)。 + """ + if ty is None: + return None + new_ty: rawptr[LLVMType] = (rawptr[LLVMType])(pool.alloc(LLVMType.__sizeof__())) + if new_ty is None: + return None + string.memset(new_ty, 0, LLVMType.__sizeof__()) + if depth >= DEEPCOPY_MAX_DEPTH: + # 深度超限:浅拷贝 tag 后停止递归(复制当前变体但不深拷子类型) + match ty: + case LLVMType.Int(bits): + c.DerefAs(new_ty, LLVMType.Int(bits)) + case LLVMType.Float(bits): + c.DerefAs(new_ty, LLVMType.Float(bits)) + case LLVMType.Void(): + c.DerefAs(new_ty, LLVMType.Void()) + case LLVMType.Label(): + c.DerefAs(new_ty, LLVMType.Label()) + case LLVMType.Metadata(): + c.DerefAs(new_ty, LLVMType.Metadata()) + case _: + c.DerefAs(new_ty, LLVMType.Void()) + return new_ty + match ty: + case LLVMType.Int(bits): + c.DerefAs(new_ty, LLVMType.Int(bits)) + case LLVMType.Float(bits): + c.DerefAs(new_ty, LLVMType.Float(bits)) + case LLVMType.Void(): + c.DerefAs(new_ty, LLVMType.Void()) + case LLVMType.Label(): + c.DerefAs(new_ty, LLVMType.Label()) + case LLVMType.Metadata(): + c.DerefAs(new_ty, LLVMType.Metadata()) + case LLVMType.Ptr(pointee): + c.DerefAs(new_ty, LLVMType.Ptr(_DeepCopyDepth(pool, pointee, depth + 1))) + case LLVMType.Array(elem_ty, count): + c.DerefAs(new_ty, LLVMType.Array(_DeepCopyDepth(pool, elem_ty, depth + 1), count)) + case LLVMType.Func(ret, params, pcount): + c.DerefAs(new_ty, LLVMType.Func( + _DeepCopyDepth(pool, ret, depth + 1), + _DeepCopyParamChain(pool, params, depth + 1), pcount)) + case LLVMType.Struct(fields, fcount, name): + c.DerefAs(new_ty, LLVMType.Struct( + _DeepCopyParamChain(pool, fields, depth + 1), + fcount, _DeepCopyStr(pool, name))) + case _: + # new_ty 由 pool(MemBuddy)分配,必须用 pool.free(buddy 回收) + # 而非 stdlib.free(仅回收 malloc 块)——后者对 arena 内指针调用 + # 会损坏堆(0xC0000374 / ASan bad-free)。 + pool.free(new_ty) + return None + return new_ty + + +def _DeepCopyParamChain(pool: memhub.MemBuddy*, + head: rawptr[ParamNode], depth: int) -> rawptr[ParamNode]: + """深拷贝 ParamNode 链表到 stdlib""" + if head is None: + return None + first: rawptr[ParamNode] = None + prev: rawptr[ParamNode] = None + cur: rawptr[ParamNode] = head + guard: int = 0 + while cur is not None: + guard += 1 + if guard > 512: + break + node: rawptr[ParamNode] = (rawptr[ParamNode])(pool.alloc(PNODE_SIZE)) + if node is None: + break + string.memset(node, 0, PNODE_SIZE) + node.Ty = _DeepCopyDepth(pool, paramnode_get_ty(cur), depth + 1) + node.Next = None + if first is None: + first = node + if prev is not None: + prev.Next = node + prev = node + cur = paramnode_get_next(cur) + return first + + +def _DeepCopyStr(pool: memhub.MemBuddy*, s: str) -> str: + """深拷贝字符串到 stdlib""" + if s is None: + return None + slen: sizet = string.strlen(s) + copy: str = pool.alloc(slen + 1) + if copy is None: + return None + string.strcpy(copy, s) + return copy + + + + diff --git a/mlirlite/__values.vp b/mlirlite/__values.vp new file mode 100644 index 0000000..0ef134e --- /dev/null +++ b/mlirlite/__values.vp @@ -0,0 +1,239 @@ +import t, c +from stdint import * +import string +import viperlib +import stdio +import memhub +from linkedlist import GSListNode +from .__types import LLVMType, TypePrint + + +# ============================================================ +# Value: SSA 值表示 +# +# 表示一个 LLVM IR 值:SSA 临时值(%0/%result)或常量字面量(42/0)。 +# 每个值有类型指针、名字、是否常量标志。 +# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr(值池链表) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class Value(GSListNode[Value]): + Ty: rawptr[LLVMType] # 值的类型 + Name: str # SSA 名("%0"/"%result")或常量文本("42"/"1.5e+00") + IsConst: int # 1=常量字面量, 0=SSA 临时值 + IntVal: int64 # 整数常量值(当 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*) -> rawptr[Value]: + """从 mpool 分配一个零初始化的 Value""" + ptr: rawptr[Value] = pool.alloc(VALUE_SIZE) + if ptr: + string.memset(ptr, 0, VALUE_SIZE) + return ptr + + +def ConstInt(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], + val: int64, name: str) -> rawptr[Value]: + """创建整数常量值 + + 参数: + ty: 整数类型(Int1/Int8/Int32/Int64) + val: 整数值 + name: 常量文本(如 "42"),由调用方提供 + """ + v: rawptr[Value] = 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*, ty: rawptr[LLVMType], + name: str) -> rawptr[Value]: + """创建 null 指针常量""" + v: rawptr[Value] = 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*, ty: rawptr[LLVMType]) -> rawptr[Value]: + """创建 zeroinitializer 常量(零初始化聚合类型:结构体/数组)""" + v: rawptr[Value] = 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*, ty: rawptr[LLVMType], + val: t.CDouble) -> rawptr[Value]: + """创建浮点常量值 + + 参数: + ty: 浮点类型(Half/Float/Double/FP128) + val: 浮点数值 + 名字自动格式化为 LLVM IR 科学计数法文本(如 "1.500000e+00")。 + """ + v: rawptr[Value] = new_value(pool) + if v is None: return None + v.Ty = ty + v.IsConst = 1 + v.FloatVal = val + v.IntVal = 0 + # 格式化名字: LLVM IR 浮点常量文本用十六进制位模式(0x%016llx / 0x%08x) + # 原因: %.17e 科学计数法文本经 llc 解析对部分值产生 ±1 ulp 误差 + # (如 "1.10000000000000000e+01" 解析为 11.000000000000002 而非 11.0, + # 导致 add_scalar[0]==11 等浮点常量比较失败)。位模式无精度损失。 + # 原 %e 默认 6 位小数还会截断精度(3.1415926535897931 -> 3.141593e+00)。 + # 用 CRT stdio.snprintf: viperlib 自实现 %g 有小数位反转 bug。 + f_bits: int = 64 + match ty: + case LLVMType.Float(ftb): + f_bits = ftb + fv_bits: t.CUInt64T = 0 + c.Load(c.Addr(fv_bits), c.Addr(val)) + name_buf: str = pool.alloc(32) + if name_buf is not None: + if f_bits == 32: + stdio.snprintf(name_buf, 32, "0x%08x", t.CUInt32T(fv_bits)) + else: + stdio.snprintf(name_buf, 32, "0x%016llx", fv_bits) + v.Name = name_buf + return v + + +def SSAValue(pool: memhub.MemBuddy*, ty: rawptr[LLVMType], + name: str) -> rawptr[Value]: + """创建 SSA 临时值 + + 参数: + ty: 值类型 + name: SSA 名(如 "%0"/"%result"),由调用方提供 + """ + v: rawptr[Value] = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 0 + v.IntVal = 0 + return v + + +# ============================================================ +# ValuePrint: 将值序列化为 MLIR 文本(仅供诊断) +# +# 渲染规则: +# SSA 值 -> "%0"(MLIR 中操作数就是 SSA 名,不附带类型) +# 常量 -> "42 : i32"(MLIR attribute 文本形态) +# +# 注意: 指令渲染**不得**依赖本函数。函数体的 op 渲染走 __function.vp 的 +# 操作数解析路径(常量必须先物化为 llvm.mlir.constant/zero/addressof op)。 +# ============================================================ +def ValuePrint(buf: str, size: sizet, + val: rawptr[Value], pool: memhub.MemBuddy*): + """将值 val 序列化为 MLIR 文本写入 buf + + pool 用于复杂类型(Array/Struct/Func)递归打印时分配临时缓冲区。 + """ + if val is None or buf is None or size == 0: + return + buf[0] = '\0' + if val.Name is None: + return + if val.IsConst == 0: + # SSA 值: 只输出 SSA 名 + _append_str(buf, size, val.Name) + return + # 常量: "<常量文本> : " + _append_str(buf, size, val.Name) + _append_str(buf, size, " : ") + tp: str = pool.alloc(256) + if tp is not None: + TypePrint(tp, 256, val.Ty, pool) + _append_str(buf, size, tp) + + +# ============================================================ +# Value 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 Value 的 stub 类型(字段不足或偏移错误), +# 导致 TransPyC 静默跳过字段访问(不生成 GEP,不报错)。 +# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问所有字段。 +# ============================================================ +def value_get_ty(val: rawptr[Value]) -> rawptr[LLVMType]: + """获取值的类型""" + if val is None: + return None + return val.Ty + + +def value_get_next(val: rawptr[Value]) -> rawptr[Value]: + """获取链表下一个值""" + if val is None: + return None + return val.Next + + +def value_set_ty(val: rawptr[Value], ty: rawptr[LLVMType]): + """设置值的类型""" + if val is None: + return + val.Ty = ty + + +def value_set_next(val: rawptr[Value], nxt: rawptr[Value]): + """设置链表下一个值""" + if val is None: + return + val.Next = nxt + + +def value_set_name(val: rawptr[Value], name: str): + """设置值的名字""" + if val is None: + return + val.Name = name + + +def value_set_isconst(val: rawptr[Value], is_const: int): + """设置是否为常量""" + if val is None: + return + val.IsConst = is_const + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_str(dst: str, dst_size: sizet, src: str): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: sizet = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen + if remain <= 0: return + i: sizet = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' diff --git a/mlirlite/__verify.vp b/mlirlite/__verify.vp new file mode 100644 index 0000000..af31793 --- /dev/null +++ b/mlirlite/__verify.vp @@ -0,0 +1,434 @@ +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 验证器 +# +# 与 llvmlite **逐名同形、语义相同**:验证的是**结构化内部模型 + 中间指令 +# 文本**(builders 生成的 %N 定义/使用、块终止、phi 位置), +# 与 MLIR 渲染文本无关 —— MLIR 的合法性由 mlir-opt/mlir-translate 负责。 +# +# 检查项: +# 1. 块终止: 每个基本块必须以终止指令结尾 (ret/br/switch/unreachable) +# 2. SSA 唯一性: 每个 %name 只能被定义一次 +# 3. 未定义引用: 所有 %name 使用必须有对应定义 +# 4. Phi 位置: phi 指令只能出现在块首(非 phi 指令之前) +# ============================================================ + +# 错误码 +VERIFY_OK: t.CDefine = 0 +VERIFY_ERR_NO_TERMINATOR: t.CDefine = 1 +VERIFY_ERR_DUPLICATE_DEF: t.CDefine = 2 +VERIFY_ERR_UNDEFINED_USE: t.CDefine = 3 +VERIFY_ERR_PHI_NOT_FIRST: t.CDefine = 4 + + +# ============================================================ +# NameEntry: 已定义 SSA 名条目(链表节点) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class NameEntry(GSListNode[NameEntry]): + Name: str # SSA 名(如 "%0"/"%result") + + +# ============================================================ +# VerifyResult: 验证结果 +# ============================================================ +class VerifyResult: + ErrorCount: int # 错误总数 + WarningCount: int # 警告总数 + ErrorCode: int # 第一个错误码 + ErrorBuf: str # 错误消息缓冲区 + ErrorBufSize: sizet # 缓冲区大小 + + +# ============================================================ +# 辅助函数 +# ============================================================ +def _new_verify_result(pool: memhub.MemBuddy*, + buf_size: sizet) -> rawptr[VerifyResult]: + """创建验证结果对象""" + ptr: rawptr[VerifyResult] = 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: str = 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: rawptr[VerifyResult], code: int, msg: str): + """记录一个错误""" + 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") + + +# _append_cstr 写入位置缓存(性能优化:同一缓冲连续追加时 O(1) 定位, +# 避免每次 strlen(dst) 从头扫描导致的 O(n²) —— IR 序列化热点)。 +# 缓冲切换(dst 不同)或缓冲被重置(dst[0]=0 且 pos>0)时自动回退 strlen。 +_g_last_dst: t.CUInt64T = 0 +_g_last_pos: sizet = 0 + +def _append_cstr(dst: str, dst_size: sizet, src: str): + """将 src 追加到 dst 末尾""" + global _g_last_dst, _g_last_pos + if dst is None or src is None: return + dlen: sizet = 0 + if _g_last_dst == t.CUInt64T(dst): + dlen = _g_last_pos + # 缓冲被重置(调用方 buf[0]=0 后复用同一地址)→ 回到头部 + if dlen > 0 and dst[0] == '\0': + dlen = 0 + # 缓存一致性校验(同 __module/__function 版):缓存 pos 过期会追加到首个 NUL + # 之后使内容不可见,校验失败回退 strlen;正常热路径仍 O(1)。 + if dlen == 0: + if dst[0] != '\0': + dlen = string.strlen(dst) + elif dst[dlen] != '\0' or dst[dlen - 1] == '\0': + dlen = string.strlen(dst) + else: + dlen = string.strlen(dst) + _g_last_dst = t.CUInt64T(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: sizet = string.strlen(src) + remain: sizet = dst_size - dlen + if remain <= 0: return + i: sizet = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + _g_last_pos = dlen + i + + +# ============================================================ +# SSA 名表操作 +# ============================================================ +def _new_name_table(pool: memhub.MemBuddy*) -> rawptr[GSList[NameEntry]]: + """创建空名表""" + gsl: rawptr[GSList[NameEntry]] = 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: rawptr[GSList[NameEntry]], + pool: memhub.MemBuddy*, + name: str) -> int: + """添加名到表。返回 1=重复, 0=成功添加""" + if table is None or name is None: return 0 + # 检查重复 + cur: rawptr[NameEntry] = table.Head + while cur is not None: + if string.strcmp(cur.Name, name) == 0: + return 1 + cur = cur.Next + # 添加新条目 + entry: rawptr[NameEntry] = 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: rawptr[GSList[NameEntry]], + name: str) -> int: + """检查名是否在表中。返回 1=存在, 0=不存在""" + if table is None or name is None: return 0 + cur: rawptr[NameEntry] = 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: char) -> int: + """判断字符是否为 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*, + text: str) -> str: + """从定义行提取被定义的 SSA 名。 + + 定义行格式: "% = " + 返回分配的 NUL 结尾名串(如 "%0"),或 None 若非定义行。 + """ + if text is None: return None + if text[0] != '%': return None + # 扫描 " = " 模式 + i: int = 1 + while text[i] != '\0': + if text[i] == ' ' and text[i + 1] == '=' and text[i + 2] == ' ': + # 找到 " = " 在位置 i + name_len: int = i + name: str = pool.alloc(name_len + 1) + if name is None: return None + j: int = 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: str) -> int: + """判断文本是否为终止指令""" + 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: str) -> int: + """判断文本是否为 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: rawptr[GSList[NameEntry]], + text: str, + def_name: str) -> int: + """检查行中所有 SSA 名使用是否已定义。 + + 跳过 def_name(定义位置的名字)。 + 返回未定义使用数量。 + """ + if text is None: return 0 + i: int = 0 + undef_count: int = 0 + while text[i] != '\0': + if text[i] == '%': + # 提取名 + name_start: int = i + i += 1 + while text[i] != '\0' and _is_char_name(text[i]) == 1: + i += 1 + name_len: int = 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: str, start: int, length: int, + table: rawptr[GSList[NameEntry]]) -> int: + """检查 text[start:start+length] 是否匹配名表中的某个条目。 + 返回 1=匹配, 0=不匹配 + """ + if table is None: return 0 + cur: rawptr[NameEntry] = 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: str, start: int, length: int, + target: str) -> int: + """检查 text[start:start+length] 是否等于 target 字符串。 + 返回 1=匹配, 0=不匹配 + """ + if text is None or target is None: return 0 + # 检查 target 长度 + target_len: sizet = string.strlen(target) + if target_len != length: return 0 + i: sizet = 0 + while i < length: + if text[start + i] != target[i]: return 0 + i += 1 + return 1 + + +# ============================================================ +# 主验证函数 +# ============================================================ +def verify_function(pool: memhub.MemBuddy*, + func: rawptr[Function], + result: rawptr[VerifyResult]) -> int: + """验证函数的 SSA 正确性。 + + 参数: + pool: 内存池 + func: 要验证的函数 + result: 验证结果(调用前需用 _new_verify_result 创建) + + 返回: 错误数量(0 = 验证通过) + """ + if func is None or result is None: return 1 + + # 创建名表 + name_table: rawptr[GSList[NameEntry]] = _new_name_table(pool) + if name_table is None: return 1 + + # 1. 将函数参数加入名表(参数是已定义的) + params: rawptr[GSList[Param]] = func.Params + param: rawptr[Param] = None + if params is not None: + param = 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 的合法引用目标) + blocks: rawptr[GSList[BasicBlock]] = func.Blocks + blk_iter: rawptr[BasicBlock] = None + if blocks is not None: + blk_iter = blocks.Head + while blk_iter is not None: + if blk_iter.Name is not None: + blk_name_len: sizet = string.strlen(blk_iter.Name) + blk_ref: str = pool.alloc(blk_name_len + 2) + if blk_ref is not None: + # 构造 "%" 字符串 + blk_ref[0] = '%' + k: sizet = 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: rawptr[BasicBlock] = None + if blocks is not None: + blk = blocks.Head + while blk is not None: + # 检查终止指令 + if blk.IsTerminated == 0: + # 进一步检查最后一行是否为终止指令 + has_term: int = 0 + line_check: rawptr[Line] = None + if blk.Lines is not None: + lines_check: rawptr[GSList[Line]] = blk.Lines + line_check = lines_check.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: str = "" + if blk.Name is not None: + blk_name = blk.Name + err_buf: str = 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: int = 0 + line: rawptr[Line] = None + if blk.Lines is not None: + lines: rawptr[GSList[Line]] = blk.Lines + line = lines.Head + while line is not None: + if line.Buf is not None: + text: str = line.Buf + + # 检查 phi 位置 + if _is_phi(text) == 1: + if seen_non_phi == 1: + phi_err: str = 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: str = _extract_def_name(pool, text) + if def_name is not None: + # 检查重复定义 + dup: int = _name_table_add(name_table, pool, def_name) + if dup == 1: + dup_err: str = 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: int = _check_uses_in_line(name_table, text, def_name) + if undef > 0: + use_err: str = 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*, mod: rawptr[LLVMModule], result: rawptr[VerifyResult]) -> int: + """验证模块中所有函数的 SSA 正确性。 + + 返回: 错误总数 + """ + if mod is None or result is None: return 1 + func: rawptr[Function] = mod.FuncHead + while func is not None: + if func.IsDeclared == 0: + # 只验证有函数体的定义,跳过声明 + verify_function(pool, func, result) + func = func.Next + return result.ErrorCount diff --git a/numpy/__init__.vp b/numpy/__init__.vp index ab16a29..7837b46 100644 --- a/numpy/__init__.vp +++ b/numpy/__init__.vp @@ -1,7 +1,7 @@ from stdint import * import stdlib import string -import vipermath +import math import stdio import t, c import memhub @@ -14,12 +14,9 @@ MAX_NDIM: t.CDefine = 4 float64: t.CTypedef = t.CDouble float32: t.CTypedef = t.CFloat -int64: t.CTypedef = t.CLong -int32: t.CTypedef = t.CInt -uint8: t.CTypedef = t.CUnsignedChar -pi: t.CDefine = 3.14159265358979323846 -e: t.CDefine = 2.71828182845904523536 +define pi = 3.14159265358979323846 +define e = 2.71828182845904523536 # ============================================================ # ndarray - generic n-dimensional array (PEP 695) @@ -30,17 +27,16 @@ e: t.CDefine = 2.71828182845904523536 # # Default usage: ndarray[t.CDouble] for floating point. # ============================================================ -@t.Object class ndarray[T]: data: T | t.CPtr - shape: t.CArray[t.CSizeT, MAX_NDIM] - strides: t.CArray[t.CSizeT, MAX_NDIM] + shape: t.CArray[sizet, MAX_NDIM] + strides: t.CArray[sizet, MAX_NDIM] ndim: t.CInt - size: t.CSizeT + size: sizet owns_data: t.CInt pool: rawptr[memhub.MemManager] - def __new__(self, pool: rawptr[memhub.MemManager], n: t.CSizeT): + def __new__(self, pool: rawptr[memhub.MemManager], n: sizet): self.pool = pool self.data = pool.alloc(n * T.__sizeof__()) if self.data: @@ -54,7 +50,7 @@ class ndarray[T]: def __add__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: result.data[i] = self.data[i] + other.data[i] i += 1 @@ -63,7 +59,7 @@ class ndarray[T]: def __sub__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: result.data[i] = self.data[i] - other.data[i] i += 1 @@ -72,7 +68,7 @@ class ndarray[T]: def __mul__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: result.data[i] = self.data[i] * other.data[i] i += 1 @@ -81,7 +77,7 @@ class ndarray[T]: def __truediv__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: if other.data[i] != T(0): result.data[i] = self.data[i] / other.data[i] @@ -93,10 +89,10 @@ class ndarray[T]: def __floordiv__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: if other.data[i] != T(0): - result.data[i] = vipermath.floor(self.data[i] / other.data[i]) + result.data[i] = math.floor(self.data[i] / other.data[i]) else: result.data[i] = T(0) i += 1 @@ -105,10 +101,10 @@ class ndarray[T]: def __mod__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: if other.data[i] != T(0): - result.data[i] = vipermath.fmod(self.data[i], other.data[i]) + result.data[i] = math.fmod(self.data[i], other.data[i]) else: result.data[i] = T(0) i += 1 @@ -117,7 +113,7 @@ class ndarray[T]: def __neg__(self) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: result.data[i] = -self.data[i] i += 1 @@ -127,10 +123,10 @@ class ndarray[T]: if self.ndim > 0: return t.CInt(self.shape[0]) return 0 - def at2d(self, row: t.CSizeT, col: t.CSizeT) -> T: + def at2d(self, row: sizet, col: sizet) -> T: return self.data[row * self.shape[1] + col] - def set2d(self, row: t.CSizeT, col: t.CSizeT, val: T): + def set2d(self, row: sizet, col: sizet, val: T): self.data[row * self.shape[1] + col] = val def delete(self): @@ -140,7 +136,7 @@ class ndarray[T]: self.pool.free(self) def fill(self, val: T): - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: self.data[i] = val i += 1 @@ -152,10 +148,10 @@ class ndarray[T]: return result def reshape(self, new_shape: INTPTR, new_ndim: t.CInt) -> ndarray[T] | t.CPtr: - new_size: t.CSizeT = 1 + new_size: sizet = 1 i: t.CInt = 0 for i in range(new_ndim): - new_size *= t.CSizeT(new_shape[i]) + new_size *= sizet(new_shape[i]) if new_size != self.size: return None result: ndarray[T] | t.CPtr = _alloc_ndarray(self.pool) if not result: return None @@ -165,13 +161,13 @@ class ndarray[T]: result.size = self.size result.owns_data = 0 for i in range(new_ndim): - result.shape[i] = t.CSizeT(new_shape[i]) + result.shape[i] = sizet(new_shape[i]) _compute_strides(result) return result def sum(self) -> T: s: T = T(0) - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: s += self.data[i] i += 1 @@ -184,7 +180,7 @@ class ndarray[T]: def min(self) -> T: if self.size == 0: return T(0) m: T = self.data[0] - i: t.CSizeT = 1 + i: sizet = 1 while i < self.size: if self.data[i] < m: m = self.data[i] i += 1 @@ -193,7 +189,7 @@ class ndarray[T]: def max(self) -> T: if self.size == 0: return T(0) m: T = self.data[0] - i: t.CSizeT = 1 + i: sizet = 1 while i < self.size: if self.data[i] > m: m = self.data[i] i += 1 @@ -203,7 +199,7 @@ class ndarray[T]: if self.size == 0: return -1 m: T = self.data[0] idx: t.CInt = 0 - i: t.CSizeT = 1 + i: sizet = 1 while i < self.size: if self.data[i] > m: m = self.data[i] @@ -215,7 +211,7 @@ class ndarray[T]: if self.size == 0: return -1 m: T = self.data[0] idx: t.CInt = 0 - i: t.CSizeT = 1 + i: sizet = 1 while i < self.size: if self.data[i] < m: m = self.data[i] @@ -225,8 +221,8 @@ class ndarray[T]: def dot(self, other: ndarray[T] | t.CPtr) -> T: s: T = T(0) - n: t.CSizeT = self.size if (self.size < other.size) else other.size - i: t.CSizeT = 0 + n: sizet = self.size if (self.size < other.size) else other.size + i: sizet = 0 while i < n: s += self.data[i] * other.data[i] i += 1 @@ -234,17 +230,17 @@ class ndarray[T]: def T(self) -> ndarray[T] | t.CPtr: if self.ndim != 2: return None - rows: t.CSizeT = self.shape[0] - cols: t.CSizeT = self.shape[1] + rows: sizet = self.shape[0] + cols: sizet = self.shape[1] result: ndarray[T] | t.CPtr = empty2d(self.pool, rows, cols) if not result: return None # Swap shape for transpose result.shape[0] = cols result.shape[1] = rows _compute_strides(result) - i: t.CSizeT = 0 + i: sizet = 0 while i < rows: - j: t.CSizeT = 0 + j: sizet = 0 while j < cols: result.data[j * rows + i] = self.data[i * cols + j] j += 1 @@ -254,21 +250,21 @@ class ndarray[T]: def print_arr(self): if self.ndim == 1: stdio.printf("[") - i: t.CSizeT = 0 + i: sizet = 0 while i < self.size: if i > 0: stdio.printf(", ") stdio.printf("%.4f", self.data[i]) i += 1 stdio.printf("]\n") elif self.ndim == 2: - rows: t.CSizeT = self.shape[0] - cols: t.CSizeT = self.shape[1] + rows: sizet = self.shape[0] + cols: sizet = self.shape[1] stdio.printf("[") - i: t.CSizeT = 0 + i: sizet = 0 while i < rows: if i > 0: stdio.printf(" ") stdio.printf("[") - j: t.CSizeT = 0 + j: sizet = 0 while j < cols: if j > 0: stdio.printf(", ") stdio.printf("%.4f", self.data[i * cols + j]) @@ -330,7 +326,7 @@ def _empty_like(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: # ============================================================ # Array creation functions (float64 default) # ============================================================ -def array(pool: rawptr[memhub.MemManager], data: t.CDouble | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def array(pool: rawptr[memhub.MemManager], data: t.CDouble | t.CPtr, n: sizet) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(pool) if not a: return None a.data = pool.alloc(n * t.CDouble.__sizeof__()) @@ -346,7 +342,7 @@ def array(pool: rawptr[memhub.MemManager], data: t.CDouble | t.CPtr, n: t.CSizeT a.owns_data = 1 return a -def zeros(pool: rawptr[memhub.MemManager], n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def zeros(pool: rawptr[memhub.MemManager], n: sizet) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(pool) if not a: return None a.data = pool.alloc(n * t.CDouble.__sizeof__()) @@ -362,13 +358,13 @@ def zeros(pool: rawptr[memhub.MemManager], n: t.CSizeT) -> ndarray[t.CDouble] | a.owns_data = 1 return a -def ones(pool: rawptr[memhub.MemManager], n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def ones(pool: rawptr[memhub.MemManager], n: sizet) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) if not a: return None a.fill(t.CDouble(1.0)) return a -def full(pool: rawptr[memhub.MemManager], n: t.CSizeT, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: +def full(pool: rawptr[memhub.MemManager], n: sizet, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) if not a: return None a.fill(val) @@ -376,7 +372,7 @@ def full(pool: rawptr[memhub.MemManager], n: t.CSizeT, val: t.CDouble) -> ndarra def arange(pool: rawptr[memhub.MemManager], start: t.CDouble, stop: t.CDouble, step: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: if step == t.CDouble(0.0): return None - n: t.CSizeT = 0 + n: sizet = 0 if step > t.CDouble(0.0): v: t.CDouble = start while v < stop: @@ -390,7 +386,7 @@ def arange(pool: rawptr[memhub.MemManager], start: t.CDouble, stop: t.CDouble, s if n == 0: return None a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) if not a: return None - i: t.CSizeT = 0 + i: sizet = 0 v = start while i < n: a.data[i] = v @@ -398,7 +394,7 @@ def arange(pool: rawptr[memhub.MemManager], start: t.CDouble, stop: t.CDouble, s i += 1 return a -def linspace(pool: rawptr[memhub.MemManager], start: t.CDouble, stop: t.CDouble, num: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def linspace(pool: rawptr[memhub.MemManager], start: t.CDouble, stop: t.CDouble, num: sizet) -> ndarray[t.CDouble] | t.CPtr: if num == 0: return None a: ndarray[t.CDouble] | t.CPtr = zeros(pool, num) if not a: return None @@ -406,16 +402,16 @@ def linspace(pool: rawptr[memhub.MemManager], start: t.CDouble, stop: t.CDouble, a.data[0] = start return a step: t.CDouble = (stop - start) / t.CDouble(num - 1) - i: t.CSizeT = 0 + i: sizet = 0 while i < num: a.data[i] = start + t.CDouble(i) * step i += 1 return a -def empty2d(pool: rawptr[memhub.MemManager], rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def empty2d(pool: rawptr[memhub.MemManager], rows: sizet, cols: sizet) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = _alloc_ndarray(pool) if not a: return None - total: t.CSizeT = rows * cols + total: sizet = rows * cols a.data = pool.alloc(total * t.CDouble.__sizeof__()) if not a.data: pool.free(a) @@ -430,29 +426,29 @@ def empty2d(pool: rawptr[memhub.MemManager], rows: t.CSizeT, cols: t.CSizeT) -> _compute_strides(a) return a -def zeros2d(pool: rawptr[memhub.MemManager], rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def zeros2d(pool: rawptr[memhub.MemManager], rows: sizet, cols: sizet) -> ndarray[t.CDouble] | t.CPtr: return empty2d(pool, rows, cols) -def ones2d(pool: rawptr[memhub.MemManager], rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def ones2d(pool: rawptr[memhub.MemManager], rows: sizet, cols: sizet) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, rows, cols) if not a: return None a.fill(t.CDouble(1.0)) return a -def eye(pool: rawptr[memhub.MemManager], n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def eye(pool: rawptr[memhub.MemManager], n: sizet) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, n, n) if not a: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < n: a.data[i * n + i] = t.CDouble(1.0) i += 1 return a def diag(pool: rawptr[memhub.MemManager], vals: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: - n: t.CSizeT = vals.size + n: sizet = vals.size a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, n, n) if not a: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < n: a.data[i * n + i] = vals.data[i] i += 1 @@ -465,7 +461,7 @@ def diag(pool: rawptr[memhub.MemManager], vals: ndarray[t.CDouble] | t.CPtr) -> def np_abs(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: v: t.CDouble = a.data[i] result.data[i] = v if v >= t.CDouble(0.0) else -v @@ -475,63 +471,63 @@ def np_abs(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: def np_sqrt(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.sqrt(a.data[i]) + result.data[i] = math.sqrt(a.data[i]) i += 1 return result def np_exp(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.exp(a.data[i]) + result.data[i] = math.exp(a.data[i]) i += 1 return result def np_log(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.log(a.data[i]) + result.data[i] = math.log(a.data[i]) i += 1 return result def np_sin(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.sin(a.data[i]) + result.data[i] = math.sin(a.data[i]) i += 1 return result def np_cos(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.cos(a.data[i]) + result.data[i] = math.cos(a.data[i]) i += 1 return result def np_tan(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.tan(a.data[i]) + result.data[i] = math.tan(a.data[i]) i += 1 return result def np_pow(a: ndarray[t.CDouble] | t.CPtr, p: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.pow(a.data[i], p) + result.data[i] = math.pow(a.data[i], p) i += 1 return result @@ -542,7 +538,7 @@ def np_pow(a: ndarray[t.CDouble] | t.CPtr, p: t.CDouble) -> ndarray[t.CDouble] | def add_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = a.data[i] + s i += 1 @@ -551,7 +547,7 @@ def add_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDoubl def mul_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = a.data[i] * s i += 1 @@ -560,7 +556,7 @@ def mul_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDoubl def sub_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = a.data[i] - s i += 1 @@ -569,7 +565,7 @@ def sub_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDoubl def div_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: if s != t.CDouble(0.0): result.data[i] = a.data[i] / s @@ -585,19 +581,19 @@ def div_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDoubl def matmul(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: # 2D matrix multiply: a(m,k) x b(k,n) = c(m,n) if a.ndim != 2 or b.ndim != 2: return None - m: t.CSizeT = a.shape[0] - k: t.CSizeT = a.shape[1] - k2: t.CSizeT = b.shape[0] - n: t.CSizeT = b.shape[1] + m: sizet = a.shape[0] + k: sizet = a.shape[1] + k2: sizet = b.shape[0] + n: sizet = b.shape[1] if k != k2: return None c: ndarray[t.CDouble] | t.CPtr = empty2d(a.pool, m, n) if not c: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < m: - j: t.CSizeT = 0 + j: sizet = 0 while j < n: s: t.CDouble = t.CDouble(0.0) - p: t.CSizeT = 0 + p: sizet = 0 while p < k: s += a.data[i * k + p] * b.data[p * n + j] p += 1 @@ -639,7 +635,7 @@ def var(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: if a.size == 0: return t.CDouble(0.0) m: t.CDouble = a.mean() s: t.CDouble = t.CDouble(0.0) - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: d: t.CDouble = a.data[i] - m s += d * d @@ -647,15 +643,15 @@ def var(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: return s / t.CDouble(a.size) def std(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: - return vipermath.sqrt(var(a)) + return math.sqrt(var(a)) def norm(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: - return vipermath.sqrt(a.dot(a)) + return math.sqrt(a.dot(a)) def clip(a: ndarray[t.CDouble] | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: v: t.CDouble = a.data[i] if v < lo: v = lo @@ -666,7 +662,7 @@ def clip(a: ndarray[t.CDouble] | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarra def concatenate(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: if a.ndim != 1 or b.ndim != 1: return None - total: t.CSizeT = a.size + b.size + total: sizet = a.size + b.size result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, total) if not result: return None string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) @@ -677,10 +673,10 @@ def sort_arr(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = a.copy() if not result: return None # Simple insertion sort - i: t.CSizeT = 1 + i: sizet = 1 while i < result.size: key: t.CDouble = result.data[i] - j: t.CSizeT = i - 1 + j: sizet = i - 1 while j < result.size and result.data[j] > key: result.data[j + 1] = result.data[j] if j == 0: break @@ -696,7 +692,7 @@ def sort_arr(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: def reverse(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = a.data[a.size - 1 - i] i += 1 @@ -709,52 +705,52 @@ def reverse(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: def np_log10(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.log10(a.data[i]) + result.data[i] = math.log10(a.data[i]) i += 1 return result def np_log2(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.log2(a.data[i]) + result.data[i] = math.log2(a.data[i]) i += 1 return result def np_floor(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.floor(a.data[i]) + result.data[i] = math.floor(a.data[i]) i += 1 return result def np_ceil(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.ceil(a.data[i]) + result.data[i] = math.ceil(a.data[i]) i += 1 return result def np_round(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.round(a.data[i]) + result.data[i] = math.round(a.data[i]) i += 1 return result def np_sign(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: if a.data[i] > t.CDouble(0.0): result.data[i] = t.CDouble(1.0) @@ -768,106 +764,106 @@ def np_sign(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: def np_tanh(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.tanh(a.data[i]) + result.data[i] = math.tanh(a.data[i]) i += 1 return result def np_sinh(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.sinh(a.data[i]) + result.data[i] = math.sinh(a.data[i]) i += 1 return result def np_cosh(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.cosh(a.data[i]) + result.data[i] = math.cosh(a.data[i]) i += 1 return result def np_arcsin(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.asin(a.data[i]) + result.data[i] = math.asin(a.data[i]) i += 1 return result def np_arccos(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.acos(a.data[i]) + result.data[i] = math.acos(a.data[i]) i += 1 return result def np_arctan(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.atan(a.data[i]) + result.data[i] = math.atan(a.data[i]) i += 1 return result def np_arctan2(y: ndarray[t.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(y) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < y.size: - result.data[i] = vipermath.atan2(y.data[i], x.data[i]) + result.data[i] = math.atan2(y.data[i], x.data[i]) i += 1 return result def np_degrees(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.degrees(a.data[i]) + result.data[i] = math.degrees(a.data[i]) i += 1 return result def np_radians(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = vipermath.radians(a.data[i]) + result.data[i] = math.radians(a.data[i]) i += 1 return result def np_isnan(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = t.CDouble(vipermath.isnan(a.data[i])) + result.data[i] = t.CDouble(math.isnan(a.data[i])) i += 1 return result def np_isinf(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - result.data[i] = t.CDouble(vipermath.isinf(a.data[i])) + result.data[i] = t.CDouble(math.isinf(a.data[i])) i += 1 return result def np_maximum(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = a.data[i] if a.data[i] > b.data[i] else b.data[i] i += 1 @@ -876,7 +872,7 @@ def np_maximum(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) - def np_minimum(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = a.data[i] if a.data[i] < b.data[i] else b.data[i] i += 1 @@ -890,7 +886,7 @@ def cumsum(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None s: t.CDouble = t.CDouble(0.0) - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: s += a.data[i] result.data[i] = s @@ -901,7 +897,7 @@ def diff(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: if a.size < 2: return None result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, a.size - 1) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size - 1: result.data[i] = a.data[i + 1] - a.data[i] i += 1 @@ -918,9 +914,9 @@ def flatten(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: def trace(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: if a.ndim != 2: return t.CDouble(0.0) - n: t.CSizeT = a.shape[0] if a.shape[0] < a.shape[1] else a.shape[1] + n: sizet = a.shape[0] if a.shape[0] < a.shape[1] else a.shape[1] s: t.CDouble = t.CDouble(0.0) - i: t.CSizeT = 0 + i: sizet = 0 while i < n: s += a.data[i * a.shape[1] + i] i += 1 @@ -929,9 +925,9 @@ def trace(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: def outer(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = empty2d(a.pool, a.size, b.size) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: - j: t.CSizeT = 0 + j: sizet = 0 while j < b.size: result.data[i * b.size + j] = a.data[i] * b.data[j] j += 1 @@ -941,7 +937,7 @@ def outer(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> nda def np_where(condition: ndarray[t.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.CPtr, y: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(x) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < x.size: if condition.data[i] != t.CDouble(0.0): result.data[i] = x.data[i] @@ -952,7 +948,7 @@ def np_where(condition: ndarray[t.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.C def np_count_nonzero(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: count: t.CInt = 0 - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: if a.data[i] != t.CDouble(0.0): count += 1 @@ -960,7 +956,7 @@ def np_count_nonzero(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: return count def np_all(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: if a.data[i] == t.CDouble(0.0): return 0 @@ -968,7 +964,7 @@ def np_all(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: return 1 def np_any(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: if a.data[i] != t.CDouble(0.0): return 1 @@ -978,7 +974,7 @@ def np_any(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: def np_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = t.CDouble(1.0) if a.data[i] == b.data[i] else t.CDouble(0.0) i += 1 @@ -987,7 +983,7 @@ def np_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> def np_not_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = t.CDouble(1.0) if a.data[i] != b.data[i] else t.CDouble(0.0) i += 1 @@ -996,7 +992,7 @@ def np_not_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) def np_less(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = t.CDouble(1.0) if a.data[i] < b.data[i] else t.CDouble(0.0) i += 1 @@ -1005,7 +1001,7 @@ def np_less(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> n def np_greater(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = t.CDouble(1.0) if a.data[i] > b.data[i] else t.CDouble(0.0) i += 1 @@ -1014,7 +1010,7 @@ def np_greater(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) - def np_less_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = t.CDouble(1.0) if a.data[i] <= b.data[i] else t.CDouble(0.0) i += 1 @@ -1023,7 +1019,7 @@ def np_less_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr def np_greater_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: result.data[i] = t.CDouble(1.0) if a.data[i] >= b.data[i] else t.CDouble(0.0) i += 1 @@ -1033,10 +1029,10 @@ def np_greater_equal(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.C # ============================================================ # Additional creation functions (float64 default) # ============================================================ -def empty(pool: rawptr[memhub.MemManager], n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: +def empty(pool: rawptr[memhub.MemManager], n: sizet) -> ndarray[t.CDouble] | t.CPtr: return zeros(pool, n) -def full2d(pool: rawptr[memhub.MemManager], rows: t.CSizeT, cols: t.CSizeT, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: +def full2d(pool: rawptr[memhub.MemManager], rows: sizet, cols: sizet, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, rows, cols) if not a: return None a.fill(val) @@ -1077,9 +1073,9 @@ def meshgrid(x: ndarray[t.CDouble] | t.CPtr, y: ndarray[t.CDouble] | t.CPtr) -> # Returns X grid as 2D array (each row is x) result: ndarray[t.CDouble] | t.CPtr = empty2d(x.pool, y.size, x.size) if not result: return None - i: t.CSizeT = 0 + i: sizet = 0 while i < y.size: - j: t.CSizeT = 0 + j: sizet = 0 while j < x.size: result.data[i * x.size + j] = x.data[j] j += 1 @@ -1122,7 +1118,7 @@ def np_interp(x: t.CDouble, xp: ndarray[t.CDouble] | t.CPtr, fp: ndarray[t.CDoub if xp.size == 0: return t.CDouble(0.0) if x <= xp.data[0]: return fp.data[0] if x >= xp.data[xp.size - 1]: return fp.data[xp.size - 1] - i: t.CSizeT = 0 + i: sizet = 0 while i < xp.size - 1: if x >= xp.data[i] and x <= xp.data[i + 1]: t_val: t.CDouble = (x - xp.data[i]) / (xp.data[i + 1] - xp.data[i]) @@ -1132,7 +1128,7 @@ def np_interp(x: t.CDouble, xp: ndarray[t.CDouble] | t.CPtr, fp: ndarray[t.CDoub def prod(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: p: t.CDouble = t.CDouble(1.0) - i: t.CSizeT = 0 + i: sizet = 0 while i < a.size: p *= a.data[i] i += 1 @@ -1142,7 +1138,7 @@ def median(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: if a.size == 0: return t.CDouble(0.0) s: ndarray[t.CDouble] | t.CPtr = sort_arr(a) if not s: return t.CDouble(0.0) - mid: t.CSizeT = a.size / 2 + mid: sizet = a.size / 2 if a.size % 2 == 1: result: t.CDouble = s.data[mid] else: @@ -1155,9 +1151,9 @@ def percentile(a: ndarray[t.CDouble] | t.CPtr, q: t.CDouble) -> t.CDouble: s: ndarray[t.CDouble] | t.CPtr = sort_arr(a) if not s: return t.CDouble(0.0) idx: t.CDouble = q / t.CDouble(100.0) * t.CDouble(a.size - 1) - lo: t.CSizeT = t.CSizeT(vipermath.floor(idx)) - hi: t.CSizeT = t.CSizeT(vipermath.ceil(idx)) - frac: t.CDouble = idx - vipermath.floor(idx) + lo: sizet = sizet(math.floor(idx)) + hi: sizet = sizet(math.ceil(idx)) + frac: t.CDouble = idx - math.floor(idx) result: t.CDouble = s.data[lo] + frac * (s.data[hi] - s.data[lo]) s.delete() return result diff --git a/openssl/bio.vp b/openssl/bio.vp index 99d2311..7d765ce 100644 --- a/openssl/bio.vp +++ b/openssl/bio.vp @@ -48,9 +48,9 @@ extern def BIO_gets(bp: BioPtr, buf: bytes, size: int) -> int # int BIO_puts(BIO *bp, const char *buf) extern def BIO_puts(bp: BioPtr, buf: str) -> int # size_t BIO_ctrl_pending(BIO *b) -extern def BIO_ctrl_pending(b: BioPtr) -> t.CSizeT +extern def BIO_ctrl_pending(b: BioPtr) -> sizet # size_t BIO_ctrl_wpending(BIO *b) -extern def BIO_ctrl_wpending(b: BioPtr) -> t.CSizeT +extern def BIO_ctrl_wpending(b: BioPtr) -> sizet # ---- BIO 控制(宏的底层 ctrl;连接/非阻塞等由它实现)---- # long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg) diff --git a/openssl/crypto.vp b/openssl/crypto.vp index 2fa3731..53d84c9 100644 --- a/openssl/crypto.vp +++ b/openssl/crypto.vp @@ -50,13 +50,13 @@ extern def OPENSSL_version_build_metadata() -> str # ---- 内存 / 安全擦除 ---- # void OPENSSL_cleanse(void *ptr, size_t len) -extern def OPENSSL_cleanse(ptr: bytes, len: t.CSizeT) +extern def OPENSSL_cleanse(ptr: bytes, len: sizet) # void CRYPTO_free(void *ptr, const char *file, int line) extern def CRYPTO_free(ptr: bytes, file: str, line: int) # void *CRYPTO_malloc(size_t num, const char *file, int line) -extern def CRYPTO_malloc(num: t.CSizeT, file: str, line: int) -> bytes +extern def CRYPTO_malloc(num: sizet, file: str, line: int) -> bytes # int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) -extern def CRYPTO_memcmp(in_a: bytes, in_b: bytes, len: t.CSizeT) -> int +extern def CRYPTO_memcmp(in_a: bytes, in_b: bytes, len: sizet) -> int # char *OPENSSL_buf2hexstr(const unsigned char *buf, long buflen) → 由 ossl_free 释放 extern def OPENSSL_buf2hexstr(buf: bytes, buflen: t.CInt32T) -> str # int OPENSSL_hexchar2int(unsigned char c) @@ -64,12 +64,12 @@ extern def OPENSSL_hexchar2int(c: t.CUInt8T) -> int # int OPENSSL_strcasecmp(const char *s1, const char *s2) extern def OPENSSL_strcasecmp(s1: str, s2: str) -> int # int OPENSSL_strncasecmp(const char *s1, const char *s2, size_t n) -extern def OPENSSL_strncasecmp(s1: str, s2: str, n: t.CSizeT) -> int +extern def OPENSSL_strncasecmp(s1: str, s2: str, n: sizet) -> int # ---- 便捷封装(OpenSSL 的 CRYPTO_free/CRYPTO_malloc 宏带 file/line 两参,此处封装为单参)---- def ossl_free(ptr: bytes): CRYPTO_free(ptr, "", 0) -def ossl_malloc(num: t.CSizeT) -> bytes: +def ossl_malloc(num: sizet) -> bytes: return CRYPTO_malloc(num, "", 0) diff --git a/openssl/err.vp b/openssl/err.vp index c8d8cf4..ba04dbc 100644 --- a/openssl/err.vp +++ b/openssl/err.vp @@ -18,7 +18,7 @@ extern def ERR_clear_error() # char *ERR_error_string(unsigned long e, char *buf) — buf 可为 NULL(用内部静态缓冲) extern def ERR_error_string(e: t.CUInt32T, buf: bytes) -> str # void ERR_error_string_n(unsigned long e, char *buf, size_t len) -extern def ERR_error_string_n(e: t.CUInt32T, buf: bytes, len: t.CSizeT) +extern def ERR_error_string_n(e: t.CUInt32T, buf: bytes, len: sizet) # const char *ERR_lib_error_string(unsigned long e) extern def ERR_lib_error_string(e: t.CUInt32T) -> str # const char *ERR_func_error_string(unsigned long e) diff --git a/openssl/evp.vp b/openssl/evp.vp index 71c3cce..049ceee 100644 --- a/openssl/evp.vp +++ b/openssl/evp.vp @@ -51,7 +51,7 @@ extern def EVP_DigestInit_ex(ctx: EvpMdCtxPtr, type: EvpMdPtr, impl: bytes) -> i # int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) extern def EVP_DigestInit(ctx: EvpMdCtxPtr, type: EvpMdPtr) -> int # int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt) -extern def EVP_DigestUpdate(ctx: EvpMdCtxPtr, d: bytes, cnt: t.CSizeT) -> int +extern def EVP_DigestUpdate(ctx: EvpMdCtxPtr, d: bytes, cnt: sizet) -> int # int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s) extern def EVP_DigestFinal_ex(ctx: EvpMdCtxPtr, md: bytes, s: bytes) -> int # int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s) @@ -60,7 +60,7 @@ extern def EVP_DigestFinal(ctx: EvpMdCtxPtr, md: bytes, s: bytes) -> int extern def EVP_MD_CTX_get_size(ctx: EvpMdCtxPtr) -> int # 一次性摘要: int EVP_Digest(const void *data, size_t count, unsigned char *md, # unsigned int *size, const EVP_MD *type, ENGINE *impl) -extern def EVP_Digest(data: bytes, count: t.CSizeT, md: bytes, size: bytes, +extern def EVP_Digest(data: bytes, count: sizet, md: bytes, size: bytes, type: EvpMdPtr, impl: bytes) -> int # ============================================================ @@ -155,9 +155,9 @@ extern def EVP_CIPHER_CTX_get_block_size(ctx: EvpCipherCtxPtr) -> int extern def EVP_CIPHER_CTX_get_key_length(ctx: EvpCipherCtxPtr) -> int extern def EVP_CIPHER_CTX_get_iv_length(ctx: EvpCipherCtxPtr) -> int # int EVP_CIPHER_CTX_get_iv(const EVP_CIPHER_CTX *ctx, void *iv, size_t len) -extern def EVP_CIPHER_CTX_get_iv(ctx: EvpCipherCtxPtr, iv: bytes, len: t.CSizeT) -> int +extern def EVP_CIPHER_CTX_get_iv(ctx: EvpCipherCtxPtr, iv: bytes, len: sizet) -> int # int EVP_CIPHER_CTX_set_iv(EVP_CIPHER_CTX *ctx, const void *iv, size_t len) -extern def EVP_CIPHER_CTX_set_iv(ctx: EvpCipherCtxPtr, iv: bytes, len: t.CSizeT) -> int +extern def EVP_CIPHER_CTX_set_iv(ctx: EvpCipherCtxPtr, iv: bytes, len: sizet) -> int # ---- GCM 相关 ctrl 常量(EVP_CIPHER_CTX_ctrl 使用)---- EvpCtrlGcmSetIvl: t.CDefine = 0x9 # EVP_CTRL_AEAD_SET_IVLEN @@ -198,28 +198,28 @@ extern def EVP_PKEY_decrypt_init(ctx: EvpPkeyCtxPtr) -> int # int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, # const unsigned char *tbs, size_t tbslen) extern def EVP_PKEY_sign(ctx: EvpPkeyCtxPtr, sig: bytes, siglen: bytes, - tbs: bytes, tbslen: t.CSizeT) -> int -extern def EVP_PKEY_verify(ctx: EvpPkeyCtxPtr, sig: bytes, siglen: t.CSizeT, - tbs: bytes, tbslen: t.CSizeT) -> int + tbs: bytes, tbslen: sizet) -> int +extern def EVP_PKEY_verify(ctx: EvpPkeyCtxPtr, sig: bytes, siglen: sizet, + tbs: bytes, tbslen: sizet) -> int extern def EVP_PKEY_encrypt(ctx: EvpPkeyCtxPtr, out: bytes, outlen: bytes, - inn: bytes, inlen: t.CSizeT) -> int + inn: bytes, inlen: sizet) -> int extern def EVP_PKEY_decrypt(ctx: EvpPkeyCtxPtr, out: bytes, outlen: bytes, - inn: bytes, inlen: t.CSizeT) -> int + inn: bytes, inlen: sizet) -> int # 摘要签名/验签(DigestSign*:RSA-PSS/ECDSA 最常用) # int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, # ENGINE *e, EVP_PKEY *pkey) extern def EVP_DigestSignInit(ctx: EvpMdCtxPtr, pctx: bytes, type: EvpMdPtr, e: bytes, pkey: EvpPkeyPtr) -> int -extern def EVP_DigestSignUpdate(ctx: EvpMdCtxPtr, data: bytes, dsize: t.CSizeT) -> int +extern def EVP_DigestSignUpdate(ctx: EvpMdCtxPtr, data: bytes, dsize: sizet) -> int # int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen) extern def EVP_DigestSignFinal(ctx: EvpMdCtxPtr, sigret: bytes, siglen: bytes) -> int # int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, # ENGINE *e, EVP_PKEY *pkey) extern def EVP_DigestVerifyInit(ctx: EvpMdCtxPtr, pctx: bytes, type: EvpMdPtr, e: bytes, pkey: EvpPkeyPtr) -> int -extern def EVP_DigestVerifyUpdate(ctx: EvpMdCtxPtr, data: bytes, dsize: t.CSizeT) -> int -extern def EVP_DigestVerifyFinal(ctx: EvpMdCtxPtr, sig: bytes, siglen: t.CSizeT) -> int +extern def EVP_DigestVerifyUpdate(ctx: EvpMdCtxPtr, data: bytes, dsize: sizet) -> int +extern def EVP_DigestVerifyFinal(ctx: EvpMdCtxPtr, sig: bytes, siglen: sizet) -> int # ============================================================ # 7) 口令派生 / 辅助 diff --git a/openssl/hmac.vp b/openssl/hmac.vp index 7963b22..24d9c22 100644 --- a/openssl/hmac.vp +++ b/openssl/hmac.vp @@ -10,7 +10,7 @@ from openssl.types import * # unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, # const unsigned char *d, size_t n, unsigned char *md, unsigned int *md_len) extern def HMAC(evp_md: EvpMdPtr, key: bytes, key_len: int, - d: bytes, n: t.CSizeT, md: bytes, md_len: bytes) -> bytes + d: bytes, n: sizet, md: bytes, md_len: bytes) -> bytes # ---- 上下文增量 HMAC(OpenSSL 3.x 提供)---- # HMAC_CTX *HMAC_CTX_new(void) @@ -21,12 +21,12 @@ extern def HMAC_CTX_free(ctx: HmacCtxPtr) extern def HMAC_Init_ex(ctx: HmacCtxPtr, key: bytes, len: int, md: EvpMdPtr, impl: bytes) -> int # int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len) -extern def HMAC_Update(ctx: HmacCtxPtr, data: bytes, len: t.CSizeT) -> int +extern def HMAC_Update(ctx: HmacCtxPtr, data: bytes, len: sizet) -> int # int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) extern def HMAC_Final(ctx: HmacCtxPtr, md: bytes, len: bytes) -> int # int HMAC_CTX_reset(HMAC_CTX *ctx) extern def HMAC_CTX_reset(ctx: HmacCtxPtr) -> int # size_t HMAC_size(const HMAC_CTX *e) -extern def HMAC_size(e: HmacCtxPtr) -> t.CSizeT +extern def HMAC_size(e: HmacCtxPtr) -> sizet # int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx) extern def HMAC_CTX_copy(dctx: HmacCtxPtr, sctx: HmacCtxPtr) -> int diff --git a/openssl/md5.vp b/openssl/md5.vp index 39b5e98..b3ba8db 100644 --- a/openssl/md5.vp +++ b/openssl/md5.vp @@ -9,4 +9,4 @@ from openssl.types import * Md5DigestLength: t.CDefine = 16 # unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md) -extern def MD5(d: bytes, n: t.CSizeT, md: bytes) -> bytes +extern def MD5(d: bytes, n: sizet, md: bytes) -> bytes diff --git a/openssl/sha.vp b/openssl/sha.vp index 4597548..8e26d80 100644 --- a/openssl/sha.vp +++ b/openssl/sha.vp @@ -16,13 +16,13 @@ Sha384DigestLength: t.CDefine = 48 Sha512DigestLength: t.CDefine = 64 # unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md) -extern def SHA1(d: bytes, n: t.CSizeT, md: bytes) -> bytes +extern def SHA1(d: bytes, n: sizet, md: bytes) -> bytes # unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md) -extern def SHA224(d: bytes, n: t.CSizeT, md: bytes) -> bytes +extern def SHA224(d: bytes, n: sizet, md: bytes) -> bytes # unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md) -extern def SHA256(d: bytes, n: t.CSizeT, md: bytes) -> bytes +extern def SHA256(d: bytes, n: sizet, md: bytes) -> bytes # unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md) -extern def SHA384(d: bytes, n: t.CSizeT, md: bytes) -> bytes +extern def SHA384(d: bytes, n: sizet, md: bytes) -> bytes # unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md) -extern def SHA512(d: bytes, n: t.CSizeT, md: bytes) -> bytes +extern def SHA512(d: bytes, n: sizet, md: bytes) -> bytes # SHA-3 只经 EVP 提供(EVP_sha3_256() 等,见 evp.vp) diff --git a/os/__init__.vp b/os/__init__.vp index b6b8857..b822948 100644 --- a/os/__init__.vp +++ b/os/__init__.vp @@ -12,7 +12,7 @@ import os._posix # os.path is for cross-platform pure string operations, can be used directly # Module-level global MBuddy pointer (initialized by the user in main) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= diff --git a/os/_posix.vp b/os/_posix.vp index 19df9d4..8456627 100644 --- a/os/_posix.vp +++ b/os/_posix.vp @@ -9,7 +9,7 @@ import stdlib MAX_PATH_LEN: t.CDefine = 4096 # 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= @@ -164,10 +164,10 @@ def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: continue # 复制文件名到新分配的内存 - name_len: t.CSizeT = len(name) + name_len: sizet = len(name) name_buf: bytes = _mbuddy.alloc(name_len + 1) if name_buf == None: break - i: t.CSizeT = 0 + i: sizet = 0 for ch in name: name_buf[i] = ch i += 1 diff --git a/os/_win32.vp b/os/_win32.vp index fbabe2e..f78f5bc 100644 --- a/os/_win32.vp +++ b/os/_win32.vp @@ -13,7 +13,7 @@ MAX_PATH_LEN: t.CDefine = 260 INVALID_FILE_ATTRIBUTES: t.CDefine = 0xFFFFFFFF # 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= @@ -181,10 +181,10 @@ def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: max_count 为 out_names 数组最大容量。 返回实际列举的条目数。失败返回 0。""" # 构造搜索模式:path\* - path_len: t.CSizeT = len(path) + path_len: sizet = len(path) pattern: bytes = _mbuddy.alloc(path_len + 3) if pattern == None: return 0 - i: t.CSizeT = 0 + i: sizet = 0 for ch in path: pattern[i] = ch i += 1 @@ -218,10 +218,10 @@ def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: continue # 复制文件名到新分配的内存 - name_len: t.CSizeT = len(name) + name_len: sizet = len(name) name_buf: bytes = _mbuddy.alloc(name_len + 1) if name_buf == None: break - j: t.CSizeT = 0 + j: sizet = 0 for ch in name: name_buf[j] = ch j += 1 diff --git a/os/path.vp b/os/path.vp index 3ca630b..2dcdc91 100644 --- a/os/path.vp +++ b/os/path.vp @@ -6,21 +6,21 @@ import platmacro # 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= # 路径分隔符 # ============================================================================= -def sep() -> t.CChar: +def sep() -> char: """返回当前平台的路径分隔符(Windows: \\,POSIX: /)""" if platmacro.IS_WINDOWS: return '\\' return '/' -def _is_sep(ch: t.CChar) -> bool: +def _is_sep(ch: char) -> bool: """判断字符是否为路径分隔符(/ 或 \\,跨平台识别)""" return ch == '/' or ch == '\\' @@ -32,10 +32,10 @@ def _is_sep(ch: t.CChar) -> bool: def _dup_str(s: str) -> str: """复制字符串(通过全局 MBuddy 分配内存)""" if s == None: return None - length: t.CSizeT = len(s) + length: sizet = len(s) buf: bytes = _mbuddy.alloc(length + 1) if buf == None: return None - i: t.CSizeT = 0 + i: sizet = 0 for ch in s: buf[i] = ch i += 1 @@ -43,15 +43,15 @@ def _dup_str(s: str) -> str: return str(buf) -def _substr(s: str, start: t.CSizeT, end: t.CSizeT) -> str: +def _substr(s: str, start: sizet, end: sizet) -> str: """提取子串 s[start:end](通过全局 MBuddy 分配内存)""" if s == None: return None if start >= end: return _dup_str("") - result_len: t.CSizeT = end - start + result_len: sizet = end - start buf: bytes = _mbuddy.alloc(result_len + 1) if buf == None: return None - i: t.CSizeT = 0 - k: t.CSizeT = start + i: sizet = 0 + k: sizet = start while k < end: buf[i] = s[k] i += 1 @@ -73,7 +73,7 @@ def isabs(path: str) -> bool: if path[0] == '/' or path[0] == '\\': return True if platmacro.IS_WINDOWS: # 检查 X:\ 或 X:/ 模式 - c0: t.CChar = path[0] + c0: char = path[0] if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'): if path[1] == ':': if path[2] == '\\' or path[2] == '/': @@ -94,15 +94,15 @@ def join(path1: str, path2: str) -> str: if isabs(path2): return _dup_str(path2) - len1: t.CSizeT = len(path1) - len2: t.CSizeT = len(path2) + len1: sizet = len(path1) + len2: sizet = len(path2) # 检查 path1 是否以分隔符结尾 need_sep: bool = True if _is_sep(path1[len1 - 1]): need_sep = False - total: t.CSizeT = len1 + len2 + 1 + total: sizet = len1 + len2 + 1 if need_sep: total += 1 @@ -110,7 +110,7 @@ def join(path1: str, path2: str) -> str: if buf == None: return None # 复制 path1 - i: t.CSizeT = 0 + i: sizet = 0 for ch in path1: buf[i] = ch i += 1 @@ -132,11 +132,11 @@ def join(path1: str, path2: str) -> str: def basename(path: str) -> str: """返回路径的文件名部分(最后一个分隔符之后的内容)""" if path == None: return None - length: t.CSizeT = len(path) + length: sizet = len(path) if length == 0: return _dup_str("") # 从后向前找分隔符 - i: t.CSizeT = length + i: sizet = length while i > 0: i -= 1 if _is_sep(path[i]): @@ -149,11 +149,11 @@ def basename(path: str) -> str: def dirname(path: str) -> str: """返回路径的目录部分(最后一个分隔符之前的内容)""" if path == None: return None - length: t.CSizeT = len(path) + length: sizet = len(path) if length == 0: return _dup_str("") # 从后向前找分隔符 - i: t.CSizeT = length + i: sizet = length while i > 0: i -= 1 if _is_sep(path[i]): @@ -174,11 +174,11 @@ def splitext_name(path: str) -> str: """返回路径去除扩展名后的主名部分。 扩展名从最后一个 '.' 开始(该 '.' 不能是路径最后一个组件的第一个字符)。""" if path == None: return None - length: t.CSizeT = len(path) + length: sizet = len(path) if length == 0: return _dup_str("") # 从后向前找 '.',遇到分隔符停止 - i: t.CSizeT = length + i: sizet = length while i > 0: i -= 1 if path[i] == '.': @@ -193,11 +193,11 @@ def splitext_name(path: str) -> str: def splitext_ext(path: str) -> str: """返回路径的扩展名部分(包含 '.')。无扩展名时返回空字符串。""" if path == None: return None - length: t.CSizeT = len(path) + length: sizet = len(path) if length == 0: return _dup_str("") # 从后向前找 '.',遇到分隔符停止 - i: t.CSizeT = length + i: sizet = length while i > 0: i -= 1 if path[i] == '.': @@ -217,16 +217,16 @@ def normpath(path: str) -> str: """规范化路径:统一分隔符、消除多余的 . 和 .. 组件、合并连续分隔符。 注意:不解析符号链接,不调用系统 API。""" if path == None: return None - length: t.CSizeT = len(path) + length: sizet = 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: t.CChar = sep() + out_pos: sizet = 0 + i: sizet = 0 + s: char = sep() # 处理绝对路径前缀 is_absolute: bool = False @@ -237,10 +237,10 @@ def normpath(path: str) -> str: i = 1 # Windows 盘符前缀(X:\ 或 X:/) - drive_prefix_len: t.CSizeT = 0 + drive_prefix_len: sizet = 0 if platmacro.IS_WINDOWS: if length >= 3: - c0: t.CChar = path[0] + c0: char = path[0] if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'): if path[1] == ':': if _is_sep(path[2]): @@ -263,10 +263,10 @@ def normpath(path: str) -> str: break # 提取组件 - comp_start: t.CSizeT = i + comp_start: sizet = i while i < length and not _is_sep(path[i]): i += 1 - comp_len: t.CSizeT = i - comp_start + comp_len: sizet = i - comp_start # 处理 "." 组件:跳过 if comp_len == 1 and path[comp_start] == '.': @@ -301,7 +301,7 @@ def normpath(path: str) -> str: buf[out_pos] = s out_pos += 1 - j: t.CSizeT = comp_start + j: sizet = comp_start while j < comp_start + comp_len: buf[out_pos] = path[j] out_pos += 1 diff --git a/platmacro.vp b/platmacro.vp index 695f918..230e378 100644 --- a/platmacro.vp +++ b/platmacro.vp @@ -1,57 +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 +define IS_WINDOWS = 1 +define IS_WIN64 = 1 +define IS_X86_64 = 1 +define IS_LP64 = 1 +define IS_LITTLE_ENDIAN = 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 +define IS_LINUX = 0 +define IS_MACOS = 0 +define IS_ARM64 = 0 +define IS_BIG_ENDIAN = 0 +define IS_ILP32 = 0 -PTR_SIZE: t.CDefine = 8 -INT_SIZE: t.CDefine = 4 -LONG_SIZE: t.CDefine = 4 -WORD_SIZE: t.CDefine = 8 +define PTR_SIZE = 8 +define INT_SIZE = 4 +define LONG_SIZE = 4 +define WORD_SIZE = 8 -CACHE_LINE_SIZE: t.CDefine = 64 -PAGE_SIZE: t.CDefine = 4096 -STACK_ALIGN: t.CDefine = 16 -MAX_PATH_LEN: t.CDefine = 260 +define CACHE_LINE_SIZE = 64 +define PAGE_SIZE = 4096 +define STACK_ALIGN = 16 +define MAX_PATH_LEN = 260 -PLATFORM_NAME: t.CDefine = 1 -ARCH_NAME: t.CDefine = 1 +define PLATFORM_NAME = 1 +define ARCH_NAME = 1 -WINVER: t.CDefine = 0x0A00 -_WIN32_WINNT: t.CDefine = 0x0A00 -NTDDI_VERSION: t.CDefine = 0x0A000006 +define WINVER = 0x0A00 +define _WIN32_WINNT = 0x0A00 +define NTDDI_VERSION = 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 +define HAS_SSE2 = 1 +define HAS_AVX = 1 +define HAS_AVX2 = 1 +define HAS_FMA = 1 +define HAS_NEON = 0 -ALIGNOF_INT: t.CDefine = 4 -ALIGNOF_LONG: t.CDefine = 4 -ALIGNOF_PTR: t.CDefine = 8 -ALIGNOF_DOUBLE: t.CDefine = 8 -ALIGNOF_LONG_DOUBLE: t.CDefine = 16 +define ALIGNOF_INT = 4 +define ALIGNOF_LONG = 4 +define ALIGNOF_PTR = 8 +define ALIGNOF_DOUBLE = 8 +define ALIGNOF_LONG_DOUBLE = 16 -SIZEOF_SHORT: t.CDefine = 2 -SIZEOF_INT: t.CDefine = 4 -SIZEOF_LONG: t.CDefine = 4 -SIZEOF_LONG_LONG: t.CDefine = 8 -SIZEOF_FLOAT: t.CDefine = 4 -SIZEOF_DOUBLE: t.CDefine = 8 -SIZEOF_LONG_DOUBLE: t.CDefine = 16 -SIZEOF_POINTER: t.CDefine = 8 -SIZEOF_SIZE_T: t.CDefine = 8 -SIZEOF_PTRDIFF_T: t.CDefine = 8 +define SIZEOF_SHORT = 2 +define SIZEOF_INT = 4 +define SIZEOF_LONG = 4 +define SIZEOF_LONG_LONG = 8 +define SIZEOF_FLOAT = 4 +define SIZEOF_DOUBLE = 8 +define SIZEOF_LONG_DOUBLE = 16 +define SIZEOF_POINTER = 8 +define SIZEOF_SIZE_T = 8 +define SIZEOF_PTRDIFF_T = 8 -BYTE_ORDER_LE: t.CDefine = 1 -BYTE_ORDER_BE: t.CDefine = 0 +define BYTE_ORDER_LE = 1 +define BYTE_ORDER_BE = 0 diff --git a/posix.vp b/posix.vp index 1d6e544..6485e93 100644 --- a/posix.vp +++ b/posix.vp @@ -23,99 +23,99 @@ time_t: t.CTypedef = t.CInt64T # Calendar time seconds # ============================================================================= # open() Flags # ============================================================================= -O_RDONLY: t.CDefine = 0 -O_WRONLY: t.CDefine = 1 -O_RDWR: t.CDefine = 2 -O_CREAT: t.CDefine = 0o100 -O_EXCL: t.CDefine = 0o200 -O_TRUNC: t.CDefine = 0o1000 -O_APPEND: t.CDefine = 0o2000 -O_NONBLOCK: t.CDefine = 0o4000 -O_CLOEXEC: t.CDefine = 0o2000000 +define O_RDONLY = 0 +define O_WRONLY = 1 +define O_RDWR = 2 +define O_CREAT = 0o100 +define O_EXCL = 0o200 +define O_TRUNC = 0o1000 +define O_APPEND = 0o2000 +define O_NONBLOCK = 0o4000 +define O_CLOEXEC = 0o2000000 # ============================================================================= # access() Test Flags # ============================================================================= -F_OK: t.CDefine = 0 # File exists -R_OK: t.CDefine = 4 # Read permission -W_OK: t.CDefine = 2 # Write permission -X_OK: t.CDefine = 1 # Execute permission +define F_OK = 0 # File exists +define R_OK = 4 # Read permission +define W_OK = 2 # Write permission +define X_OK = 1 # Execute permission # ============================================================================= # stat struct st_mode Mask and Type Bits # ============================================================================= -S_IFMT: t.CDefine = 0o170000 # Type mask bits -S_IFSOCK: t.CDefine = 0o140000 # Socket -S_IFLNK: t.CDefine = 0o120000 # Symbolic link -S_IFREG: t.CDefine = 0o100000 # Regular file -S_IFBLK: t.CDefine = 0o060000 # Block device -S_IFDIR: t.CDefine = 0o040000 # Directory -S_IFCHR: t.CDefine = 0o020000 # Character device -S_IFIFO: t.CDefine = 0o010000 # FIFO/pipe +define S_IFMT = 0o170000 # Type mask bits +define S_IFSOCK = 0o140000 # Socket +define S_IFLNK = 0o120000 # Symbolic link +define S_IFREG = 0o100000 # Regular file +define S_IFBLK = 0o060000 # Block device +define S_IFDIR = 0o040000 # Directory +define S_IFCHR = 0o020000 # Character device +define S_IFIFO = 0o010000 # FIFO/pipe # Permission Bits -S_ISUID: t.CDefine = 0o4000 # Set-user-ID -S_ISGID: t.CDefine = 0o2000 # Set-group-ID -S_ISVTX: t.CDefine = 0o1000 # Sticky bit -S_IRWXU: t.CDefine = 0o700 # Read/write/execute permission -S_IRUSR: t.CDefine = 0o400 # User read permission -S_IWUSR: t.CDefine = 0o200 # User write permission -S_IXUSR: t.CDefine = 0o100 # User execute permission -S_IRWXG: t.CDefine = 0o070 # Read/write/execute permission -S_IRGRP: t.CDefine = 0o040 # Read permission -S_IWGRP: t.CDefine = 0o020 # Write -S_IXGRP: t.CDefine = 0o010 # Execute -S_IRWXO: t.CDefine = 0o007 # Read/write/execute permission -S_IROTH: t.CDefine = 0o004 # Other read permission -S_IWOTH: t.CDefine = 0o002 # Other write permission -S_IXOTH: t.CDefine = 0o001 # Other execute permission +define S_ISUID = 0o4000 # Set-user-ID +define S_ISGID = 0o2000 # Set-group-ID +define S_ISVTX = 0o1000 # Sticky bit +define S_IRWXU = 0o700 # Read/write/execute permission +define S_IRUSR = 0o400 # User read permission +define S_IWUSR = 0o200 # User write permission +define S_IXUSR = 0o100 # User execute permission +define S_IRWXG = 0o070 # Read/write/execute permission +define S_IRGRP = 0o040 # Read permission +define S_IWGRP = 0o020 # Write +define S_IXGRP = 0o010 # Execute +define S_IRWXO = 0o007 # Read/write/execute permission +define S_IROTH = 0o004 # Other read permission +define S_IWOTH = 0o002 # Other write permission +define S_IXOTH = 0o001 # Other execute permission # ============================================================================= # lseek() whence values # ============================================================================= -SEEK_SET: t.CDefine = 0 -SEEK_CUR: t.CDefine = 1 -SEEK_END: t.CDefine = 2 +define SEEK_SET = 0 +define SEEK_CUR = 1 +define SEEK_END = 2 # ============================================================================= # Path/name length limits # ============================================================================= -PATH_MAX: t.CDefine = 4096 -NAME_MAX: t.CDefine = 255 +define PATH_MAX = 4096 +define NAME_MAX = 255 # ============================================================================= # sysconf() parameters # ============================================================================= -_SC_NPROCESSORS_ONLN: t.CDefine = 84 -_SC_PAGESIZE: t.CDefine = 30 -_SC_CLK_TCK: t.CDefine = 2 +define _SC_NPROCESSORS_ONLN = 84 +define _SC_PAGESIZE = 30 +define _SC_CLK_TCK = 2 # ============================================================================= # dirent struct d_type values # ============================================================================= -DT_UNKNOWN: t.CDefine = 0 -DT_FIFO: t.CDefine = 1 -DT_CHR: t.CDefine = 2 -DT_DIR: t.CDefine = 4 -DT_BLK: t.CDefine = 6 -DT_REG: t.CDefine = 8 -DT_LNK: t.CDefine = 10 -DT_SOCK: t.CDefine = 12 -DT_WHT: t.CDefine = 14 +define DT_UNKNOWN = 0 +define DT_FIFO = 1 +define DT_CHR = 2 +define DT_DIR = 4 +define DT_BLK = 6 +define DT_REG = 8 +define DT_LNK = 10 +define DT_SOCK = 12 +define DT_WHT = 14 # ============================================================================= # waitpid() options # ============================================================================= -WNOHANG: t.CDefine = 1 -WUNTRACED: t.CDefine = 2 -WCONTINUED: t.CDefine = 8 +define WNOHANG = 1 +define WUNTRACED = 2 +define WCONTINUED = 8 # ============================================================================= @@ -125,7 +125,7 @@ WCONTINUED: t.CDefine = 8 # struct stat (144 bytes, Linux x86_64 glibc layout) # Note: st_atim/st_mtim/st_ctim in C are struct timespec { tv_sec; tv_nsec; } # Here split into _sec/_nsec two LONGLONG fields to maintain binary compatibility -class Stat(): +class Stat: st_dev: dev_t # @ 0 st_ino: ino_t # @ 8 st_nlink: nlink_t # @ 16 @@ -164,8 +164,8 @@ class Dirent(): # ============================================================================= extern def open(path: t.CConst | str, oflag: INT, *args) -> INT extern def close(fd: INT) -> INT -extern def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t -extern def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t +extern def read(fd: INT, buf: bytes, count: sizet) -> ssize_t +extern def write(fd: INT, buf: t.CConst | bytes, count: sizet) -> ssize_t extern def lseek(fd: INT, offset: off_t, whence: INT) -> off_t extern def unlink(path: t.CConst | str) -> INT extern def access(path: t.CConst | str, amode: INT) -> INT @@ -188,7 +188,7 @@ extern def readdir(dirp: DIR) -> Dirent | t.CPtr extern def closedir(dirp: DIR) -> INT extern def mkdir(path: t.CConst | str, mode: mode_t) -> INT extern def rmdir(path: t.CConst | str) -> INT -extern def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR +extern def getcwd(buf: CHARPTR, size: sizet) -> CHARPTR extern def chdir(path: t.CConst | str) -> INT @@ -219,46 +219,16 @@ extern def isatty(fd: INT) -> INT # ============================================================================= # st_mode type determination -def S_ISREG(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFREG - - -def S_ISDIR(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFDIR - - -def S_ISLNK(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFLNK - - -def S_ISCHR(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFCHR - - -def S_ISBLK(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFBLK - - -def S_ISFIFO(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFIFO - - -def S_ISSOCK(mode: mode_t) -> bool: - return (mode & S_IFMT) == S_IFSOCK - +def S_ISREG(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFREG +def S_ISDIR(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFDIR +def S_ISLNK(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFLNK +def S_ISCHR(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFCHR +def S_ISBLK(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFBLK +def S_ISFIFO(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFIFO +def S_ISSOCK(mode: mode_t) -> bool: return (mode & S_IFMT) == S_IFSOCK # waitpid status parsing -def WIFEXITED(status: INT) -> bool: - return (status & 0x7F) == 0 - - -def WEXITSTATUS(status: INT) -> INT: - return (status >> 8) & 0xFF - - -def WIFSIGNALED(status: INT) -> bool: - return ((status & 0x7F) != 0) and ((status & 0x7F) != 0x7F) - - -def WTERMSIG(status: INT) -> INT: - return status & 0x7F +def WIFEXITED(status: INT) -> bool: return (status & 0x7F) == 0 +def WEXITSTATUS(status: INT) -> INT: return (status >> 8) & 0xFF +def WIFSIGNALED(status: INT) -> bool: return ((status & 0x7F) != 0) and ((status & 0x7F) != 0x7F) +def WTERMSIG(status: INT) -> INT: return status & 0x7F diff --git a/random.vp b/random.vp new file mode 100644 index 0000000..25047b1 --- /dev/null +++ b/random.vp @@ -0,0 +1,301 @@ +# vrandom - Hardware Random Number Generation Library +# Implemented using inline assembly based on x86 RDRAND / RDSEED instructions +import t, c +import math + + +# Retry limit (RDRAND usually doesn't need retries, RDSEED might) +define RDRAND_RETRY_LIMIT = 10 +define RDSEED_RETRY_LIMIT = 100 + + +# ============================================================ +# RDRAND - Hardware random numbers (output from a pseudo-random number generator) +# ============================================================ +def rdrand16() -> uint16: + val: uint32 = 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 uint16(val) + +def rdrand32() -> uint32: + val: uint32 = 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() -> uint64: + val: uint64 = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +# ============================================================ +# RDSEED - Hardware random seeds (direct output from entropy source) +# ============================================================ +def rdseed16() -> uint16: + val: uint32 = 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 uint16(val) + +def rdseed32() -> uint32: + val: uint32 = 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() -> uint64: + val: uint64 = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +# ============================================================ +# Step version (with success flag, matching GCC builtin interface) +# Returns success flag: 1 on success, 0 on failure; random value written to *p +# ============================================================ +def rdrand16_step(p: rawptr[uint16]) -> int: + val: uint32 = 0 + ok: uint32 = 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] = uint16(val) + return int(ok) + +def rdrand32_step(p: rawptr[uint32]) -> int: + val: uint32 = 0 + ok: uint32 = 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 int(ok) + +def rdrand64_step(p: rawptr[uint64]) -> int: + val: uint64 = 0 + ok: uint32 = 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 int(ok) + +def rdseed16_step(p: rawptr[uint16]) -> int: + val: uint32 = 0 + ok: uint32 = 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] = uint16(val) + return int(ok) + +def rdseed32_step(p: rawptr[uint32]) -> int: + val: uint32 = 0 + ok: uint32 = 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 int(ok) + +def rdseed64_step(p: rawptr[uint64]) -> int: + val: uint64 = 0 + ok: uint32 = 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 int(ok) + + +# ============================================================ +# Convenient interface with retry (automatically retries until it succeeds or reaches the limit) +# ============================================================ +def random_u16() -> uint16: + r: uint16 = 0 + for i in range(RDRAND_RETRY_LIMIT): + if rdrand16_step(&r) == 1: return r + return 0 + +def random_u32() -> uint32: + r: uint32 = 0 + for i in range(RDRAND_RETRY_LIMIT): + if rdrand32_step(&r) == 1: return r + return 0 + +def random_u64() -> uint64: + r: uint64 = 0 + for i in range(RDRAND_RETRY_LIMIT): + if rdrand64_step(&r) == 1: return r + return 0 + +def seed_u16() -> uint16: + r: uint16 = 0 + for i in range(RDRAND_RETRY_LIMIT): + if rdseed16_step(&r) == 1: return r + return 0 + +def seed_u32() -> uint32: + r: uint32 = 0 + for i in range(RDRAND_RETRY_LIMIT): + if rdseed32_step(&r) == 1: return r + return 0 + +def seed_u64() -> uint64: + r: uint64 = 0 + for i in range(RDSEED_RETRY_LIMIT): + if rdseed64_step(&r) == 1: return r + return 0 + + +# ============================================================ +# Python random standard library function implementations +# Default types: uint64 (u64), double (f64), int (i32) +# ============================================================ +# ---------- ONE, Random integers ---------- +def randint(a: int, b: int) -> int: + return int(a + int(random_u64() % uint64(b - a + 1))) + +def randrange(start: int, stop: int, step: int = 1) -> int: + width: int = 0 + if step > 0: width = (stop - start + step - 1) // step + else: width = (start - stop - step - 1) // (-step) + return int(start + int(random_u64() % uint64(width)) * step) + +def getrandbits(k: int) -> uint64: + r: uint64 = rdrand64() + if k >= 64: return r + mask: uint64 = (uint64(1) << k) - uint64(1) + return r & mask + +# ---------- TWO, Random floating-point numbers ---------- +def random() -> double: + return double(rdrand64() >> 11) * (1.0 / 9007199254740992.0) + +def uniform(a: double, b: double) -> double: + return a + (b - a) * random() + +def triangular(low: double, high: double, mode: double) -> double: + u: double = random() + c: double = (mode - low) / (high - low) + tmp: double = 0.0 + if u > c: + u = 1.0 - u; c = 1.0 - c + tmp = low; low = high; high = tmp + return low + (high - low) * math.sqrt(u * c) + +def betavariate(alpha: double, beta: double) -> double: + y: double = gammavariate(alpha, 1.0) + if y != 0.0: return y / (y + gammavariate(beta, 1.0)) + return 0.0 + +def expovariate(lambd: double) -> double: + u: double = random() + if u < 1e-300: u = 1e-300 + return -math.log(1.0 - u) / lambd + +def gammavariate(alpha: double, beta: double) -> double: + u: double = 0.0 + d: double = 0.0 + c: double = 0.0 + x: double = 0.0 + v: double = 0.0 + if alpha <= 0.0 or beta <= 0.0: return 0.0 + if alpha < 1.0: + u = random() + if u < 1e-300: u = 1e-300 + return gammavariate(alpha + 1.0, beta) * math.pow(u, 1.0 / alpha) + d = alpha - 1.0 / 3.0 + c = 1.0 / math.sqrt(9.0 * d) + while True: + x = gauss(0.0, 1.0) + v = 1.0 + c * x + if v > 0.0: + v = v * v * v + u = random() + if u < 1.0 - 0.0331 * x * x * x * x: return d * v * beta + if math.log(u) < 0.5 * x * x + d * (1.0 - v + math.log(v)): return d * v * beta + +def gauss(mu: double, sigma: double) -> double: + u1: double = random() + u2: double = random() + if u1 < 1e-300: u1 = 1e-300 + z0: double = math.sqrt(-2.0 * math.log(u1)) * math.cos(2.0 * math.U_M_PI * u2) + return mu + sigma * z0 + +def normalvariate(mu: double, sigma: double) -> double: + NV_MAGICCONST: double = 1.7155277699214135 + u1: double = 0.0 + u2: double = 0.0 + z: double = 0.0 + zz: double = 0.0 + while True: + u1 = random() + u2 = random() + if u2 < 1e-300: continue + z = NV_MAGICCONST * (u1 - 0.5) / u2 + zz = z * z / 4.0 + if zz <= 0.0 - math.log(u2): break + return mu + z * sigma + +def lognormvariate(mu: double, sigma: double) -> double: + return math.exp(gauss(mu, sigma)) + +def vonmisesvariate(mu: double, kappa: double) -> double: + if kappa <= 1e-6: return math.U_M_PI * 2.0 * random() + s: double = 0.5 / kappa + r: double = s + math.sqrt(1.0 + s * s) + u1: double = 0.0 + u2: double = 0.0 + u3: double = 0.0 + z: double = 0.0 + d: double = 0.0 + q: double = 0.0 + f: double = 0.0 + theta: double = 0.0 + two_pi: double = math.U_M_PI * 2.0 + while True: + u1 = random() + z = math.cos(math.U_M_PI * u1) + d = 1.0 / (r + z) + u2 = random() + if (u2 < 1.0 - d * d) or (u2 < (1.0 - z) * math.exp(kappa * (z - 1.0) - d * kappa * r)): break + q = 1.0 / r + f = (q + z) / (1.0 + q * z) + u3 = random() + theta = mu + (math.acos(f) if u3 > 0.5 else -math.acos(f)) + while theta < 0.0: theta += two_pi + while theta >= two_pi: theta -= two_pi + return theta + +def paretovariate(alpha: double) -> double: + u: double = random() + if u < 1e-300: u = 1e-300 + return 1.0 / math.pow(1.0 - u, 1.0 / alpha) + +def weibullvariate(alpha: double, beta: double) -> double: + u: double = random() + if u < 1e-300: u = 1e-300 + return alpha * math.pow(-1.0 * math.log(1.0 - u), 1.0 / beta) diff --git a/requests.vp.bak b/requests.vp.bak deleted file mode 100644 index ba9f72e..0000000 --- a/requests.vp.bak +++ /dev/null @@ -1,360 +0,0 @@ -import t, c -from stdint import * -import string -import socket -import memhub -import stdio - - -# ============================================================ -# requests.py — HTTP client library (Python original style) -# -# Usage: -# requests._mbuddy = my_mbuddy -# resp = requests.get("http://example.com/path") -# if resp is not None: -# print(resp.status_code) -# print(resp.text) -# requests.release(resp) -# ============================================================ - -# Module-level global MBuddy pointer (assigned by the user in main) -_mbuddy: memhub.MemBuddy | t.CPtr - -# Socket initialization flag -_socket_ready: bool = False - -HTTP_PORT: t.CDefine = 80 -HTTP_BUFSIZ: t.CDefine = 4096 - - -# ============================================================ -# Response — HTTP response object -# ============================================================ - -class Response: - """HTTP response object, similar to how Python's requests.Response works. - - Allocated from _mbuddy, call release(resp) to free it after use. - """ - status_code: INT # HTTP status code (e.g., 200, 404) - text: str # Response body text (points into _raw_buf) - body_len: INT # Response body length - _raw_buf: str # Raw buffer pointer - - -# ============================================================ -# Internal auxiliary functions -# ============================================================ - -def _EnsureSocketInit() -> INT: - """Ensure Socket library is initialized (idempotent).""" - global _socket_ready - if _socket_ready: return 0 - result: INT = socket.SocketInit() - if result == 0: - _socket_ready = True - return result - - -def _AllocResponse() -> Response | t.CPtr: - """Allocate Response struct from _mbuddy and initialize it in-place.""" - if _mbuddy is None: return None - resp: Response | t.CPtr = _mbuddy.alloc(Response.__sizeof__()) - if resp is None: return None - resp.status_code = 0 - resp.text = None - resp.body_len = 0 - resp._raw_buf = None - return resp - - -def _ParseUrl(url: str, host_buf: str, host_size: INT, path_buf: str, path_size: INT, port: INT | t.CPtr) -> INT: - """Parse URL and extract host, port, and path.""" - if url is None: return -1 - if host_buf is None or path_buf is None or port is None: return -1 - - p: str = url - - # Skip "http://" - if string.strncmp(p, "http://", 7) == 0: - p += 7 - - # Parse host - host_start: str = p - host_len: INT = 0 - while p[0] != '\0' and p[0] != ':' and p[0] != '/': - host_len += 1 - p += 1 - - if host_len == 0 or host_len >= host_size: return -1 - string.strncpy(host_buf, host_start, host_len) - host_buf[host_len] = 0 - - # Parse port - if p[0] == ':': - p += 1 - port_val: INT = 0 - while p[0] >= '0' and p[0] <= '9': - port_val = port_val * 10 + INT(p[0] - '0') - p += 1 - c.DerefAs(port, port_val) - else: - c.DerefAs(port, HTTP_PORT) - - # Parse path - if p[0] == '/': - path_start: str = p - path_len: INT = 0 - while p[0] != '\0': - path_len += 1 - p += 1 - if path_len >= path_size: return -1 - string.strncpy(path_buf, path_start, path_len) - path_buf[path_len] = 0 - else: - if path_size < 2: return -1 - path_buf[0] = '/' - path_buf[1] = 0 - - return 0 - - -def _ParseStatusLine(resp_text: str, out_code: INT | t.CPtr) -> INT: - """Parse HTTP status line and extract status code.""" - if resp_text is None or out_code is None: return -1 - - p: str = resp_text - - # Skip "HTTP/x.x " - while p[0] != '\0' and p[0] != ' ': - p += 1 - if p[0] == ' ': p += 1 - - # Parse status code - code: INT = 0 - while p[0] >= '0' and p[0] <= '9': - code = code * 10 + INT(p[0] - '0') - p += 1 - - c.DerefAs(out_code, code) - - # Find \n - while p[0] != '\0' and p[0] != '\n': - p += 1 - if p[0] == '\n': p += 1 - - return INT(t.CUInt64T(p) - t.CUInt64T(resp_text)) - - -def _FindBodyStart(resp_text: str, resp_len: INT) -> INT: - """Find the start of the HTTP response body (after rnrn).""" - if resp_text is None: return -1 - - end_of_headers: str = string.strstr(resp_text, "\r\n\r\n") - if end_of_headers is None: - end_of_headers = string.strstr(resp_text, "\n\n") - if end_of_headers is None: - return -1 - return INT(t.CUInt64T(end_of_headers) - t.CUInt64T(resp_text)) + 2 - - return INT(t.CUInt64T(end_of_headers) - t.CUInt64T(resp_text)) + 4 - - -# ============================================================ -# 公共 API -# ============================================================ - -def get(url: str) -> Response | t.CPtr: - """HTTP GET request. - - Args: - url: Full URL (e.g., "http://example.com/path") - Returns: - Pointer to a Response object (allocated from _mbuddy), returns None on failure. - """ - if _mbuddy is None: return None - - resp: Response | t.CPtr = _AllocResponse() - if resp is None: return None - - if _EnsureSocketInit() != 0: - release(resp) - return None - - # Parse URL - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] - port: INT = 0 - - if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: - release(resp) - return None - - # Create Socket - sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) - if sock.fd == socket.INVALID_SOCKET: - release(resp) - return None - - if sock.connect(host_buf, port) != 0: - sock.close() - release(resp) - return None - - # Build HTTP request - req_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) - if req_buf is None: - sock.close() - release(resp) - return None - - stdio.snprintf(req_buf, HTTP_BUFSIZ, - "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", - path_buf, host_buf) - - req_len: INT = INT(string.strlen(req_buf)) - sent: INT = sock.send(req_buf, req_len) - _mbuddy.free(req_buf) - - if sent <= 0: - sock.close() - release(resp) - return None - - # Receive response body - resp_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) - if resp_buf is None: - sock.close() - release(resp) - return None - - total: INT = 0 - while total < HTTP_BUFSIZ - 1: - n: INT = sock.recv(resp_buf + total, HTTP_BUFSIZ - 1 - total) - if n <= 0: break - total += n - - resp_buf[total] = 0 - sock.close() - - resp._raw_buf = resp_buf - - # Parse status line - _ParseStatusLine(resp_buf, c.Addr(resp.status_code)) - - # Find body start - body_offset: INT = _FindBodyStart(resp_buf, total) - if body_offset < 0 or body_offset >= total: - resp.text = None - resp.body_len = 0 - else: - resp.text = resp_buf + body_offset - resp.body_len = total - body_offset - - return resp - - -def post(url: str, data: str = None, content_type: str = "application/x-www-form-urlencoded") -> Response | t.CPtr: - """HTTP POST request. - - Args: - url: Full URL - data: Request body data - content_type: Content-Type header (default is "application/x-www-form-urlencoded") - Returns: - Pointer to Response object (allocated from _mbuddy), returns None on failure. - """ - if _mbuddy is None: return None - - resp: Response | t.CPtr = _AllocResponse() - if resp is None: return None - - if _EnsureSocketInit() != 0: - release(resp) - return None - - # Parse URL - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] - port: INT = 0 - - if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: - release(resp) - return None - - body_len: INT = INT(string.strlen(data)) if data is not None else 0 - ct: str = content_type if content_type is not None else "application/x-www-form-urlencoded" - - # Create Socket - sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) - if sock.fd == socket.INVALID_SOCKET: - release(resp) - return None - - if sock.connect(host_buf, port) != 0: - sock.close() - release(resp) - return None - - # Build HTTP request - req_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) - if req_buf is None: - sock.close() - release(resp) - return None - - stdio.snprintf(req_buf, HTTP_BUFSIZ, - "POST %s HTTP/1.1\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\nConnection: close\r\n\r\n", - path_buf, host_buf, ct, body_len) - - hdr_len: INT = INT(string.strlen(req_buf)) - - # Send headers + body - sent: INT = sock.send(req_buf, hdr_len) - if sent > 0 and body_len > 0 and data is not None: - sock.send(data, body_len) - - _mbuddy.free(req_buf) - - # Receive response body - resp_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) - if resp_buf is None: - sock.close() - release(resp) - return None - - total: INT = 0 - while total < HTTP_BUFSIZ - 1: - n: INT = sock.recv(resp_buf + total, HTTP_BUFSIZ - 1 - total) - if n <= 0: break - total += n - - resp_buf[total] = 0 - sock.close() - - resp._raw_buf = resp_buf - - _ParseStatusLine(resp_buf, c.Addr(resp.status_code)) - body_offset: INT = _FindBodyStart(resp_buf, total) - if body_offset < 0 or body_offset >= total: - resp.text = None - resp.body_len = 0 - else: - resp.text = resp_buf + body_offset - resp.body_len = total - body_offset - - return resp - - -def release(resp: Response | t.CPtr): - """Release Response object and its internal buffers. - - Args: - resp: The Response object to release - """ - if resp is None: return - if _mbuddy is None: return - if resp._raw_buf is not None: - _mbuddy.free(resp._raw_buf) - _mbuddy.free(t.CVoid(t.CUInt64T(resp), t.CPtr)) diff --git a/requests/__init__.vp b/requests/__init__.vp index 1152ade..fb255d3 100644 --- a/requests/__init__.vp +++ b/requests/__init__.vp @@ -25,7 +25,7 @@ import zlib.pyzlib as pyzlib # ============================================================ # Module-level global MBuddy pointer (assigned by the user in main) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # Socket initialization flag _socket_ready: bool = False @@ -35,7 +35,7 @@ HTTP_BUFSIZ: t.CDefine = 4096 GZIP_BUFSIZ: t.CDefine = 65536 # 模块内重定向 / 失败诊断(静态缓冲) -_http_err_store: t.CArray[t.CChar, 512] +_http_err_store: t.CArray[char, 512] def last_error() -> str: @@ -210,10 +210,10 @@ def find_body_start(resp_text: str, resp_len: INT) -> INT: # 响应解析(header 查询 / chunked 解码 / 统一 parse_response) # ============================================================ -def _CIEq(a: t.CChar, b: t.CChar) -> bool: +def _CIEq(a: char, b: char) -> bool: """大小写不敏感字符相等(仅 ASCII)。""" - if a >= 'A' and a <= 'Z': a = t.CChar(INT(a) - INT('A') + INT('a')) - if b >= 'A' and b <= 'Z': b = t.CChar(INT(b) - INT('A') + INT('a')) + if a >= 'A' and a <= 'Z': a = char(INT(a) - INT('A') + INT('a')) + if b >= 'A' and b <= 'Z': b = char(INT(b) - INT('A') + INT('a')) return a == b @@ -268,7 +268,7 @@ def header_value(resp: Response | t.CPtr, name: str, out: str, out_size: INT) -> return -1 -def _HexVal(ch: t.CChar) -> INT: +def _HexVal(ch: char) -> INT: if ch >= '0' and ch <= '9': return INT(ch - '0') if ch >= 'a' and ch <= 'f': return INT(ch - 'a') + 10 if ch >= 'A' and ch <= 'F': return INT(ch - 'A') + 10 @@ -293,7 +293,7 @@ def decode_chunked(src: str, src_len: INT, dst: str, dst_cap: INT) -> INT: size: INT = 0 digit_seen: bool = False while r < src_len: - ch: t.CChar = src[r] + ch: char = src[r] if ch == '\r' or ch == '\n' or ch == ';': break hv: INT = _HexVal(ch) if hv < 0: return -1 @@ -343,7 +343,7 @@ def parse_response(resp: Response | t.CPtr, total: INT) -> INT: return 0 # 检测 Transfer-Encoding: chunked - te_buf: t.CArray[t.CChar, 64] + te_buf: t.CArray[char, 64] chunked: bool = False if header_value(resp, "Transfer-Encoding", te_buf, 64) == 0: if string.strstr(te_buf, "chunked") is not None: @@ -370,18 +370,18 @@ def parse_response(resp: Response | t.CPtr, total: INT) -> INT: resp.body_len = total - body_offset # ---- Content-Encoding: gzip 解压(zlib.pyzlib,纯 Viper 实现)---- - ce_buf: t.CArray[t.CChar, 64] + ce_buf: t.CArray[char, 64] if header_value(resp, "Content-Encoding", ce_buf, 64) == 0 \ and string.strstr(ce_buf, "gzip") is not None \ and resp.text is not None and resp.body_len > 0: - src_len2: t.CSizeT = t.CSizeT(resp.body_len) - olen2: t.CSizeT = 0 + src_len2: sizet = sizet(resp.body_len) + olen2: sizet = 0 gz_out: BYTEPTR = pyzlib.decompress(_mbuddy, BYTEPTR(resp.text), src_len2, 15, GZIP_BUFSIZ, c.Addr(olen2)) if gz_out is not None: old_owned: str = resp._body_owned if old_owned is not None: _mbuddy.free(old_owned) - gz_str: str = t.CChar(t.CUInt64T(gz_out), t.CPtr) + gz_str: str = char(t.CUInt64T(gz_out), t.CPtr) gz_str[olen2] = 0 resp._body_owned = gz_str resp.text = gz_str @@ -409,8 +409,8 @@ def _HttpGetOnce(url: str) -> Response | t.CPtr: return None # Parse URL - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] + host_buf: t.CArray[char, 256] + path_buf: t.CArray[char, 1024] port: INT = 0 if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: @@ -482,8 +482,8 @@ def _HttpPostOnce(url: str, data: str = None, content_type: str = "application/x return None # Parse URL - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] + host_buf: t.CArray[char, 256] + path_buf: t.CArray[char, 1024] port: INT = 0 if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: @@ -766,7 +766,7 @@ def _StatusRaw(buf: str) -> INT: def _CLenOf(buf: str, total: INT) -> INT: """读取 Content-Length(无则 -1)。""" - hbuf: t.CArray[t.CChar, 32] + hbuf: t.CArray[char, 32] if _RawHeaderValue(buf, total, "Content-Length", hbuf, 32) != 0: return -1 v: INT = 0 @@ -777,9 +777,9 @@ def _CLenOf(buf: str, total: INT) -> INT: return v -def _CRTotalOf(buf: str, total: INT) -> t.CSizeT: +def _CRTotalOf(buf: str, total: INT) -> sizet: """从 Content-Range: bytes s-e/TOTAL 解析 TOTAL(非 206/缺头则 0)。""" - hbuf: t.CArray[t.CChar, 128] + hbuf: t.CArray[char, 128] if _RawHeaderValue(buf, total, "Content-Range", hbuf, 128) != 0: return 0 p: INT = 0 @@ -788,16 +788,16 @@ def _CRTotalOf(buf: str, total: INT) -> t.CSizeT: if hbuf[p] == 0: return 0 p += 1 - v: t.CSizeT = 0 + v: sizet = 0 while hbuf[p] != 0 and hbuf[p] >= '0' and hbuf[p] <= '9': - v = v * 10 + t.CSizeT(hbuf[p] - '0') + v = v * 10 + sizet(hbuf[p] - '0') p += 1 return v -def _DlOnce(url: str, start: t.CSizeT, count: INT, dst: str, dst_cap: INT, +def _DlOnce(url: str, start: sizet, count: INT, dst: str, dst_cap: INT, out_status: INT | t.CPtr, out_loc: str, out_loccap: INT, - out_total: t.CSizeT | t.CPtr) -> INT: + out_total: sizet*) -> INT: """HTTP 单次 Range 拉取(线程安全,见模块注释)。""" if url is None or dst is None or dst_cap <= 0 \ or out_status is None or out_total is None: @@ -811,8 +811,8 @@ def _DlOnce(url: str, start: t.CSizeT, count: INT, dst: str, dst_cap: INT, _SetHttpError("socket init failed") return -3 - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] + host_buf: t.CArray[char, 256] + path_buf: t.CArray[char, 1024] port: INT = 0 if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: _SetHttpError("bad http url") @@ -835,7 +835,7 @@ def _DlOnce(url: str, start: t.CSizeT, count: INT, dst: str, dst_cap: INT, cnt: INT = count if cnt < 0: cnt = 0 - end: t.CSizeT = start + t.CSizeT(cnt) - 1 + end: sizet = start + sizet(cnt) - 1 if cnt <= 0: end = start stdio.snprintf(req, 1024, @@ -888,7 +888,7 @@ def _DlOnce(url: str, start: t.CSizeT, count: INT, dst: str, dst_cap: INT, else: cl2: INT = _CLenOf(dst, total) if cl2 > 0: - c.Set(c.Deref(out_total), t.CSizeT(cl2)) + c.Set(c.Deref(out_total), sizet(cl2)) bo: INT = _FindBodyStart(dst, total) if bo < 0 or bo >= total: return 0 diff --git a/requests/download.vp b/requests/download.vp index a83063c..79a6d45 100644 --- a/requests/download.vp +++ b/requests/download.vp @@ -36,7 +36,7 @@ DL_MAX_THREADS: t.CDefine = 8 DL_DEFAULT_CHUNK: t.CDefine = 262144 DL_REDIRECT_MAX: t.CDefine = 5 -_dl_err_store: t.CArray[t.CChar, 512] +_dl_err_store: t.CArray[char, 512] def last_error() -> str: @@ -55,7 +55,7 @@ def _dl_strdup(s: str) -> str: """stdlib 堆上复制字符串(调用方 free),None 失败。""" if s is None: return None - n: t.CSizeT = string.strlen(s) + n: sizet = string.strlen(s) out: str = stdlib.malloc(n + 1) if out is None: return None @@ -69,8 +69,8 @@ def _dl_strdup(s: str) -> str: # 单切片拉取(含重定向跟随,≤5 跳;http/https 按 scheme 分发) # ============================================================ -def _dl_slice(url: str, pos: t.CSizeT, want: INT, verify: bool, ca_file: str, - dst: str, dst_cap: INT, out_total: t.CSizeT | t.CPtr) -> INT: +def _dl_slice(url: str, pos: sizet, want: INT, verify: bool, ca_file: str, + dst: str, dst_cap: INT, out_total: sizet*) -> INT: """拉取 [pos, pos+want) 一片,返回体字节数写入 dst(dst 内正文起始需 调用方用 _dl_body_off 定位);-2 重定向超限;-3 网络/服务器失败。""" if url is None or dst is None or out_total is None: @@ -83,8 +83,8 @@ def _dl_slice(url: str, pos: t.CSizeT, want: INT, verify: bool, ca_file: str, while True: is_https: INT = 1 if (string.strncmp(cur, "https://", 8) == 0) else 0 st: INT = 0 - tot: t.CSizeT = 0 - loc: t.CArray[t.CChar, 512] + tot: sizet = 0 + loc: t.CArray[char, 512] if is_https != 0: rc = rhttps._DlOnce(cur, pos, want, verify, ca_file, dst, dst_cap, c.Addr(st), loc, 512, c.Addr(tot)) @@ -126,7 +126,7 @@ def _dl_body_off(dst: str, dst_cap: INT) -> INT: # 文件写入(按偏移落盘,支持多线程并发写不同区段) # ============================================================ -def _dl_write_at(path: str, src: str, length: INT, offset: t.CSizeT) -> INT: +def _dl_write_at(path: str, src: str, length: INT, offset: sizet) -> INT: """打开文件(不存在则创建),Seek 到 offset 写 length 字节。0 成功;-1 失败。""" if path is None or src is None or length <= 0: return -1 @@ -136,10 +136,22 @@ def _dl_write_at(path: str, src: str, length: INT, offset: t.CSizeT) -> INT: None, wf.OPEN_ALWAYS, wf.FILE_ATTRIBUTE_NORMAL, None) if h == wb.INVALID_HANDLE_VALUE: return -1 - li: wb.LARGE_INTEGER = wb.LARGE_INTEGER() - li.QuadPart = t.CLongLong(offset) - ok_seek: BOOL = wf.SetFilePointerEx(h, c.Addr(li), None, wf.FILE_BEGIN) - if ok_seek == 0: + # 用 32 位版 SetFilePointer:lDistanceToMove 按值传 LONG,无结构体 ABI 歧义。 + # 不用 SetFilePointerEx:win32file.vp:93 声明为 + # liDistanceToMove: LARGE_INTEGER | t.CPtr + # 传 c.Addr(li) 时该联合实参按"指针"传,而真实 Win32 的 liDistanceToMove 是 + # 按值传 8 字节 ⇒ 移动距离变成 li 的地址数值(与 VET 已修掉的 VFs.SeekTo 同根因, + # 见 VET/App/lib/VPe.vp:286 的绕行说明);可用先例:includes/w32/fileio.vp:169 + # 的 File.seek 就走 32 位版。 + # lpDistanceToMoveHigh=NULL ⇒ 距离限定 32 位有符号(|offset| < 2 GiB), + # 故先显式上界守卫:超范围直接判失败,绝不静默 seek 到错误位置。 + if offset > sizet(0x7FFFFFFF): + wb.CloseHandle(h) + return -1 + ok_seek: LONG = wf.SetFilePointer(h, LONG(offset), None, wf.FILE_BEGIN) + # INVALID_SET_FILE_POINTER(0xFFFFFFFF) 截断成 LONG 即 -1。因上面已把 offset + # 限制在 0..0x7FFFFFFF,0xFFFFFFFF 不可能是"合法偏移",无需再叠 GetLastError 消歧。 + if ok_seek == -1: wb.CloseHandle(h) return -1 written: ULONG = 0 @@ -169,7 +181,7 @@ def _dl_truncate(path: str) -> INT: # ============================================================ def _dl_probe(url: str, verify: bool, ca_file: str, - out_total: t.CSizeT | t.CPtr) -> INT: + out_total: sizet*) -> INT: """探测服务器总大小与 Range 支持。 返回 0=支持 Range 且 out_total 有效;1=服务器返回 200(不支持 Range, 退化为整段下载,out_total=Content-Length);-3 失败。""" @@ -178,7 +190,7 @@ def _dl_probe(url: str, verify: bool, ca_file: str, if buf is None: _dl_set_err("out of memory") return -3 - tot: t.CSizeT = 0 + tot: sizet = 0 rc: INT = _dl_slice(url, 0, 0, verify, ca_file, buf, 8192, c.Addr(tot)) stdlib.free(buf) if rc < 0: @@ -196,16 +208,16 @@ def _dl_probe(url: str, verify: bool, ca_file: str, # ============================================================ def _dl_download_band(path: str, url: str, is_https: INT, verify: bool, ca_file: str, - b_start: t.CSizeT, b_end: t.CSizeT, chunk: INT, + b_start: sizet, b_end: sizet, chunk: INT, buf: str, buf_cap: INT, - p_done: t.CSizeT | t.CPtr) -> INT: + p_done: sizet*) -> INT: """0 成功;-1 网络/服务器;-2 写入失败。p_done 累计已写字节。""" - pos: t.CSizeT = b_start + pos: sizet = b_start while pos < b_end: want: INT = chunk - if b_end - pos < t.CSizeT(want): + if b_end - pos < sizet(want): want = INT(b_end - pos) - tot: t.CSizeT = 0 + tot: sizet = 0 rc: INT = _dl_slice(url, pos, want, verify, ca_file, buf, buf_cap, c.Addr(tot)) if rc <= 0: _dl_set_err("slice fetch failed") @@ -223,8 +235,8 @@ def _dl_download_band(path: str, url: str, is_https: INT, verify: bool, ca_file: if _dl_write_at(path, buf + bo, got, pos) != 0: _dl_set_err("write file failed") return -2 - c.Set(c.Deref(p_done), c.Deref(p_done) + t.CSizeT(got)) - pos += t.CSizeT(got) + c.Set(c.Deref(p_done), c.Deref(p_done) + sizet(got)) + pos += sizet(got) if got < want: # 服务端提前结束(正常收尾时仅末片 < want) if pos >= b_end: @@ -237,20 +249,18 @@ def _dl_download_band(path: str, url: str, is_https: INT, verify: bool, ca_file: # ============================================================ # 多线程 worker # ============================================================ - -@t.Object class DlJob: path: str url: str is_https: INT verify: INT ca_file: str - start: t.CSizeT - end: t.CSizeT + start: sizet + end: sizet chunk: INT buf: str buf_cap: INT - done: t.CSizeT + done: sizet status: INT @@ -304,7 +314,7 @@ def download(url: str, path: str, threads: INT = 1, return -1 # 探测总大小与 Range 支持 - total: t.CSizeT = 0 + total: sizet = 0 prc: INT = _dl_probe(url, verify, ca_file, c.Addr(total)) if prc < 0: return -3 @@ -324,11 +334,11 @@ def download(url: str, path: str, threads: INT = 1, if threads == 1: # ---- 串行切片 ---- - buf: str = stdlib.malloc(t.CSizeT(slab)) + buf: str = stdlib.malloc(sizet(slab)) if buf is None: _dl_set_err("out of memory") return -3 - done: t.CSizeT = 0 + done: sizet = 0 rc: INT = _dl_download_band(path, url, 0, verify, ca_file, 0, total, chunk_size, buf, slab, c.Addr(done)) stdlib.free(buf) @@ -338,17 +348,17 @@ def download(url: str, path: str, threads: INT = 1, return 0 # ---- 多线程并行分带 ---- - band: t.CSizeT = (total + t.CSizeT(threads) - 1) / t.CSizeT(threads) + band: sizet = (total + sizet(threads) - 1) / sizet(threads) ctxs: t.CArray[VOIDPTR, DL_MAX_THREADS] handles: t.CArray[VOIDPTR, DL_MAX_THREADS] threads_ok: INT = 0 i: INT = 0 while i < threads: - b_start: t.CSizeT = t.CSizeT(i) * band + b_start: sizet = sizet(i) * band if b_start >= total: break - b_end: t.CSizeT = b_start + band + b_end: sizet = b_start + band if b_end > total: b_end = total job: DlJob | t.CPtr = stdlib.calloc(1, DlJob.__sizeof__()) @@ -368,7 +378,7 @@ def download(url: str, path: str, threads: INT = 1, job.end = b_end job.chunk = chunk_size job.buf_cap = slab - job.buf = stdlib.malloc(t.CSizeT(slab)) + job.buf = stdlib.malloc(sizet(slab)) if job.buf is None: stdlib.free(job.path) stdlib.free(job.url) @@ -406,7 +416,7 @@ def download(url: str, path: str, threads: INT = 1, j += 1 # 汇总结果 - total_done: t.CSizeT = 0 + total_done: sizet = 0 failed_job: INT = 0 k: INT = 0 while k < threads_ok: diff --git a/requests/https.vp b/requests/https.vp index 9cbf894..f2c472b 100644 --- a/requests/https.vp +++ b/requests/https.vp @@ -34,9 +34,9 @@ HTTPS_PORT: t.CDefine = 443 # 模块内部状态 _ossl_ready: bool = False _socket_ready: bool = False -_err_store: t.CArray[t.CChar, 512] # 最近一次失败原因(静态缓冲) -_info_store: t.CArray[t.CChar, 512] # 最近一次成功握手的 TLS 元信息 -_scratch_store: t.CArray[t.CChar, 512] # 临时拼接缓冲 +_err_store: t.CArray[char, 512] # 最近一次失败原因(静态缓冲) +_info_store: t.CArray[char, 512] # 最近一次成功握手的 TLS 元信息 +_scratch_store: t.CArray[char, 512] # 临时拼接缓冲 _last_verify_val: INT = -1 # 最近一次握手后 SSL_get_verify_result(0=通过;-1=未启用) _last_verify_flag: INT = -1 # 最近一次请求 verify 标志(1=开启;0=关闭;-1=未知) @@ -48,12 +48,12 @@ _last_verify_flag: INT = -1 # 最近一次请求 verify 标志(1= # _st_status: HTTP 状态码(失败网络路径为负错误码) # ============================================================ STREAM_CAP: t.CDefine = 262144 -_st_buf: t.CArray[t.CChar, 262144] -_st_len: t.CSizeT = 0 -_st_consumed: t.CSizeT = 0 +_st_buf: t.CArray[char, 262144] +_st_len: sizet = 0 +_st_consumed: sizet = 0 _st_state: INT = 0 _st_status: INT = 0 -_st_err: t.CArray[t.CChar, 512] +_st_err: t.CArray[char, 512] def stream_begin(): @@ -76,12 +76,12 @@ def stream_pull(out: str, cap: INT) -> INT: avail = INT(_st_len - _st_consumed) if avail > cap - 1: avail = cap - 1 - i: t.CSizeT = 0 - while i < t.CSizeT(avail): + i: sizet = 0 + while i < sizet(avail): out[i] = _st_buf[_st_consumed + i] i += 1 - out[t.CSizeT(avail)] = 0 - _st_consumed += t.CSizeT(avail) + out[sizet(avail)] = 0 + _st_consumed += sizet(avail) return avail @@ -251,8 +251,8 @@ def _HttpsRequest(method: str, url: str, verify: bool, ca_file: str, data: str, return None # ---- 解析 URL ---- - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] + host_buf: t.CArray[char, 256] + path_buf: t.CArray[char, 1024] port: INT = 0 if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: @@ -433,7 +433,7 @@ def _HttpsRequest(method: str, url: str, verify: bool, ca_file: str, data: str, # ---- 接收响应(缓冲自动翻倍增长, 支持 MB 级正文, 如 MNIST .gz 下载) ---- resp_cap: INT = requests.HTTP_BUFSIZ - resp_buf: str = requests._mbuddy.alloc(t.CSizeT(resp_cap)) + resp_buf: str = requests._mbuddy.alloc(sizet(resp_cap)) if resp_buf is None: _RecordErrorText("alloc response buffer failed") openssl.SSL_free(ssl) @@ -451,7 +451,7 @@ def _HttpsRequest(method: str, url: str, verify: bool, ca_file: str, data: str, if resp_cap >= 268435456: break resp_cap = resp_cap * 2 - nb: t.CPtr = requests._mbuddy.realloc(resp_buf, t.CSizeT(resp_cap)) + nb: t.CPtr = requests._mbuddy.realloc(resp_buf, sizet(resp_cap)) if nb is None: _RecordErrorText("realloc response buffer failed") requests._mbuddy.free(resp_buf) @@ -461,7 +461,7 @@ def _HttpsRequest(method: str, url: str, verify: bool, ca_file: str, data: str, requests._mbuddy.free(errmsg) requests.release(resp) return None - resp_buf = t.CChar(t.CUInt64T(nb), t.CPtr) + resp_buf = char(t.CUInt64T(nb), t.CPtr) room = resp_cap - 1 - total n: INT = openssl.SSL_read(ssl, resp_buf + total, room) if n <= 0: @@ -623,10 +623,10 @@ def _StreamAppendContent(txt: str): global _st_len if txt is None: return - pos: t.CSizeT = _st_len - i: t.CSizeT = 0 + pos: sizet = _st_len + i: sizet = 0 while txt[i] != 0: - if pos >= t.CSizeT(STREAM_CAP) - 1: + if pos >= sizet(STREAM_CAP) - 1: break _st_buf[pos] = txt[i] pos += 1 @@ -666,8 +666,8 @@ def post_stream(url: str, data: str, content_type: str = "application/json", if errmsg is None: return -1 - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] + host_buf: t.CArray[char, 256] + path_buf: t.CArray[char, 1024] port: INT = 0 if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: stdio.snprintf(errmsg, 512, "bad https url: %s", url) @@ -822,7 +822,7 @@ def post_stream(url: str, data: str, content_type: str = "application/json", return -1 jpool: rawptr[memhub.MemPool] = memhub.MemPool(pmem, 524288) - leftover: t.CArray[t.CChar, 16384] + leftover: t.CArray[char, 16384] llen: INT = 0 header_done: INT = 0 status_code: INT = 0 @@ -929,10 +929,10 @@ def post_stream(url: str, data: str, content_type: str = "application/json", # -3 其它失败(last_error() 查看原因)。 # ============================================================ -def _DlOnce(url: str, start: t.CSizeT, count: INT, verify: bool, ca_file: str, +def _DlOnce(url: str, start: sizet, count: INT, verify: bool, ca_file: str, dst: str, dst_cap: INT, out_status: INT | t.CPtr, out_loc: str, out_loccap: INT, - out_total: t.CSizeT | t.CPtr) -> INT: + out_total: sizet*) -> INT: """HTTPS 单次 Range 拉取(线程安全,见模块注释)。""" global _last_verify_val, _last_verify_flag if url is None or dst is None or dst_cap <= 0 \ @@ -947,8 +947,8 @@ def _DlOnce(url: str, start: t.CSizeT, count: INT, verify: bool, ca_file: str, if _EnsureReady() != 0: return -3 - host_buf: t.CArray[t.CChar, 256] - path_buf: t.CArray[t.CChar, 1024] + host_buf: t.CArray[char, 256] + path_buf: t.CArray[char, 1024] port: INT = 0 if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: _RecordErrorText("bad https url") @@ -1023,7 +1023,7 @@ def _DlOnce(url: str, start: t.CSizeT, count: INT, verify: bool, ca_file: str, cnt: INT = count if cnt < 0: cnt = 0 - end: t.CSizeT = start + t.CSizeT(cnt) - 1 + end: sizet = start + sizet(cnt) - 1 if cnt <= 0: end = start stdio.snprintf(req, 1024, @@ -1082,7 +1082,7 @@ def _DlOnce(url: str, start: t.CSizeT, count: INT, verify: bool, ca_file: str, else: cl2: INT = requests._CLenOf(dst, total) if cl2 > 0: - c.Set(c.Deref(out_total), t.CSizeT(cl2)) + c.Set(c.Deref(out_total), sizet(cl2)) bo: INT = requests._FindBodyStart(dst, total) if bo < 0 or bo >= total: return 0 diff --git a/rwlock.vp b/rwlock.vp index 3d0ae58..c7b99ec 100644 --- a/rwlock.vp +++ b/rwlock.vp @@ -8,7 +8,6 @@ from w32.win32sync import ( ) -@t.Object class RWLock: """SRWLock-based read-write lock that supports multiple readers and single writer, but does not support recursion. diff --git a/shutil.vp b/shutil.vp index 2ba97d4..8e4ff1d 100644 --- a/shutil.vp +++ b/shutil.vp @@ -13,10 +13,10 @@ import posix # File copy buffer size -COPY_BUF_SIZE: t.CDefine = 65536 # 2^16 +define COPY_BUF_SIZE = 65536 # 2^16 # Module-level global MBuddy pointer (initialized by the user in main) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= @@ -56,7 +56,7 @@ def _copyfile_posix(src: str, dst: str) -> int: 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)) + written: ssize_t = posix.write(fd_out, buf, sizet(n)) if written < 0: result = -1 break @@ -109,12 +109,12 @@ def rmtree(path: str) -> int: def _rmtree_win32(path: str) -> int: """Windows: Recursively delete a directory tree using FindFirstFileA/FindNextFileA.""" - path_len: t.CSizeT = len(path) + path_len: sizet = len(path) # Construct search pattern path\* pattern: bytes = _mbuddy.alloc(path_len + 3) if pattern == None: return -1 - i: t.CSizeT = 0 + i: sizet = 0 for ch in path: pattern[i] = ch i += 1 @@ -145,12 +145,12 @@ def _rmtree_win32(path: str) -> int: skip = True if not skip: # Construct full path path\name - name_len: t.CSizeT = len(name) + name_len: sizet = len(name) full_path: bytes = _mbuddy.alloc(path_len + name_len + 2) if full_path == None: result = -1 else: - j: t.CSizeT = 0 + j: sizet = 0 for ch in path: full_path[j] = ch j += 1 @@ -191,7 +191,7 @@ def _rmtree_posix(path: str) -> int: if dirp == None: return -1 - path_len: t.CSizeT = len(path) + path_len: sizet = len(path) result: int = 0 entry: rawptr[posix.Dirent] = posix.readdir(dirp) while entry != None: @@ -205,12 +205,12 @@ def _rmtree_posix(path: str) -> int: skip = True if not skip: # Construct full path path/name - name_len: t.CSizeT = len(name) + name_len: sizet = len(name) full_path: bytes = _mbuddy.alloc(path_len + name_len + 2) if full_path == None: result = -1 else: - j: t.CSizeT = 0 + j: sizet = 0 for ch in path: full_path[j] = ch j += 1 diff --git a/socket.vp b/socket.vp index 5513e3c..81703ca 100644 --- a/socket.vp +++ b/socket.vp @@ -27,27 +27,27 @@ import w32.winsock2 # ============================================================ # Constants # ============================================================ -AF_INET: t.CDefine = 2 -AF_INET6: t.CDefine = 10 +define AF_INET = 2 +define AF_INET6 = 10 -SOCK_STREAM: t.CDefine = 1 -SOCK_DGRAM: t.CDefine = 2 -SOCK_RAW: t.CDefine = 3 +define SOCK_STREAM = 1 +define SOCK_DGRAM = 2 +define SOCK_RAW = 3 -IPPROTO_TCP: t.CDefine = 6 -IPPROTO_UDP: t.CDefine = 17 +define IPPROTO_TCP = 6 +define IPPROTO_UDP = 17 -SOL_SOCKET: t.CDefine = 1 -SO_RCVTIMEO: t.CDefine = 20 -SO_SNDTIMEO: t.CDefine = 21 -SO_REUSEADDR: t.CDefine = 2 +define SOL_SOCKET = 1 +define SO_RCVTIMEO = 20 +define SO_SNDTIMEO = 21 +define SO_REUSEADDR = 2 -INADDR_ANY: t.CDefine = 0 +define INADDR_ANY = 0 -SOCKET_ERROR: t.CDefine = -1 -INVALID_SOCKET: t.CDefine = -1 +define SOCKET_ERROR = -1 +define INVALID_SOCKET = -1 -SOCKET_DEFAULT_TIMEOUT: t.CDefine = 0 +define SOCKET_DEFAULT_TIMEOUT = 0 # ============================================================ @@ -57,24 +57,24 @@ SOCKET_DEFAULT_TIMEOUT: t.CDefine = 0 class SocketAddr: """sockaddr_in — IPv4 address (16 bytes layout)""" family: u16 - port: u16 - addr: u32 - zero: u64 + port: u16 + addr: u32 + zero: u64 class HostEnt: """struct hostent — DNS resolution result""" - h_name: CHARPTR - h_aliases: CHARPTR - h_addrtype: INT - h_length: INT - h_addr_list: CHARPTR + h_name: str + h_aliases: bytes + h_addrtype: int + h_length: int + h_addr_list: bytes class timeval: """struct timeval — Timeout setting""" - tv_sec: INT - tv_usec: INT + tv_sec: int + tv_usec: int # ============================================================ @@ -126,16 +126,16 @@ def _MakeAddr(host: str, port: INT) -> SocketAddr: he_raw: rawptr[w32.winsock2.WSAHostEnt] = 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))) + # 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))) if ip_ptr != 0: - addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr))) + addr.addr = u32(c.Deref(uint32(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))) + ip_ptr: u64 = u64(c.Deref(uint64(he.h_addr_list, t.CPtr))) if ip_ptr != 0: - addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr))) + addr.addr = u32(c.Deref(uint32(ip_ptr, t.CPtr))) return addr @@ -273,7 +273,7 @@ class Socket: total: INT = 0 while total < length: - n: INT = self.send(t.CPtr(t.CUInt64T(data) + total), length - total) + n: INT = self.send(t.CPtr(uint64(data) + total), length - total) if n <= 0: return SOCKET_ERROR total += n return 0 diff --git a/spinlock.vp b/spinlock.vp index b16ecb3..d9bb101 100644 --- a/spinlock.vp +++ b/spinlock.vp @@ -1,16 +1,15 @@ -import t, c import atom class _spinlock: - locked: t.CVolatile | t.CInt - name: t.CArray[t.CChar, 32] + locked: volatile int = 0 + name: [32]char def __init__(self): - self.locked = 0 + pass def lock(self): - while atom.__atomic_test_and_set(c.Addr(self.locked), atom.ATOMIC_ACQUIRE): pass + while atom.__atomic_test_and_set(&self.locked, atom.ATOMIC_ACQUIRE): pass def unlock(self): - atom.__atomic_clear(c.Addr(self.locked), atom.ATOMIC_RELEASE) + atom.__atomic_clear(&self.locked, atom.ATOMIC_RELEASE) diff --git a/stdint.vp b/stdint.vp index 029f8c8..a2fd321 100644 --- a/stdint.vp +++ b/stdint.vp @@ -88,7 +88,7 @@ u16: t.CTypedef = t.CUInt16T u32: t.CTypedef = t.CUInt32T u64: t.CTypedef = t.CUInt64T -SIZE_T: t.CTypedef = t.CSizeT +SIZE_T: t.CTypedef = sizet SSIZE_T: t.CTypedef = t.CPtrDiffT PTRDIFF_T: t.CTypedef = t.CPtrDiffT @@ -108,7 +108,7 @@ uint16_t: t.CTypedef = t.CUInt16T uint32_t: t.CTypedef = t.CUInt32T uint64_t: t.CTypedef = t.CUInt64T -size_t: t.CTypedef = t.CSizeT +size_t: t.CTypedef = sizet ssize_t: t.CTypedef = t.CPtrDiffT ptrdiff_t: t.CTypedef = t.CPtrDiffT diff --git a/stdio.vp b/stdio.vp index a74d249..873fd3a 100644 --- a/stdio.vp +++ b/stdio.vp @@ -4,7 +4,7 @@ import t, c extern def printf(fmt: t.CConst | str, *args) -> int extern def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> int extern def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> int -extern def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> int +extern def snprintf(buf: bytes, size: sizet, fmt: t.CConst | str, *args) -> int extern def puts(s: t.CConst | str) -> int extern def fputs(s: t.CConst | str, stream: bytes) -> int extern def fgets(buf: bytes, size: int, stream: bytes) -> bytes diff --git a/stdlib.vp b/stdlib.vp index 104b73d..68b6959 100644 --- a/stdlib.vp +++ b/stdlib.vp @@ -2,9 +2,9 @@ from stdint import * import t -extern def malloc(size: t.CSizeT) -> t.CPtr -extern def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CPtr -extern def realloc(p: t.CPtr, size: t.CSizeT) -> t.CPtr +extern def malloc(size: sizet) -> t.CPtr +extern def calloc(nmemb: sizet, size: sizet) -> t.CPtr +extern def realloc(p: t.CPtr, size: sizet) -> t.CPtr extern def free(p: t.CPtr) extern def system(cmd: t.CConst | str) -> int extern def exit(status: int) diff --git a/string.vp b/string.vp index 1df884c..d4d7ed8 100644 --- a/string.vp +++ b/string.vp @@ -30,10 +30,10 @@ def strcat(dest: str, src: str) -> str: # String copy function with limited length -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: +def strncpy(dest: str, src: str, n: sizet) -> str: if dest == None or src == None or n == 0: return dest original_dest: str = dest - i: t.CSizeT = 0 + i: sizet = 0 for s in src: if i >= n: break dest[0] = s @@ -48,14 +48,14 @@ def strncpy(dest: str, src: str, n: t.CSizeT) -> str: # String concatenate function with limited length -def strncat(dest: str, src: str, n: t.CSizeT) -> str: +def strncat(dest: str, src: str, n: sizet) -> str: if dest == None or src == None or n == 0: return dest original_dest: str = dest # Find end of dest while dest[0] != '\0': dest += 1 # Copy up to n chars from src - i: t.CSizeT = 0 + i: sizet = 0 for s in src: if i >= n: break dest[0] = s @@ -66,8 +66,8 @@ def strncat(dest: str, src: str, n: t.CSizeT) -> str: # String length function -export def strlen(src: str) -> t.CSizeT: - length: t.CSizeT = 0 +export def strlen(src: str) -> sizet: + length: sizet = 0 for _ in src: length += 1 return length @@ -95,12 +95,12 @@ def samestr(str1: str, str2: str) -> bool: # String compare function with limited length -def strncmp(str1: str, str2: str, n: t.CSizeT) -> int: +def strncmp(str1: str, str2: str, n: sizet) -> int: # 指针相等短路(同 strcmp):相同指针在任意 n 下比较结果恒为 0(相同字符串 # 的前 n 个字符必然相等),直接返回 0,语义严格不变。 if str1 == str2: return 0 - i: t.CSizeT = 0 + i: sizet = 0 while str1[0] != '\0' and str2[0] != '\0' and i < n: if str1[0] != str2[0]: return int(str1[0]) - int(str2[0]) @@ -113,10 +113,10 @@ def strncmp(str1: str, str2: str, n: t.CSizeT) -> int: # Memory compare function -def memcmp(ptr1: t.CPtr, ptr2: t.CPtr, n: t.CSizeT) -> int: +def memcmp(ptr1: t.CPtr, ptr2: t.CPtr, n: sizet) -> int: p1: BYTEPTR = BYTEPTR(ptr1) p2: BYTEPTR = BYTEPTR(ptr2) - i: t.CSizeT = 0 + i: sizet = 0 while i < n: if p1[i] != p2[i]: return int(p1[i]) - int(p2[i]) @@ -127,7 +127,7 @@ def memcmp(ptr1: t.CPtr, ptr2: t.CPtr, n: t.CSizeT) -> int: # String find function def strchr(s: str, cr: int) -> str: while s[0] != '\0': - if s[0] == t.CChar(cr): + if s[0] == char(cr): return str(s) s += 1 if cr == '\0': @@ -138,7 +138,7 @@ def strchr(s: str, cr: int) -> str: def strrchr(s: str, cr: int) -> str: last: str = None while s[0] != '\0': - if s[0] == t.CChar(cr): + if s[0] == char(cr): last = s s += 1 if cr == '\0': return s @@ -154,7 +154,7 @@ def strrchr(s: str, cr: int) -> str: def strstr(s: str, needle: str) -> str: if needle[0] == 0: return s - needle_len: t.CSizeT = strlen(needle) + needle_len: sizet = strlen(needle) if needle_len == 0: return s first_ch: int = int(needle[0]) @@ -184,10 +184,10 @@ def strspn(s: str, skip: str = " ") -> int: return si # Memory set function -export def memset(ptr: t.CPtr, value: int, num: t.CSizeT) -> t.CPtr: +export def memset(ptr: t.CPtr, value: int, num: sizet) -> t.CPtr: # Original implementation: # p: BYTEPTR = BYTEPTR(ptr) - # i: t.CSizeT + # i: sizet # for i in range(num): # p[i] = t.CUnsignedChar(value) if num == 0: return ptr @@ -200,10 +200,10 @@ export def memset(ptr: t.CPtr, value: int, num: t.CSizeT) -> t.CPtr: return ptr -def memset32(ptr: t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CPtr: +def memset32(ptr: t.CPtr, value: t.CUInt32T, count: sizet) -> t.CPtr: # Original implementation: # p: UINT32PTR = UINT32PTR(ptr) - # i: t.CSizeT + # i: sizet # for i in range(count): # p[i] = value if count == 0: return ptr @@ -217,11 +217,11 @@ def memset32(ptr: t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CPtr: # Memory copy function -export def memcpy(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr: +export def memcpy(dest: t.CPtr, src: t.CPtr, num: sizet) -> t.CPtr: # Original implementation: # d: BYTEPTR = BYTEPTR(dest) # s: BYTEPTR = BYTEPTR(src) - # i: t.CSizeT + # i: sizet # for i in range(num): # d[i] = s[i] if num == 0: return dest @@ -235,11 +235,11 @@ export def memcpy(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr: # 内存移动函数 -def memmove(dest: t.CPtr, src: t.CPtr, num: t.CSizeT) -> t.CPtr: +def memmove(dest: t.CPtr, src: t.CPtr, num: sizet) -> t.CPtr: # 原始实现: # d: BYTEPTR = BYTEPTR(dest) # s: BYTEPTR = BYTEPTR(src) - # i: t.CSizeT + # i: sizet # if d < s: # for i in range(num): # d[i] = s[i] @@ -486,7 +486,7 @@ def atof(src: str) -> double: started: int = 0 rounded: int = 0 while s[0] != '\0': - ch: t.CChar = s[0] + ch: char = s[0] if ch >= '0' and ch <= '9': d: int = ch - '0' if started == 0: @@ -604,7 +604,7 @@ def split(s: str, delim: str, result: t.CArray[str], cap: int) -> int: return 0 if cap <= 0: return 0 - d: t.CChar = delim[0] # 单分隔符 + d: char = delim[0] # 单分隔符 while start[0]: # 跳过分隔符 diff --git a/subprocess.vp b/subprocess.vp index b5969cd..b29c9ce 100644 --- a/subprocess.vp +++ b/subprocess.vp @@ -18,7 +18,7 @@ import posix OUTPUT_BUF_SIZE: t.CDefine = 65536 # Module global MBuddy pointer (initialized in main) -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= @@ -64,11 +64,11 @@ def run(args: str, capture_output: bool = True, text: bool = True) -> CompletedP def _run_win32(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: """Windows platform subprocess execution (CreateProcessA pipe)""" # Copy command line (CreateProcessA requires a modifiable lpCommandLine) - args_len: t.CSizeT = len(args) + args_len: sizet = len(args) cmd_line: bytes = _mbuddy.alloc(args_len + 1) if cmd_line == None: return CompletedProcess(args, -1, None, None) - i: t.CSizeT = 0 + i: sizet = 0 for ch in args: cmd_line[i] = ch i += 1 @@ -142,7 +142,7 @@ def _run_win32(args: str, capture_output: bool, text: bool) -> CompletedProcess buf: bytes = _mbuddy.alloc(buf_size) if buf != None: total: ULONG = 0 - while 1: + while True: bytes_read: ULONG = 0 read_result: BOOL = w32.win32file.ReadFile( stdout_read, diff --git a/sys.vp b/sys.vp index b48430d..035c006 100644 --- a/sys.vp +++ b/sys.vp @@ -1,4 +1,4 @@ -import t, c +import t from stdint import * import platmacro import memhub @@ -13,15 +13,14 @@ import w32.win32process import posix # Module global MBuddy pointer (initialized in user main), Plans to ban -_mbuddy: rawptr[memhub.MemBuddy] +_mbuddy: memhub.MemBuddy* # ============================================================================= # C Standard Library IO Declarations # ============================================================================= - -extern def fgets(buf: bytes, size: int, stream: t.CPtr) -> str -extern def fflush(stream: t.CPtr) -> int +extern def fgets(buf: bytes, size: int, stream: rawptr) -> str +extern def fflush(stream: rawptr) -> int # C standard library exit (terminates the process after flushing the buffer, cross-platform) extern def exit(status: int) @@ -29,81 +28,60 @@ extern def exit(status: int) # ============================================================================= # Platform Information # ============================================================================= - # Maximum integer value (64-bit platform ssize_t upper limit) -maxsize: t.CDefine = 9223372036854775807 # 2^63 - 1 +define maxsize = 9223372036854775807 # 2^63 - 1 def platform() -> str: """Returns the platform identifier string ('win32' or 'linux').""" - if platmacro.IS_WINDOWS: - return "win32" + if platmacro.IS_WINDOWS: return "win32" return "linux" # ============================================================================= # Process Information # ============================================================================= - def get_pid() -> int: """返回当前进程 ID""" - if platmacro.IS_WINDOWS: - return w32.win32process.GetCurrentProcessId() + if platmacro.IS_WINDOWS: return w32.win32process.GetCurrentProcessId() return posix.getpid() # ============================================================================= # Command Line Arguments (argv) # ============================================================================= - # global argv status (initialized on first access) _argc: int = 0 -# _argv is a pointer array (char**), must use str | t.CPtr to index with sizeof(char*) -# str | t.CPtr is a pointer to char** -# bytes | t.CPtr is a pointer to char** -_argv: str | t.CPtr +_argv: str* def _init_argv(): """Initialize global argv once on first access""" global _argc, _argv - if _argc != 0: - return - if platmacro.IS_WINDOWS: - _init_argv_win32() - else: - _init_argv_posix() + if _argc != 0: return + _init_argv_win32() if platmacro.IS_WINDOWS else _init_argv_posix() def _init_argv_win32(): """Windows: GetCommandLineA + manual parsing (handle spaces/double quotes/backslashes)""" global _argc, _argv - cmdline: CHARPTR = w32.win32base.GetCommandLineA() - if cmdline == None: - return - cmdlen: t.CSizeT = string.strlen(cmdline) - if cmdlen == 0: - return - + cmdline: str = w32.win32base.GetCommandLineA() + if cmdline == None: return + cmdlen: sizet = len(cmdline) + if cmdlen == 0: return # Allocate buffer for parameter strings (worst case: entire command line + argc \0s) buf: bytes = _mbuddy.alloc(cmdlen + 1) - if buf == None: - return - + if buf == None: return # Allocate pointer array for argv (worst case: each character is a parameter) - max_args: t.CSizeT = cmdlen + 1 - argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(max_args * platmacro.SIZEOF_POINTER)) - if argv_arr == None: - return - - argc: INT = 0 - i: t.CSizeT = 0 - j: t.CSizeT = 0 + max_args: sizet = cmdlen + 1 + argv_arr: str* = str*(_mbuddy.alloc(max_args * platmacro.SIZEOF_POINTER)) + if argv_arr == None: return + argc: int = 0 + j: sizet = 0 in_quote: bool = False in_arg: bool = False - - while i < cmdlen: - ch: t.CInt = cmdline[i] + for i in range(cmdlen): + ch: int = cmdline[i] if ch == 34: # Double quote in_quote = not in_quote if not in_arg: @@ -123,11 +101,7 @@ def _init_argv_win32(): in_arg = True buf[j] = ch j += 1 - i += 1 - - if in_arg: - buf[j] = 0 - + if in_arg: buf[j] = 0 _argc = argc _argv = argv_arr @@ -135,64 +109,47 @@ def _init_argv_win32(): def _init_argv_posix(): """POSIX: Read cmdline from /proc/self/cmdline (\0) separated parameters""" global _argc, _argv - fd: INT = posix.open("/proc/self/cmdline", posix.O_RDONLY, 0) - if fd < 0: - return - + fd: int = posix.open("/proc/self/cmdline", posix.O_RDONLY, 0) + if fd < 0: return # Read cmdline (4KB) buf: bytes = _mbuddy.alloc(4096) # Need to verify size of buffer if buf == None: posix.close(fd) return - total: ssize_t = posix.read(fd, buf, 4096) posix.close(fd) - if total <= 0: - return - + if total <= 0: return # Calculate argument count (\0 delimited) - argc: INT = 0 - i: t.CSizeT = 0 - total_size: t.CSizeT = t.CSizeT(total) - while i < total_size: - if buf[i] == 0: - argc += 1 - i += 1 - - if argc == 0: - return - + argc: int = 0 + total_size: sizet = sizet(total) + for i in range(total_size): + if buf[i] == 0: argc += 1 + if argc == 0: return # Allocate pointer array for argv (argc pointers) - argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(argc * platmacro.SIZEOF_POINTER)) - if argv_arr == None: - return - + argv_arr: str* = str*(_mbuddy.alloc(argc * platmacro.SIZEOF_POINTER)) + if argv_arr == None: return # Populate pointer array (start address of each parameter) argv_arr[0] = str(buf) - idx: INT = 1 + idx: int = 1 i = 0 while i < total_size and idx < argc: if buf[i] == 0: argv_arr[idx] = str(buf + i + 1) idx += 1 i += 1 - _argc = argc _argv = argv_arr def argc() -> int: """Returns the number of command line arguments. Automatically initializes on the first call.""" - if _argc == 0: - _init_argv() + if _argc == 0: _init_argv() return _argc def argv(index: int) -> str: """Returns the command line argument at index `index` (starting from 0). Automatically initializes on first call. Returns None if the index is out of range.""" - if _argc == 0: - _init_argv() - if index < 0 or index >= _argc: - return None + if _argc == 0: _init_argv() + if index < 0 or index >= _argc: return None return _argv[index] diff --git a/testcheck.vp b/testcheck.vp index 97a7622..f747567 100644 --- a/testcheck.vp +++ b/testcheck.vp @@ -4,7 +4,8 @@ import t, c import stdio from w32.win32console import SetConsoleOutputCP, SetConsoleCP -CP_UTF8: t.CDefine = 65001 + +define CP_UTF8 = 65001 _pass_count: int = 0 _fail_count: int = 0 diff --git a/this.vp b/this.vp index 8c93b93..866b74e 100644 --- a/this.vp +++ b/this.vp @@ -1,8 +1,6 @@ -import stdio, t, c +import stdio - -def this(): - s: str = """Ivcre Cevapvcyrf, ol GrezvArkhf +s: str = """Ivcre Cevapvcyrf, ol GrezvArkhf Ornhgl orngf htyvarff. Rkcyvpvg orngf vzcyvpvg. @@ -25,15 +23,13 @@ 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!""" +def this(): # ASCII - m: t.CArray[t.CChar, 256] = [0] - l: t.CArray[int, 2] = [65, 97] - + m: [256]char = [0] for k in [65, 97]: for i in range(26): m[k + i] = (k + ((i + 13) % 26)) # Implicit type conversion - for ch in s: - _: t.CUInt8T = ch + _: uint8 = ch stdio.printf("%c", m[_] if m[_] else ch) stdio.printf("\n") diff --git a/torch/__init__.vp b/torch/__init__.vp index ef9e296..83d6003 100644 --- a/torch/__init__.vp +++ b/torch/__init__.vp @@ -21,7 +21,7 @@ import t, c import stdlib import string import stdio -import vipermath +import math import vipersimd import memhub @@ -29,8 +29,7 @@ import memhub # ------------------------------------------------------------ # Tensor # ------------------------------------------------------------ -@t.NoVTable -class Tensor: +novirtual class Tensor: Data: t.CPtr # rows*cols*8 字节连续 double Grad: t.CPtr # 同尺寸梯度(可为 None) Rows: sizet @@ -40,7 +39,7 @@ class Tensor: TENSOR_SIZE: t.CDefine = 32 -def _zeros_block(pool: rawptr[memhub.MemBuddy], bytes_n: sizet) -> t.CPtr: +def _zeros_block(pool: memhub.MemBuddy*, bytes_n: sizet) -> t.CPtr: """分配并清零一块内存""" p: t.CPtr = pool.alloc(bytes_n) if p is not None: @@ -48,7 +47,7 @@ def _zeros_block(pool: rawptr[memhub.MemBuddy], bytes_n: sizet) -> t.CPtr: return p -def zeros(pool: rawptr[memhub.MemBuddy], rows: sizet, +def zeros(pool: memhub.MemBuddy*, rows: sizet, cols: sizet, with_grad: int = 1) -> Tensor | t.CPtr: """torch.zeros: 创建 rows x cols 的全零 Tensor, 可选分配 Grad 缓冲""" if pool is None: @@ -68,7 +67,7 @@ def zeros(pool: rawptr[memhub.MemBuddy], rows: sizet, return t0 -def from_raw(pool: rawptr[memhub.MemBuddy], data: t.CPtr, +def from_raw(pool: memhub.MemBuddy*, data: t.CPtr, rows: sizet, cols: sizet, with_grad: int = 0) -> Tensor | t.CPtr: """torch.from_raw: 包装一块已有内存为 Tensor(不复制, 不拥有)""" @@ -151,7 +150,7 @@ def manual_seed(seed: int64): def _next_rand() -> double: """(0,1) 均匀随机""" global _rng_state - _rng_state = vipermath.fmod(_rng_state * LCG_A, LCG_M) + _rng_state = math.fmod(_rng_state * LCG_A, LCG_M) return _rng_state / LCG_M @@ -171,7 +170,7 @@ def uniform_fill(t0: Tensor | t.CPtr, lo: double, hi: double): def kaiming_uniform_fill(w: Tensor | t.CPtr, fan_in: sizet, fan_out: sizet): """PyTorch Linear 默认初始化: U(-sqrt(6/(fan_in+fan_out)), +...)""" - bound: double = vipermath.sqrt( + bound: double = math.sqrt( double(6.0) / double(fan_in + fan_out)) uniform_fill(w, -bound, bound) @@ -391,15 +390,15 @@ def softmax_crossentropy(logits: Tensor | t.CPtr, s: double = double(0.0) j = 0 while j < c: - s = s + vipermath.exp(ld[b * c + j] - mx) + s = s + math.exp(ld[b * c + j] - mx) j += 1 y: int = lb[b] # loss += -(logits[lab] - max - log(s)) - total = total - (ld[b * c + sizet(y)] - mx - vipermath.log(s)) + total = total - (ld[b * c + sizet(y)] - mx - math.log(s)) # 梯度: (softmax - onehot) / m j = 0 while j < c: - p: double = vipermath.exp(ld[b * c + j] - mx) / s + p: double = math.exp(ld[b * c + j] - mx) / s o: double = double(0.0) if sizet(y) == j: o = double(1.0) diff --git a/vector.vp b/vector.vp index b2b7097..0af980b 100644 --- a/vector.vp +++ b/vector.vp @@ -4,13 +4,13 @@ import memhub class Vector[T](): - data: t.CPtr - length: t.CSizeT - capacity: t.CSizeT - elem_size: t.CSizeT - pool: rawptr[memhub.MemManager] + data: bytes + length: sizet + capacity: sizet + elem_size: sizet + pool: memhub.MemManager* - def __init__(self, pool: rawptr[memhub.MemManager], capacity: t.CSizeT, _hint: T): + def __init__(self, pool: memhub.MemManager*, capacity: sizet, _hint: T): self.elem_size = T.__sizeof__() self.capacity = capacity self.length = 0 @@ -22,35 +22,35 @@ class Vector[T](): 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.CPtr = t.CPtr(offset) - c.DerefAs(dst, value) + offset: uint64 = uint64(self.data) + self.length * self.elem_size + dst: rawptr = rawptr(offset) + *dst = value self.length += 1 def _grow(self): if self.pool == None: return - new_capacity: t.CSizeT = self.capacity * 2 + new_capacity: sizet = self.capacity * 2 if new_capacity == 0: new_capacity = 4 - new_size: t.CSizeT = new_capacity * self.elem_size - new_data: t.CPtr = self.pool.realloc(self.data, new_size) + new_size: sizet = new_capacity * self.elem_size + new_data: rawptr = self.pool.realloc(self.data, new_size) if new_data == None: return self.data = new_data self.capacity = new_capacity - def get(self, index: t.CSizeT) -> T: + def get(self, index: sizet) -> 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) + offset: uint64 = uint64(self.data) + index * self.elem_size + typed_ptr = (T*)offset + return *typed_ptr - def set(self, index: t.CSizeT, value: T): + def set(self, index: sizet, 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.CPtr = t.CPtr(offset) - c.DerefAs(dst, value) + offset: uint64 = uint64(self.data) + index * self.elem_size + dst: rawptr = rawptr(offset) + *dst = value - def len(self) -> t.CSizeT: + def len(self) -> sizet: return self.length def clear(self): diff --git a/viperio.vp b/viperio.vp index 48157bc..980d429 100644 --- a/viperio.vp +++ b/viperio.vp @@ -3,12 +3,12 @@ from stdint import * class Buf: - data: t.CChar | t.CPtr - length: t.CSizeT - capacity: t.CSizeT + data: char | t.CPtr + length: sizet + capacity: sizet owned: bool - def __init__(self, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT = 0, owned: bool = False): + def __init__(self, data: char | t.CPtr, capacity: sizet, length: sizet = 0, owned: bool = False): self.data = data self.capacity = capacity self.length = length @@ -19,14 +19,14 @@ class Buf: 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: + def write(self, src: char | t.CPtr, count: sizet) -> sizet: if self.data == None: return 0 if src == None: return 0 if count == 0: return 0 - avail: t.CSizeT = self.capacity - self.length + avail: sizet = self.capacity - self.length if avail <= 0: return 0 - n: t.CSizeT = count if count < avail else avail - i: t.CSizeT = 0 + n: sizet = count if count < avail else avail + i: sizet = 0 while i < n: self.data[self.length + i] = src[i] i += 1 @@ -36,7 +36,7 @@ class Buf: self.data[self.length] = 0 return n - def cstr(self) -> t.CChar | t.CPtr: + def cstr(self) -> char | t.CPtr: return self.data def reset(self): diff --git a/viperlib.vp b/viperlib.vp index a1689e4..4a8d1e3 100644 --- a/viperlib.vp +++ b/viperlib.vp @@ -2,10 +2,10 @@ import t, c import viperio from stdarg import arg, va_arg -TEMP_BUF_SIZE: t.CDefine = 68 +define TEMP_BUF_SIZE = 68 -def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt: - count: t.CInt = 0 +def get_digit_count(num: uint, base: int) -> int: + count: int = 0 if num == 0: return 1 while num > 0: count += 1 @@ -14,141 +14,138 @@ def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt: # 返回类型必须与 CRT `sprintf` 以及 includes/stdio.vp 的 # 语义上直接返回 vsnprintf 的写入长度(与 CRT 一致)。 -export def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt: +export def sprintf(buf: str, rule: str, *args) -> int: if buf is None or rule is None: return 0 return vsnprintf(buf, 0x7FFFFFFF, rule, args) -def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt: +def vsprintf(buf: str, rule: str, *args) -> int: if buf is None or rule is None: return 0 return vsnprintf(buf, 0x7FFFFFFF, rule, args) -export def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt: +export def snprintf(buf: str, size: sizet, fmt: str, *args) -> int: if fmt is None: return 0 - if buf is None or size == 0: - return vsnprintf(None, 0, fmt, args) + if buf is None or size == 0: return vsnprintf(None, 0, fmt, args) ret: int = vsnprintf(buf, size, fmt, args) return ret # Check floating-point special values (IEEE 754) # Return: 0=normal, 1=+inf, 2=-inf, 3=nan def _check_special_float(fv: double) -> int: - fbits: t.CUInt64T = 0 - c.Load(c.Addr(fbits), c.Addr(fv)) - if ((fbits >> 52) & 0x7FF) != 0x7FF: - return 0 + fbits: uint64 = 0 + *&fbits = *&fv + if ((fbits >> 52) & 0x7FF) != 0x7FF: return 0 is_neg: int = 1 if (fbits >> 63) != 0 else 0 if (fbits & 0x000FFFFFFFFFFFFF) == 0: - if is_neg: - return 2 + if is_neg: return 2 return 1 return 3 -export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) -> int: +export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: if fmt is None: return 0 - # 长度探测模式:buf is None 时只计算格式化后长度,不实际写入 - # _step=0 使 ptr 不前进,反复写入同一个 dummy 字节(无害),write_count 正确累加 + # Length detection mode: when buf is None, only calculate the formatted length, without actually writing + # _step=0 makes ptr not advance, repeatedly writing the same dummy byte (harmless), write_count accumulates correctly count_mode: int = 0 _step: int = 1 - _dummy: t.CChar = '\0' + _dummy: char = '\0' if buf is None or size == 0: count_mode = 1 _step = 0 - buf = c.Addr(_dummy) + buf = &_dummy size = 0x7FFFFFFF - ptr: t.CChar | t.CPtr = buf - write_count: t.CInt = 0 - temp: t.CArray[t.CChar, 68] + ptr: str = buf + write_count: int = 0 + temp: t.CArray[char, 68] temp[0] = '\t' - while c.Deref(fmt) != 0 and write_count < size - 1: - if c.Deref(fmt) != 37: - ptr[0] = c.Deref(fmt) + while *fmt != 0 and write_count < size - 1: + if *fmt != 37: + ptr[0] = *fmt write_count += 1 ptr += _step fmt += 1 else: fmt += 1 - if c.Deref(fmt) == 0: break - width: t.CInt = 0 - pad_zero: t.CInt = 0 - left_align: t.CInt = 0 - show_sign: t.CInt = 0 - space_sign: t.CInt = 0 - alt_form: t.CInt = 0 - precision: t.CInt = -1 - is_long: t.CInt = 0 - is_long_long: t.CInt = 0 - is_size: t.CInt = 0 - is_short: t.CInt = 0 - is_char: t.CInt = 0 + if *fmt == 0: break + width: int = 0 + pad_zero: int = 0 + left_align: int = 0 + show_sign: int = 0 + space_sign: int = 0 + alt_form: int = 0 + precision: int = -1 + is_long: int = 0 + is_long_long: int = 0 + is_size: int = 0 + is_short: int = 0 + is_char: int = 0 while True: - if c.Deref(fmt) == 45: + if *fmt == 45: left_align = 1 fmt += 1 - elif c.Deref(fmt) == 48: + elif *fmt == 48: pad_zero = 1 fmt += 1 - elif c.Deref(fmt) == 43: + elif *fmt == 43: show_sign = 1 fmt += 1 - elif c.Deref(fmt) == 32: + elif *fmt == 32: space_sign = 1 fmt += 1 - elif c.Deref(fmt) == 35: + elif *fmt == 35: alt_form = 1 fmt += 1 else: break if show_sign: space_sign = 0 - while c.Deref(fmt) >= 48 and c.Deref(fmt) <= 57: - width = width * 10 + (c.Deref(fmt) - 48) + while *fmt >= 48 and *fmt <= 57: + width = width * 10 + (*fmt - 48) fmt += 1 - if c.Deref(fmt) == 46: + if *fmt == 46: fmt += 1 precision = 0 - while c.Deref(fmt) >= 48 and c.Deref(fmt) <= 57: - precision = precision * 10 + (c.Deref(fmt) - 48) + while *fmt >= 48 and *fmt <= 57: + precision = precision * 10 + (*fmt - 48) fmt += 1 if left_align: pad_zero = 0 - if c.Deref(fmt) == 108: + if *fmt == 108: is_long = 1 fmt += 1 - if c.Deref(fmt) == 108: + if *fmt == 108: is_long_long = 1 is_long = 0 fmt += 1 - elif c.Deref(fmt) == 104: + elif *fmt == 104: is_short = 1 fmt += 1 - if c.Deref(fmt) == 104: + if *fmt == 104: is_char = 1 is_short = 0 fmt += 1 - elif c.Deref(fmt) == 122: + elif *fmt == 122: is_size = 1 fmt += 1 - elif c.Deref(fmt) == 106: + elif *fmt == 106: is_long_long = 1 fmt += 1 - elif c.Deref(fmt) == 116: + elif *fmt == 116: is_long = 1 fmt += 1 - if c.Deref(fmt) == 99: + if *fmt == 99: if write_count < size - 1: - ptr_i: t.CInt = va_arg(ap) - ptr[0] = t.CChar(ptr_i) + ptr_i: int = va_arg(ap) + ptr[0] = char(ptr_i) write_count += 1 ptr += _step else: - ptr_i: t.CInt = va_arg(ap) - elif c.Deref(fmt) == 115: + ptr_i: int = va_arg(ap) + elif *fmt == 115: s: str = va_arg(ap, t.CPtr) if s is None: s = "(None)" - slen: t.CInt = 0 + slen: int = 0 sc: str = s while c.Deref(sc) != 0: slen += 1 sc += 1 if not left_align and width > slen: - pad_count: t.CInt = width - slen + pad_count: int = width - slen while pad_count > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 @@ -166,30 +163,30 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 100 or c.Deref(fmt) == 105: + elif *fmt == 100 or *fmt == 105: if is_long_long or is_size or is_long: - num_l: t.CInt64T = va_arg(ap, t.CInt64T) + num_l: int64 = va_arg(ap, int64) else: - num_l: t.CInt64T = t.CInt64T(va_arg(ap, t.CInt)) + num_l: int64 = int64(va_arg(ap, int)) if is_char: - num_l = t.CInt64T(t.CChar(num_l)) + num_l = int64(char(num_l)) elif is_short: - num_l = t.CInt64T(t.CShort(num_l)) - sign: t.CInt = 0 + num_l = int64(short(num_l)) + sign: int = 0 if num_l < 0: sign = 1 if num_l == (-9223372036854775807 - 1): - u_num: t.CUInt64T = t.CUInt64T(0x8000000000000000) + u_num: uint64 = uint64(0x8000000000000000) else: - u_num: t.CUInt64T = t.CUInt64T(-num_l) + u_num: uint64 = uint64(-num_l) else: - u_num: t.CUInt64T = t.CUInt64T(num_l) + u_num: uint64 = uint64(num_l) if show_sign: sign = 2 elif space_sign: sign = 3 - i: t.CInt = 0 + i: int = 0 while True: if i >= TEMP_BUF_SIZE - 1: break - temp[i] = t.CChar(u_num % 10 + 48) + temp[i] = char(u_num % 10 + 48) i += 1 u_num //= 10 if u_num <= 0: break @@ -228,15 +225,15 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 117: + elif *fmt == 117: if is_long or is_long_long or is_size: - u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + u_num_l: uint64 = va_arg(ap, uint64) else: - u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + u_num_l: uint64 = uint64(uint(va_arg(ap))) i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break - temp[i] = t.CChar(u_num_l % 10 + 48) + temp[i] = char(u_num_l % 10 + 48) i += 1 u_num_l //= 10 if u_num_l <= 0: break @@ -266,30 +263,30 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 120: + elif *fmt == 120: if is_long or is_long_long or is_size: - u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + u_num_l: uint64 = va_arg(ap, uint64) else: - u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) - is_nonzero: t.CInt = 0 + u_num_l: uint64 = uint64(uint(va_arg(ap))) + is_nonzero: int = 0 if u_num_l != 0: is_nonzero = 1 i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break - digit: t.CInt = t.CInt(u_num_l % 16) + digit: int = int(u_num_l % 16) if digit < 10: - temp[i] = t.CChar(digit + 48) + temp[i] = char(digit + 48) else: - temp[i] = t.CChar(digit - 10 + 97) + temp[i] = char(digit - 10 + 97) u_num_l //= 16 i += 1 if u_num_l <= 0: break - digit_count: t.CInt = i - prefix_len: t.CInt = 0 + digit_count: int = i + prefix_len: int = 0 if alt_form and is_nonzero: prefix_len = 2 - effective_len: t.CInt = digit_count + prefix_len + effective_len: int = digit_count + prefix_len if not left_align and not pad_zero and width > effective_len: pad_count = width - effective_len while pad_count > 0 and write_count < size - 1: @@ -325,22 +322,22 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 88: + elif *fmt == 88: if is_long or is_long_long or is_size: - u_num_l: t.CUInt64T = va_arg(ap) + u_num_l: uint64 = va_arg(ap) else: - u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + u_num_l: uint64 = uint64(uint(va_arg(ap))) is_nonzero = 0 if u_num_l != 0: is_nonzero = 1 i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break - digit = t.CInt(u_num_l % 16) + digit = int(u_num_l % 16) if digit < 10: - temp[i] = t.CChar(digit + 48) + temp[i] = char(digit + 48) else: - temp[i] = t.CChar(digit - 10 + 65) + temp[i] = char(digit - 10 + 65) u_num_l //= 16 i += 1 if u_num_l <= 0: break @@ -384,15 +381,15 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 111: + elif *fmt == 111: if is_long or is_long_long or is_size: - u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + u_num_l: uint64 = va_arg(ap, uint64) else: - u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + u_num_l: uint64 = uint64(uint(va_arg(ap))) if is_char: - u_num_l = t.CUInt64T(t.CChar(u_num_l)) + u_num_l = uint64(char(u_num_l)) elif is_short: - u_num_l = t.CUInt64T(t.CShort(u_num_l)) + u_num_l = uint64(short(u_num_l)) i = 0 if u_num_l == 0 and not alt_form: temp[0] = 48 @@ -400,7 +397,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) else: while True: if i >= TEMP_BUF_SIZE - 1: break - temp[i] = t.CChar(u_num_l % 8 + 48) + temp[i] = char(u_num_l % 8 + 48) i += 1 u_num_l //= 8 if u_num_l <= 0: break @@ -433,15 +430,15 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 98: + elif *fmt == 98: if is_long or is_long_long or is_size: - u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + u_num_l: uint64 = va_arg(ap, uint64) else: - u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + u_num_l: uint64 = uint64(uint(va_arg(ap))) if is_char: - u_num_l = t.CUInt64T(t.CChar(u_num_l)) + u_num_l = uint64(char(u_num_l)) elif is_short: - u_num_l = t.CUInt64T(t.CShort(u_num_l)) + u_num_l = uint64(short(u_num_l)) i = 0 if u_num_l == 0: temp[0] = 48 @@ -449,7 +446,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) else: while True: if i >= TEMP_BUF_SIZE - 1: break - temp[i] = t.CChar(u_num_l % 2 + 48) + temp[i] = char(u_num_l % 2 + 48) i += 1 u_num_l //= 2 if u_num_l <= 0: break @@ -482,8 +479,8 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 112: - ptr_val: t.CUInt64T = t.CUInt64T(va_arg(ap, t.CPtr)) + elif *fmt == 112: + ptr_val: uint64 = uint64(va_arg(ap, t.CPtr)) if ptr_val == 0: temp[0] = 40 temp[1] = 110 @@ -496,11 +493,11 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) i = 0 while True: if i >= TEMP_BUF_SIZE - 1: break - digit = t.CInt(u_num_l % 16) + digit = int(u_num_l % 16) if digit < 10: - temp[i] = t.CChar(digit + 48) + temp[i] = char(digit + 48) else: - temp[i] = t.CChar(digit - 10 + 97) + temp[i] = char(digit - 10 + 97) u_num_l //= 16 i += 1 if u_num_l <= 0: break @@ -536,22 +533,22 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 102 or c.Deref(fmt) == 70: - f_upper: t.CInt = 1 if c.Deref(fmt) == 70 else 0 + elif *fmt == 102 or *fmt == 70: + f_upper: int = 1 if *fmt == 70 else 0 if precision < 0: precision = 6 - fv: t.CDouble = va_arg(ap, t.CDouble) - f_sp: t.CInt = _check_special_float(fv) + fv: double = va_arg(ap, double) + f_sp: int = _check_special_float(fv) if f_sp != 0: - f_sgn_len: t.CInt = 0 + f_sgn_len: int = 0 if f_sp == 2: f_sgn_len = 1 elif f_sp == 1 and show_sign: f_sgn_len = 1 elif f_sp == 1 and space_sign: f_sgn_len = 1 - f_total_len: t.CInt = f_sgn_len + 3 + f_total_len: int = f_sgn_len + 3 if not left_align and width > f_total_len: - f_pad: t.CInt = width - f_total_len + f_pad: int = width - f_total_len while f_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 @@ -572,9 +569,9 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - fi_c: t.CInt = 0 + fi_c: int = 0 while fi_c < 3 and write_count < size - 1: - fc: t.CInt = 0 + fc: int = 0 if f_sp == 3: # nan if fi_c == 0: @@ -593,7 +590,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) fc = 102 if f_upper and fc >= 97 and fc <= 122: fc -= 32 - ptr[0] = t.CChar(fc) + ptr[0] = char(fc) write_count += 1 ptr += _step fi_c += 1 @@ -622,29 +619,29 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - di: t.CInt = 0 - work: t.CDouble = fv + di: int = 0 + work: double = fv if work < 1.0: temp[0] = 48 di = 1 else: - scale: t.CDouble = 1.0 + scale: double = 1.0 while work >= scale * 10.0: scale *= 10.0 while scale >= 1.0 and di < TEMP_BUF_SIZE - 1: - d: t.CInt = t.CInt(work / scale) + d: int = int(work / scale) if d > 9: d = 9 - temp[di] = t.CChar(d + 48) + temp[di] = char(d + 48) di += 1 - work = work - t.CDouble(d) * scale + work = work - double(d) * scale scale /= 10.0 - frac_val: t.CDouble = work - p: t.CInt = 0 + frac_val: double = work + p: int = 0 while p < precision: frac_val *= 10.0 p += 1 - frac_part: t.CUInt64T = t.CUInt64T(frac_val + 0.5) - f_total: t.CInt = di + (precision + 1 if precision > 0 else 0) + frac_part: uint64 = uint64(frac_val + 0.5) + f_total: int = di + (precision + 1 if precision > 0 else 0) if not left_align and not pad_zero and width > f_total: pad_count = width - f_total while pad_count > 0 and write_count < size - 1: @@ -669,9 +666,9 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 46 write_count += 1 ptr += _step - fi: t.CInt = 0 + fi: int = 0 while fi < precision and fi < TEMP_BUF_SIZE - 1: - temp[fi] = t.CChar(frac_part % 10 + 48) + temp[fi] = char(frac_part % 10 + 48) fi += 1 frac_part //= 10 while fi < precision and fi < TEMP_BUF_SIZE - 1: @@ -694,22 +691,22 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 101 or c.Deref(fmt) == 69: + elif *fmt == 101 or *fmt == 69: if precision < 0: precision = 6 - fv: t.CDouble = va_arg(ap, t.CDouble) - e_upper: t.CInt = 1 if c.Deref(fmt) == 69 else 0 - e_sp: t.CInt = _check_special_float(fv) + fv: double = va_arg(ap, double) + e_upper: int = 1 if *fmt == 69 else 0 + e_sp: int = _check_special_float(fv) if e_sp != 0: - e_sgn_len: t.CInt = 0 + e_sgn_len: int = 0 if e_sp == 2: e_sgn_len = 1 elif e_sp == 1 and show_sign: e_sgn_len = 1 elif e_sp == 1 and space_sign: e_sgn_len = 1 - e_total_len: t.CInt = e_sgn_len + 3 + e_total_len: int = e_sgn_len + 3 if not left_align and width > e_total_len: - e_pad: t.CInt = width - e_total_len + e_pad: int = width - e_total_len while e_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 @@ -730,9 +727,9 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - ei_c: t.CInt = 0 + ei_c: int = 0 while ei_c < 3 and write_count < size - 1: - ec: t.CInt = 0 + ec: int = 0 if e_sp == 3: # nan if ei_c == 0: @@ -751,7 +748,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ec = 102 if e_upper and ec >= 97 and ec <= 122: ec -= 32 - ptr[0] = t.CChar(ec) + ptr[0] = char(ec) write_count += 1 ptr += _step ei_c += 1 @@ -780,7 +777,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - exp10: t.CInt = 0 + exp10: int = 0 if fv != 0.0: while fv >= 10.0: fv /= 10.0 @@ -788,16 +785,16 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) while fv < 1.0: fv *= 10.0 exp10 -= 1 - int_digit: t.CInt = t.CInt(fv) + int_digit: int = int(fv) if int_digit > 9: int_digit = 9 if int_digit < 0: int_digit = 0 - frac_v: t.CDouble = fv - t.CDouble(int_digit) - p: t.CInt = 0 + frac_v: double = fv - double(int_digit) + p: int = 0 while p < precision: frac_v *= 10.0 p += 1 - frac_p: t.CUInt64T = t.CUInt64T(frac_v + 0.5) - carry: t.CUInt64T = 1 + frac_p: uint64 = uint64(frac_v + 0.5) + carry: uint64 = 1 p = 0 while p < precision: carry *= 10 @@ -808,7 +805,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) if int_digit > 9: int_digit = 1 exp10 += 1 - e_total: t.CInt = 1 + (precision + 1 if precision > 0 else 0) + 4 + e_total: int = 1 + (precision + 1 if precision > 0 else 0) + 4 if not left_align and not pad_zero and width > e_total: pad_count = width - e_total while pad_count > 0 and write_count < size - 1: @@ -824,7 +821,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr += _step pad_count -= 1 if write_count < size - 1: - ptr[0] = t.CChar(int_digit + 48) + ptr[0] = char(int_digit + 48) write_count += 1 ptr += _step if precision > 0: @@ -832,9 +829,9 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 46 write_count += 1 ptr += _step - fi: t.CInt = 0 + fi: int = 0 while fi < precision and fi < TEMP_BUF_SIZE - 1: - temp[fi] = t.CChar(frac_p % 10 + 48) + temp[fi] = char(frac_p % 10 + 48) fi += 1 frac_p //= 10 while fi < precision and fi < TEMP_BUF_SIZE - 1: @@ -858,15 +855,15 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 45 if exp10 < 0 else 43 write_count += 1 ptr += _step - exp_abs: t.CUInt64T = t.CUInt64T(exp10) if exp10 >= 0 else t.CUInt64T(0 - exp10) - ei: t.CInt = 0 + exp_abs: uint64 = uint64(exp10) if exp10 >= 0 else uint64(0 - exp10) + ei: int = 0 if exp_abs == 0: temp[0] = 48 temp[1] = 48 ei = 2 else: while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: - temp[ei] = t.CChar(exp_abs % 10 + 48) + temp[ei] = char(exp_abs % 10 + 48) ei += 1 exp_abs //= 10 while ei < 2: @@ -884,23 +881,23 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 103 or c.Deref(fmt) == 71: + elif *fmt == 103 or *fmt == 71: if precision < 0: precision = 6 if precision == 0: precision = 1 - fv: t.CDouble = va_arg(ap, t.CDouble) - g_upper: t.CInt = 1 if c.Deref(fmt) == 71 else 0 - g_sp: t.CInt = _check_special_float(fv) + fv: double = va_arg(ap, double) + g_upper: int = 1 if *fmt == 71 else 0 + g_sp: int = _check_special_float(fv) if g_sp != 0: - g_sgn_len: t.CInt = 0 + g_sgn_len: int = 0 if g_sp == 2: g_sgn_len = 1 elif g_sp == 1 and show_sign: g_sgn_len = 1 elif g_sp == 1 and space_sign: g_sgn_len = 1 - g_total_len: t.CInt = g_sgn_len + 3 + g_total_len: int = g_sgn_len + 3 if not left_align and width > g_total_len: - g_pad: t.CInt = width - g_total_len + g_pad: int = width - g_total_len while g_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 @@ -921,9 +918,9 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - gi_c: t.CInt = 0 + gi_c: int = 0 while gi_c < 3 and write_count < size - 1: - gc: t.CInt = 0 + gc: int = 0 if g_sp == 3: # nan if gi_c == 0: @@ -942,7 +939,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) gc = 102 if g_upper and gc >= 97 and gc <= 122: gc -= 32 - ptr[0] = t.CChar(gc) + ptr[0] = char(gc) write_count += 1 ptr += _step gi_c += 1 @@ -971,8 +968,8 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - fv_orig: t.CDouble = fv - exp10: t.CInt = 0 + fv_orig: double = fv + exp10: int = 0 if fv != 0.0: while fv >= 10.0: fv /= 10.0 @@ -980,22 +977,22 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) while fv < 1.0: fv *= 10.0 exp10 -= 1 - g_use_e: t.CInt = 0 + g_use_e: int = 0 if exp10 < -4 or exp10 >= precision: g_use_e = 1 - g_len: t.CInt = 0 + g_len: int = 0 if g_use_e: - int_digit: t.CInt = t.CInt(fv) + int_digit: int = int(fv) if int_digit > 9: int_digit = 9 if int_digit < 0: int_digit = 0 - frac_v: t.CDouble = fv - t.CDouble(int_digit) - prec_e: t.CInt = precision - 1 - p: t.CInt = 0 + frac_v: double = fv - double(int_digit) + prec_e: int = precision - 1 + p: int = 0 while p < prec_e: frac_v *= 10.0 p += 1 - frac_p: t.CUInt64T = t.CUInt64T(frac_v + 0.5) - carry: t.CUInt64T = 1 + frac_p: uint64 = uint64(frac_v + 0.5) + carry: uint64 = 1 p = 0 while p < prec_e: carry *= 10 @@ -1006,7 +1003,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) if int_digit > 9: int_digit = 1 exp10 += 1 - temp[0] = t.CChar(int_digit + 48) + temp[0] = char(int_digit + 48) g_len = 1 if prec_e > 0: temp[1] = 46 @@ -1014,50 +1011,50 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) # 小数位逆序存入(个位放 g_len+prec_e-1),temp 直接为正序。 # 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654), # 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。 - fi: t.CInt = 0 - fp_inv: t.CUInt64T = frac_p - fp_idx: t.CInt = g_len + prec_e - 1 + fi: int = 0 + fp_inv: uint64 = frac_p + fp_idx: int = g_len + prec_e - 1 while fi < prec_e and fp_idx < TEMP_BUF_SIZE - 1: - temp[fp_idx] = t.CChar(fp_inv % 10 + 48) + temp[fp_idx] = char(fp_inv % 10 + 48) fp_idx -= 1 fp_inv //= 10 fi += 1 g_len += prec_e else: - prec_f: t.CInt = precision - 1 - exp10 + prec_f: int = precision - 1 - exp10 if prec_f < 0: prec_f = 0 - work: t.CDouble = fv_orig + work: double = fv_orig if work < 1.0: temp[0] = 48 g_len = 1 else: - scale: t.CDouble = 1.0 + scale: double = 1.0 while work >= scale * 10.0: scale *= 10.0 while scale >= 1.0 and g_len < TEMP_BUF_SIZE - 1: - d: t.CInt = t.CInt(work / scale) + d: int = int(work / scale) if d > 9: d = 9 - temp[g_len] = t.CChar(d + 48) + temp[g_len] = char(d + 48) g_len += 1 - work = work - t.CDouble(d) * scale + work = work - double(d) * scale scale /= 10.0 if prec_f > 0 and g_len < TEMP_BUF_SIZE - 1: temp[g_len] = 46 g_len += 1 - frac_val: t.CDouble = work + frac_val: double = work p = 0 while p < prec_f: frac_val *= 10.0 p += 1 - frac_part: t.CUInt64T = t.CUInt64T(frac_val + 0.5) - # 小数位逆序存入(个位放 g_len+prec_f-1),temp 直接为正序。 - # 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654), - # 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。 + frac_part: uint64 = uint64(frac_val + 0.5) + # Store decimal digits in reverse order (ones place goes to g_len prec_f-1), temp is directly in forward order. + # The original swap-reverse loop doesn't work in TPV compiled output (decimal digits aren't reversed, e.g., 456->654), + # Change to reverse storage, consistent with %f's reverse output, avoiding three-variable swapping. fi = 0 - fp_inv: t.CUInt64T = frac_part - fp_idx: t.CInt = g_len + prec_f - 1 + fp_inv: uint64 = frac_part + fp_idx: int = g_len + prec_f - 1 while fi < prec_f and fp_idx < TEMP_BUF_SIZE - 1: - temp[fp_idx] = t.CChar(fp_inv % 10 + 48) + temp[fp_idx] = char(fp_inv % 10 + 48) fp_idx -= 1 fp_inv //= 10 fi += 1 @@ -1070,7 +1067,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) break if g_len > 0 and temp[g_len - 1] == 46: g_len -= 1 - g_total: t.CInt = g_len + g_total: int = g_len if g_use_e: g_total = g_len + 4 if not left_align and not pad_zero and width > g_total: pad_count = width - g_total @@ -1086,7 +1083,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - gi: t.CInt = 0 + gi: int = 0 while gi < g_len and write_count < size - 1: ptr[0] = temp[gi] write_count += 1 @@ -1101,15 +1098,15 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 45 if exp10 < 0 else 43 write_count += 1 ptr += _step - exp_abs: t.CUInt64T = t.CUInt64T(exp10) if exp10 >= 0 else t.CUInt64T(0 - exp10) - ei: t.CInt = 0 + exp_abs: uint64 = uint64(exp10) if exp10 >= 0 else uint64(0 - exp10) + ei: int = 0 if exp_abs == 0: temp[0] = 48 temp[1] = 48 ei = 2 else: while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: - temp[ei] = t.CChar(exp_abs % 10 + 48) + temp[ei] = char(exp_abs % 10 + 48) ei += 1 exp_abs //= 10 while ei < 2: @@ -1127,21 +1124,21 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step pad_count -= 1 - elif c.Deref(fmt) == 97 or c.Deref(fmt) == 65: - a_upper: t.CInt = 1 if c.Deref(fmt) == 65 else 0 - fv: t.CDouble = va_arg(ap, t.CDouble) - a_sp: t.CInt = _check_special_float(fv) + elif *fmt == 97 or *fmt == 65: + a_upper: int = 1 if *fmt == 65 else 0 + fv: double = va_arg(ap, double) + a_sp: int = _check_special_float(fv) if a_sp != 0: - a_sgn_len: t.CInt = 0 + a_sgn_len: int = 0 if a_sp == 2: a_sgn_len = 1 elif a_sp == 1 and show_sign: a_sgn_len = 1 elif a_sp == 1 and space_sign: a_sgn_len = 1 - a_total_len: t.CInt = a_sgn_len + 3 + a_total_len: int = a_sgn_len + 3 if not left_align and width > a_total_len: - a_pad: t.CInt = width - a_total_len + a_pad: int = width - a_total_len while a_pad > 0 and write_count < size - 1: ptr[0] = 32 write_count += 1 @@ -1162,9 +1159,9 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 32 write_count += 1 ptr += _step - ai_c: t.CInt = 0 + ai_c: int = 0 while ai_c < 3 and write_count < size - 1: - ac: t.CInt = 0 + ac: int = 0 if a_sp == 3: # nan if ai_c == 0: @@ -1183,7 +1180,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ac = 102 if a_upper and ac >= 97 and ac <= 122: ac -= 32 - ptr[0] = t.CChar(ac) + ptr[0] = char(ac) write_count += 1 ptr += _step ai_c += 1 @@ -1196,13 +1193,13 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) a_pad -= 1 fmt += 1 continue - fbits: t.CUInt64T = 0 + fbits: uint64 = 0 c.Load(c.Addr(fbits), c.Addr(fv)) - a_neg: t.CInt = 1 if (fbits >> 63) != 0 else 0 - a_exp: t.CInt = t.CInt((fbits >> 52) & 0x7FF) - a_frac: t.CUInt64T = fbits & 0x000FFFFFFFFFFFFF - a_leading: t.CInt = 0 - a_binexp: t.CInt = 0 + a_neg: int = 1 if (fbits >> 63) != 0 else 0 + a_exp: int = int((fbits >> 52) & 0x7FF) + a_frac: uint64 = fbits & 0x000FFFFFFFFFFFFF + a_leading: int = 0 + a_binexp: int = 0 if a_exp == 0: a_leading = 0 if a_frac == 0: @@ -1212,57 +1209,57 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) else: a_leading = 1 a_binexp = a_exp - 1023 - a_prec: t.CInt = precision + a_prec: int = precision if a_prec < 0: a_prec = 13 if a_prec > 50: a_prec = 50 - a_hi: t.CInt = 0 + a_hi: int = 0 while a_hi < 13 and a_hi < a_prec: - a_digit: t.CInt = t.CInt((a_frac >> (48 - 4 * a_hi)) & 0xF) + a_digit: int = int((a_frac >> (48 - 4 * a_hi)) & 0xF) if a_digit < 10: - temp[a_hi] = t.CChar(a_digit + 48) + temp[a_hi] = char(a_digit + 48) else: if a_upper: - temp[a_hi] = t.CChar(a_digit - 10 + 65) + temp[a_hi] = char(a_digit - 10 + 65) else: - temp[a_hi] = t.CChar(a_digit - 10 + 97) + temp[a_hi] = char(a_digit - 10 + 97) a_hi += 1 while a_hi < a_prec: temp[a_hi] = 48 a_hi += 1 - a_hd_count: t.CInt = a_prec + a_hd_count: int = a_prec if precision < 0: while a_hd_count > 0 and temp[a_hd_count - 1] == 48: a_hd_count -= 1 - a_has_dot: t.CInt = 0 + a_has_dot: int = 0 if a_hd_count > 0: a_has_dot = 1 elif alt_form: a_has_dot = 1 - a_eb: t.CInt = a_binexp - a_esign: t.CInt = 0 + a_eb: int = a_binexp + a_esign: int = 0 if a_binexp < 0: a_esign = 1 a_eb = -a_binexp - a_ei: t.CInt = 0 + a_ei: int = 0 if a_eb == 0: temp[60] = 48 a_ei = 1 else: while a_eb > 0 and a_ei < 7: - temp[60 + a_ei] = t.CChar(a_eb % 10 + 48) + temp[60 + a_ei] = char(a_eb % 10 + 48) a_ei += 1 a_eb //= 10 - a_ecount: t.CInt = a_ei - a_sign_len: t.CInt = 0 + a_ecount: int = a_ei + a_sign_len: int = 0 if a_neg: a_sign_len = 1 elif show_sign: a_sign_len = 1 elif space_sign: a_sign_len = 1 - a_content_len: t.CInt = a_sign_len + 2 + 1 + a_has_dot + a_hd_count + 1 + 1 + a_ecount + a_content_len: int = a_sign_len + 2 + 1 + a_has_dot + a_hd_count + 1 + 1 + a_ecount if not left_align and not pad_zero and width > a_content_len: a_pad = width - a_content_len while a_pad > 0 and write_count < size - 1: @@ -1304,7 +1301,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step if write_count < size - 1: - ptr[0] = t.CChar(a_leading + 48) + ptr[0] = char(a_leading + 48) write_count += 1 ptr += _step if a_has_dot: @@ -1312,7 +1309,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 46 write_count += 1 ptr += _step - a_hj: t.CInt = 0 + a_hj: int = 0 while a_hj < a_hd_count and write_count < size - 1: ptr[0] = temp[a_hj] write_count += 1 @@ -1332,7 +1329,7 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) ptr[0] = 43 write_count += 1 ptr += _step - a_ek: t.CInt = a_ecount + a_ek: int = a_ecount while a_ek > 0 and write_count < size - 1: a_ek -= 1 ptr[0] = temp[60 + a_ek] @@ -1345,31 +1342,31 @@ export def vsnprintf(buf: bytes, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) write_count += 1 ptr += _step a_pad -= 1 - elif c.Deref(fmt) == 110: + elif *fmt == 110: if is_long_long or is_long: - np: t.CInt64T | t.CPtr = va_arg(ap, t.CInt64T | t.CPtr) + np: int64* = va_arg(ap, int64*) if np != None: - np[0] = t.CInt64T(write_count) + np[0] = int64(write_count) elif is_short: - sp: t.CShort | t.CPtr = va_arg(ap, t.CShort | t.CPtr) + sp: short* = va_arg(ap, short*) if sp != None: - sp[0] = t.CShort(write_count) + sp[0] = short(write_count) elif is_char: - cp: t.CChar | t.CPtr = va_arg(ap, t.CChar | t.CPtr) + cp: str = va_arg(ap, str) if cp != None: - cp[0] = t.CChar(write_count) + cp[0] = char(write_count) else: - ip: t.CInt | t.CPtr = va_arg(ap, t.CInt | t.CPtr) + ip: int* = va_arg(ap, int*) if ip != None: ip[0] = write_count - elif c.Deref(fmt) == 37: + elif *fmt == 37: if write_count < size - 1: ptr[0] = 37 write_count += 1 ptr += _step else: if write_count < size - 1: - ptr[0] = c.Deref(fmt) + ptr[0] = *fmt write_count += 1 ptr += _step fmt += 1 diff --git a/vipermath.vp b/vipermath.vp deleted file mode 100644 index f4a4ed4..0000000 --- a/vipermath.vp +++ /dev/null @@ -1,551 +0,0 @@ -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: - """e^x - - 范围归约 + 短泰勒: 直接对 x 展开 18 项泰勒在 |x| 稍大时就会发散 - (x=-10 得 54.5, 真值 4.5e-5; x=-30 得 3.7e10), 负数端更是给出巨大正值, - 会让 softmax 的分母被撑爆 → 所有概率 ≈ 0。改为先做 - x = k*ln2 + r (|r| <= ln2/2), 再算 exp(r) 后乘 2^k。 - """ - # 先用"有限且落在范围里"的正向判断过一遍: NaN 与任何数比较都为假, 会同时漏过 - # 下面两个判断, 而 t.CInt(NaN) 在 x86 上是 INT_MIN -> 后面 2^k 缩放循环要跑 - # 21 亿次, 表现为"卡死"。故 NaN/越界必须在这里挡掉。 - if x <= t.CDouble(709.0) and x >= t.CDouble(-745.0): - pass - else: - if x > t.CDouble(709.0): - return t.CDouble(1.7976931348623157e308) - if x < t.CDouble(-745.0): - return t.CDouble(0.0) - return x # NaN: 原样返回, 让 NaN 传播而不是卡死 - # 归约: 把 x 折到 [-ln2/2, ln2/2], 整数部分累积到 k (内联取整, 避免前向引用) - ln2: t.CDouble = U_M_LN2 - q: t.CDouble = x / ln2 - k: t.CInt = t.CInt(q) - frac: t.CDouble = q - t.CDouble(k) - if frac > t.CDouble(0.5): - k = k + 1 - elif frac < t.CDouble(-0.5): - k = k - 1 - r: t.CDouble = x - t.CDouble(k) * ln2 - # exp(r), |r| <= 0.3466: 12 项后截断误差 < 1e-17 - result: t.CDouble = t.CDouble(1.0) - term: t.CDouble = t.CDouble(1.0) - n: t.CInt = 1 - while n <= 12: - term = term * r / t.CDouble(n) - result = result + term - n += 1 - while k > 0: - result = result * t.CDouble(2.0) - k = k - 1 - while k < 0: - result = result * t.CDouble(0.5) - k = k + 1 - return result - - -def log(x: t.CDouble) -> t.CDouble: - if x <= t.CDouble(0.0): - return t.CDouble(-1e308) - exponent: t.CInt = 0 - while x >= t.CDouble(2.0): - x /= t.CDouble(2.0) - exponent += 1 - while x < t.CDouble(1.0): - x *= t.CDouble(2.0) - exponent -= 1 - y: t.CDouble = (x - t.CDouble(1.0)) / (x + t.CDouble(1.0)) - y2: t.CDouble = y * y - result: t.CDouble = t.CDouble(2.0) * y - term: t.CDouble = t.CDouble(2.0) * y - term = term * y2 - result = result + term / t.CDouble(3.0) - term = term * y2 - result = result + term / t.CDouble(5.0) - term = term * y2 - result = result + term / t.CDouble(7.0) - term = term * y2 - result = result + term / t.CDouble(9.0) - term = term * y2 - result = result + term / t.CDouble(11.0) - term = term * y2 - result = result + term / t.CDouble(13.0) - term = term * y2 - result = result + term / t.CDouble(15.0) - term = term * y2 - result = result + term / t.CDouble(17.0) - term = term * y2 - result = result + term / t.CDouble(19.0) - term = term * y2 - result = result + term / t.CDouble(21.0) - result += t.CDouble(exponent) * U_M_LN2 - return result - - -def sqrt(x: t.CDouble) -> t.CDouble: - if x < t.CDouble(0.0): - return t.CDouble(0.0) - if x == t.CDouble(0.0): - return t.CDouble(0.0) - guess: t.CDouble = x / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - guess = (guess + x / guess) / t.CDouble(2.0) - return guess - - -def abs(x: t.CInt) -> t.CInt: - return x if x >= 0 else -x - -def fabs(x: t.CDouble) -> t.CDouble: - return x if x >= t.CDouble(0.0) else -x - -def labs(x: t.CLong) -> t.CLong: - return x if x >= 0 else -x - -def factorial(n: t.CInt) -> t.CDouble: - if n < 0: return t.CDouble(0.0) - if n == 0 or n == 1: return t.CDouble(1.0) - result: t.CDouble = t.CDouble(1.0) - for i in range(2, n + 1): - result *= i - return result - - -def combination(n: t.CInt, k: t.CInt) -> t.CDouble: - if k < 0 or k > n: return t.CDouble(0.0) - if k == 0 or k == n: return t.CDouble(1.0) - k = k if k < n - k else n - k - result: t.CDouble = t.CDouble(1.0) - for i in range(1, k + 1): - result = result * (n - k + i) / i - return result - - -def permutation(n: t.CInt, k: t.CInt) -> t.CDouble: - if k < 0 or k > n: return t.CDouble(0.0) - result: t.CDouble = t.CDouble(1.0) - for i in range(0, k): - result *= (n - i) - return result - -def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: - if x == t.CDouble(0.0): - if y > t.CDouble(0.0): - return t.CDouble(0.0) - return t.CDouble(1.0) - if x < t.CDouble(0.0): - iy: t.CDouble = y * log(-x) - return exp(iy) - return exp(y * log(x)) - - -def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble: - return pow(x, y) - - -def cbrt(x: t.CDouble) -> t.CDouble: - return pow(x, t.CDouble(1.0) / t.CDouble(3.0)) - -def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble: - return sqrt(x * x + y * y) - - -def floor(x: t.CDouble) -> t.CDouble: - if x >= t.CDouble(0.0): - return t.CDouble(t.CInt(x)) - i: t.CInt = t.CInt(x) - if x < t.CDouble(i): - return t.CDouble(i - 1) - else: - return t.CDouble(i) - - -def ceil(x: t.CDouble) -> t.CDouble: - if x < t.CDouble(0.0): - return t.CDouble(t.CInt(x)) - i: t.CInt = t.CInt(x) - if x > t.CDouble(i): - return t.CDouble(i + 1) - else: - return t.CDouble(i) - - -def round(x: t.CDouble) -> t.CDouble: - return floor(x + t.CDouble(0.5)) - -def trunc(x: t.CDouble) -> t.CDouble: - if x >= t.CDouble(0.0): - return floor(x) - else: - return ceil(x) - - -def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble: - if y == t.CDouble(0.0): - return t.CDouble(0.0) - result: t.CDouble = x - y * floor(x / y) - if result < t.CDouble(0.0): - result += y - return result - - -def fmodf(x: float, y: float) -> float: - if y == float(0.0): - return float(0.0) - result: float = x - y * floorf(x / y) - if result < float(0.0): - result += y - return result - - -def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble: - int_part: t.CDouble = floor(x) - # c.Set(a, b) = a = b:a 为 c.Deref(iptr) 左值表达式 → *iptr = int_part - # TPV 的 c.Deref 立即 load 返回右值,故 c.Set 需识别 Deref 左值形态(translate_c_set 形态 1) - c.Set(c.Deref(iptr), int_part) - return x - int_part - - -def log10(x: t.CDouble) -> t.CDouble: - return log(x) / U_M_LN10 - - -def log2(x: t.CDouble) -> t.CDouble: - return log(x) / U_M_LN2 - - -def exp2(x: t.CDouble) -> t.CDouble: - return pow(t.CDouble(2.0), x) - - -def expm1(x: t.CDouble) -> t.CDouble: - return exp(x) - t.CDouble(1.0) - - -def log1p(x: t.CDouble) -> t.CDouble: - return log(t.CDouble(1.0) + x) - - -def asinh(x: t.CDouble) -> t.CDouble: - return log(x + sqrt(x * x + t.CDouble(1.0))) - -def acosh(x: t.CDouble) -> t.CDouble: - return log(x + sqrt(x * x - t.CDouble(1.0))) - -def atanh(x: t.CDouble) -> t.CDouble: - return (log(t.CDouble(1.0) + x) - log(t.CDouble(1.0) - x)) / t.CDouble(2.0) - - -def gamma(x: t.CDouble) -> t.CDouble: - if x <= t.CDouble(0.0): return t.CDouble(0.0) - if x == t.CDouble(1.0) or x == t.CDouble(2.0): return t.CDouble(1.0) - ln_gamma: t.CDouble = t.CDouble(0.5) * log(t.CDouble(2.0) * U_M_PI / x) + x * log(x / U_M_E) - return exp(ln_gamma) - - -def erf(x: t.CDouble) -> t.CDouble: - sign: t.CDouble = t.CDouble(1.0) if x >= t.CDouble(0.0) else t.CDouble(-1.0) - abs_x: t.CDouble = fabs(x) - t0: t.CDouble = t.CDouble(4.0) * abs_x * abs_x / U_M_PI - exp_term: t.CDouble = exp(-t0) - return sign * sqrt(t.CDouble(1.0) - exp_term) - - -def erfc(x: t.CDouble) -> t.CDouble: - return t.CDouble(1.0) - erf(x) - -def sqrtf(x: t.CFloat) -> t.CFloat: - if x < t.CFloat(0.0): - return t.CFloat(0.0) - if x == t.CFloat(0.0): - return t.CFloat(0.0) - guess: t.CFloat = x / t.CFloat(2.0) - for i in range(10): - guess = (guess + x / guess) / t.CFloat(2.0) - return guess - -def sinf(x: t.CFloat) -> t.CFloat: - while x > t.CFloat(3.14159265): - x -= t.CFloat(6.28318530) - while x < t.CFloat(-3.14159265): - x += t.CFloat(6.28318530) - x2: t.CFloat = x * x - result: t.CFloat = x - term: t.CFloat = x - term = term * x2 / t.CFloat(6.0) - result = result - term - term = term * x2 / t.CFloat(20.0) - result = result + term - term = term * x2 / t.CFloat(42.0) - result = result - term - term = term * x2 / t.CFloat(72.0) - result = result + term - term = term * x2 / t.CFloat(110.0) - result = result - term - term = term * x2 / t.CFloat(156.0) - result = result + term - term = term * x2 / t.CFloat(210.0) - result = result - term - term = term * x2 / t.CFloat(272.0) - result = result + term - return result - -def cosf(x: t.CFloat) -> t.CFloat: - while x > t.CFloat(3.14159265): - x -= t.CFloat(6.28318530) - while x < t.CFloat(-3.14159265): - x += t.CFloat(6.28318530) - x2: t.CFloat = x * x - result: t.CFloat = t.CFloat(1.0) - term: t.CFloat = t.CFloat(1.0) - term = term * x2 / t.CFloat(2.0) - result = result - term - term = term * x2 / t.CFloat(12.0) - result = result + term - term = term * x2 / t.CFloat(30.0) - result = result - term - term = term * x2 / t.CFloat(56.0) - result = result + term - term = term * x2 / t.CFloat(90.0) - result = result - term - term = term * x2 / t.CFloat(132.0) - result = result + term - term = term * x2 / t.CFloat(182.0) - result = result - term - term = term * x2 / t.CFloat(240.0) - result = result + term - return result - -def tanf(x: t.CFloat) -> t.CFloat: - c: t.CFloat = cosf(x) - if c == t.CFloat(0.0): - return t.CFloat(0.0) - return sinf(x) / c - -def fabsf(x: t.CFloat) -> t.CFloat: - return x if x >= t.CFloat(0.0) else -x - -def floorf(x: t.CFloat) -> t.CFloat: - if x >= t.CFloat(0.0): - return t.CFloat(t.CInt(x)) - i: t.CInt = t.CInt(x) - if x < t.CFloat(i): - return t.CFloat(i - 1) - else: - return t.CFloat(i) - -def ceilf(x: t.CFloat) -> t.CFloat: - if x < t.CFloat(0.0): - return t.CFloat(t.CInt(x)) - i: t.CInt = t.CInt(x) - if x > t.CFloat(i): - return t.CFloat(i + 1) - else: - return t.CFloat(i) - - -class _U(t.CUnion): - d: t.CDouble - u: t.CUInt64T - -def isnan(x: t.CDouble) -> t.CStatic | t.CInt: - # IEEE-754 位重解释(不能用 t.CUInt64T(x) 数值转换:那是 fptosi,位模式全丢 - # → exp_part 恒 0 → 永远返回 0)。用 c.Load 按位拷贝(viperlib - # _check_special_float 同款惯用法)。 - xv: t.CDouble = x - u: t.CUInt64T = 0 - c.Load(c.Addr(u), c.Addr(xv)) - 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: - xv2: t.CDouble = x - u2: t.CUInt64T = 0 - c.Load(c.Addr(u2), c.Addr(xv2)) - exp_part2: t.CUInt64T = (u2 >> 52) & 0x7FF - mantissa_part2: t.CUInt64T = u2 & 0xFFFFFFFFFFFFF - if exp_part2 == 0x7FF: - if mantissa_part2 == 0: - return 1 - return 0 diff --git a/vipersimd.vp b/vipersimd.vp index ed9bcf4..df3db6e 100644 --- a/vipersimd.vp +++ b/vipersimd.vp @@ -183,7 +183,7 @@ movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", # Batch array operations (AVX2 loop, process N double values) # ============================================================ -def simd_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): +def simd_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: sizet): """AVX2 batch: out[i:i+4] = a[i:i+4] + b[i:i+4], i=0,4,8,... ×8 双缓冲(32 doubles/大迭代):a(ymm0-7)+b(ymm8-15) 16 路 load 全部在飞后 做 8 条独立 add→store 链,最大化内存级并行、压榨访存口。 @@ -256,7 +256,7 @@ vzeroupper""", 'ymm12', 'ymm13', 'ymm14', 'ymm15', 'rcx', 'r8', 'r9', 'r10', 'r11']) -def simd_sub_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): +def simd_sub_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: sizet): """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 @@ -280,7 +280,7 @@ 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): +def simd_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: sizet): """AVX2 batch: out[i:i+4] = a[i:i+4] * b[i:i+4] ×8 双缓冲(同 simd_add_array)。""" c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} @@ -350,7 +350,7 @@ vzeroupper""", 'ymm12', 'ymm13', 'ymm14', 'ymm15', 'rcx', 'r8', 'r9', 'r10', 'r11']) -def simd_fma_array(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr, n: t.CSizeT): +def simd_fma_array(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr, n: sizet): """AVX2 batch (单趟融合乘加): out[i:i+4] = a[i:i+4]*b[i:i+4] + c_val[i:i+4] ×8 双缓冲(同 simd_mul_array):a(ymm0-7)+b(ymm8-15) 16 路 load 在飞后, 用 8 条 vfmadd213pd 以 c_val 内存操作数为加数一次完成 FMA 并落 out, @@ -428,7 +428,7 @@ vzeroupper""", 'ymm12', 'ymm13', 'ymm14', 'ymm15', 'rcx', 'rdx', 'r8', 'r9', 'r10', 'r11']) -def scalar_fma_array(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr, n: t.CSizeT): +def scalar_fma_array(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr, n: sizet): """标量(逐元素)融合乘加: out[i] = a[i]*b[i] + c_val[i], 一次只算 1 个 double。 与 simd_fma_array 是同一数学内核的"未向量化"对照实现: @@ -461,7 +461,7 @@ jnz .Lsca_loop 'rcx', 'rdx', 'r8', 'r9', 'r10']) -def scalar_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): +def scalar_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: sizet): """标量(逐元素)加法: out[i] = a[i] + b[i], 一次 1 个 double。 `simd_add_array` 的未向量化对照: 标量 `vaddsd` vs SIMD `vaddpd`, @@ -485,7 +485,7 @@ jnz .Lsca_add_loop op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'rcx', 'r8', 'r9', 'r10']) -def scalar_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): +def scalar_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: sizet): """标量(逐元素)乘法: out[i] = a[i] * b[i], 一次 1 个 double。 `simd_mul_array` 的未向量化对照: 标量 `vmulsd` vs SIMD `vmulpd`, @@ -509,7 +509,7 @@ jnz .Lsca_mul_loop op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'rcx', 'r8', 'r9', 'r10']) -def scalar_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT): +def scalar_sqrt_array(a: t.CPtr, out: t.CPtr, n: sizet): """标量(逐元素)平方根: out[i] = sqrt(a[i]), 一次 1 个 double。 `simd_sqrt_array` 的未向量化对照: 标量 `vsqrtsd` vs SIMD `vsqrtpd`, @@ -531,7 +531,7 @@ jnz .Lsca_sqrt_loop op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'rcx', 'r8', 'r10']) -def simd_div_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): +def simd_div_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: sizet): """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 @@ -555,7 +555,7 @@ 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): +def simd_sqrt_array(a: t.CPtr, out: t.CPtr, n: sizet): """AVX2 batch: out[i:i+4] = sqrt(a[i:i+4]) ×4 展开:4 路独立 vsqrtpd 链隐藏平方根长延迟(吞吐受限场景显著提速)。""" c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} @@ -600,7 +600,7 @@ vzeroupper""", 'rcx', 'r8', 'r10', 'r11']) -def simd_abs_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT): +def simd_abs_array(a: t.CPtr, out: t.CPtr, n: sizet): """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 @@ -623,7 +623,7 @@ 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): +def simd_neg_array(a: t.CPtr, out: t.CPtr, n: sizet): """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 @@ -646,7 +646,7 @@ 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): +def simd_dot_array(a: t.CPtr, b: t.CPtr, n: sizet, out: t.CPtr): """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 diff --git a/viperstring.vp b/viperstring.vp deleted file mode 100644 index 212d749..0000000 --- a/viperstring.vp +++ /dev/null @@ -1 +0,0 @@ -from .string import * diff --git a/vqt6/__init__.vp b/vqt6/__init__.vp index 0ecdbab..6c92325 100644 --- a/vqt6/__init__.vp +++ b/vqt6/__init__.vp @@ -144,15 +144,14 @@ def qtree_click_toggle(tw: QtTreeWidgetPtr): vqt6_qtreewidgetitem_set_expanded(cur, 1 - ex) -@t.NoVTable -class QApplication: +novirtual class QApplication: """QApplication 包装(不透明指针)""" _ptr: QtAppPtr - def __new__(self, argv: list[str] | t.CPtr) -> t.CPtr: + def __new__(self, argv: list[str]*) -> t.CPtr: return stdlib.malloc(8) # 包装壳堆分配, 见本文件顶部说明 - def __init__(self, argv: list[str] | t.CPtr): + def __init__(self, argv: list[str]*): # 把 argv 转换为 argc/argv 数组 argc: t.CInt = 1 # Viper 端 argv 是 c_char_p 指针数组 @@ -193,8 +192,7 @@ class QApplication: vqt6_qapplication_set_font_family_utf8(self._ptr, family) -@t.NoVTable -class QWidget: +novirtual class QWidget: """QWidget 包装""" _ptr: QtWidgetPtr @@ -258,8 +256,7 @@ class QWidget: vqt6_qwidget_set_stylesheet_utf8(self._ptr, qss) -@t.NoVTable -class QLabel: +novirtual class QLabel: """QLabel 包装""" _ptr: QtLabelPtr @@ -298,8 +295,7 @@ class QLabel: vqt6_qwidget_set_stylesheet_utf8(self._ptr, qss) -@t.NoVTable -class QPushButton: +novirtual class QPushButton: """QPushButton 包装""" _ptr: QtPushButtonPtr @@ -372,8 +368,7 @@ class QPushButton: # ('QStatusBar'), 同样解析失败 → 调用方 fatal(mro_ret)。 # 故 QMainWindow.menuBar/statusBar 一律返回裸指针。 # ============================================================ -@t.NoVTable -class QAction: +novirtual class QAction: """QAction 包装""" _ptr: QtActionPtr @@ -425,8 +420,7 @@ class QAction: vqt6_qaction_connect_triggered(self._ptr, cb, data) -@t.NoVTable -class QMenu: +novirtual class QMenu: """QMenu 包装""" _ptr: QtMenuPtr @@ -471,8 +465,7 @@ class QMenu: vqt6_qmenu_clear(self._ptr) -@t.NoVTable -class QMenuBar: +novirtual class QMenuBar: """QMenuBar 包装""" _ptr: QtMenuBarPtr @@ -499,8 +492,7 @@ class QMenuBar: vqt6_qmenubar_clear(self._ptr) -@t.NoVTable -class QStatusBar: +novirtual class QStatusBar: """QStatusBar 包装""" _ptr: QtStatusBarPtr @@ -530,8 +522,7 @@ class QStatusBar: # ============================================================ # 窗口:QMainWindow(依赖上面的 QMenuBar / QStatusBar, 故排在其后) # ============================================================ -@t.NoVTable -class QMainWindow: +novirtual class QMainWindow: """QMainWindow 包装""" _ptr: QtMainWindowPtr @@ -594,8 +585,7 @@ class QMainWindow: _w_set_tool_tip(self._ptr, tip) -@t.NoVTable -class QDialog: +novirtual class QDialog: """QDialog 包装""" _ptr: QtDialogPtr @@ -650,8 +640,7 @@ class QDialog: # ============================================================ # 输入控件:QLineEdit / QCheckBox / QRadioButton # ============================================================ -@t.NoVTable -class QLineEdit: +novirtual class QLineEdit: """QLineEdit 包装""" _ptr: QtLineEditPtr @@ -718,8 +707,7 @@ class QLineEdit: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QCheckBox: +novirtual class QCheckBox: """QCheckBox 包装""" _ptr: QtCheckBoxPtr @@ -781,8 +769,7 @@ class QCheckBox: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QRadioButton: +novirtual class QRadioButton: """QRadioButton 包装""" _ptr: QtRadioButtonPtr @@ -838,8 +825,7 @@ class QRadioButton: # ============================================================ # 选择控件:QComboBox / QSlider / QSpinBox / QProgressBar # ============================================================ -@t.NoVTable -class QComboBox: +novirtual class QComboBox: """QComboBox 包装""" _ptr: QtComboBoxPtr @@ -910,8 +896,7 @@ class QComboBox: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QSlider: +novirtual class QSlider: """QSlider 包装""" _ptr: QtSliderPtr @@ -966,8 +951,7 @@ class QSlider: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QSpinBox: +novirtual class QSpinBox: """QSpinBox 包装""" _ptr: QtSpinBoxPtr @@ -1035,8 +1019,7 @@ class QSpinBox: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QProgressBar: +novirtual class QProgressBar: """QProgressBar 包装""" _ptr: QtProgressBarPtr @@ -1102,8 +1085,7 @@ class QProgressBar: # ============================================================ # 文本:QTextEdit / QPlainTextEdit # ============================================================ -@t.NoVTable -class QTextEdit: +novirtual class QTextEdit: """QTextEdit 包装""" _ptr: QtTextEditPtr @@ -1161,8 +1143,7 @@ class QTextEdit: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QPlainTextEdit: +novirtual class QPlainTextEdit: """QPlainTextEdit 包装""" _ptr: QtPlainTextEditPtr @@ -1221,8 +1202,7 @@ class QPlainTextEdit: # ============================================================ # 列表:QListWidget / QTabWidget / QStackedWidget # ============================================================ -@t.NoVTable -class QListWidget: +novirtual class QListWidget: """QListWidget 包装""" _ptr: QtListWidgetPtr @@ -1318,8 +1298,7 @@ class QListWidget: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QTreeWidgetItem: +novirtual class QTreeWidgetItem: """QTreeWidgetItem 包装(树节点,勾选态 0=未选 2=选中)""" _ptr: QtTreeWidgetItemPtr @@ -1372,8 +1351,7 @@ class QTreeWidgetItem: return vqt6_qtreewidgetitem_is_expanded(self._ptr) -@t.NoVTable -class QTreeWidget: +novirtual class QTreeWidget: """QTreeWidget 包装""" _ptr: QtTreeWidgetPtr @@ -1444,8 +1422,7 @@ class QTreeWidget: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QTabWidget: +novirtual class QTabWidget: """QTabWidget 包装""" _ptr: QtTabWidgetPtr @@ -1508,8 +1485,7 @@ class QTabWidget: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class QStackedWidget: +novirtual class QStackedWidget: """QStackedWidget 包装""" _ptr: QtStackedWidgetPtr @@ -1561,8 +1537,7 @@ class QStackedWidget: # ============================================================ # 布局:QHBoxLayout / QVBoxLayout / QGridLayout # ============================================================ -@t.NoVTable -class QHBoxLayout: +novirtual class QHBoxLayout: """QHBoxLayout 包装(addWidget 传控件 ._ptr)""" _ptr: QtBoxLayoutPtr @@ -1596,8 +1571,7 @@ class QHBoxLayout: vqt6_qlayout_set_contents_margins(self._ptr, left, top, right, bottom) -@t.NoVTable -class QVBoxLayout: +novirtual class QVBoxLayout: """QVBoxLayout 包装(addWidget 传控件 ._ptr)""" _ptr: QtBoxLayoutPtr @@ -1631,8 +1605,7 @@ class QVBoxLayout: vqt6_qlayout_set_contents_margins(self._ptr, left, top, right, bottom) -@t.NoVTable -class QGridLayout: +novirtual class QGridLayout: """QGridLayout 包装(addWidget 传控件 ._ptr)""" _ptr: QtGridLayoutPtr @@ -1660,8 +1633,7 @@ class QGridLayout: # ============================================================ # 对话框:QMessageBox / QFileDialog(静态方法) # ============================================================ -@t.NoVTable -class QMessageBox: +novirtual class QMessageBox: """QMessageBox 静态对话框""" _ptr: QtMessageBoxPtr @@ -1725,8 +1697,7 @@ class QMessageBox: vqt6_qstring_free(qs_text) -@t.NoVTable -class QFileDialog: +novirtual class QFileDialog: """QFileDialog 静态对话框""" _ptr: QtFileDialogPtr @@ -1774,8 +1745,7 @@ class QFileDialog: # ============================================================ # 定时器:QTimer # ============================================================ -@t.NoVTable -class QTimer: +novirtual class QTimer: """QTimer 包装""" _ptr: QtTimerPtr @@ -1812,8 +1782,7 @@ class QTimer: # ============================================================ # 绘图基础:QColor / QFont # ============================================================ -@t.NoVTable -class QColor: +novirtual class QColor: """QColor 包装""" _ptr: QtColorPtr @@ -1835,8 +1804,7 @@ class QColor: return vqt6_qcolor_alpha(self._ptr) -@t.NoVTable -class QFont: +novirtual class QFont: """QFont 包装""" _ptr: QtFontPtr @@ -1889,8 +1857,7 @@ def clipboard_text() -> str: # ============================================================ # 自绘控件:Canvas / Graph3D / ChartView # ============================================================ -@t.NoVTable -class Canvas: +novirtual class Canvas: """手绘板 / 28x28 灰度显示控件 手绘模式下鼠标左键描绘; toMnist28 把笔迹按 MNIST 预处理 @@ -1969,8 +1936,7 @@ class Canvas: vqt6_qwidget_set_stylesheet_utf8(self._ptr, qss) -@t.NoVTable -class Graph3D: +novirtual class Graph3D: """软件 3D 神经网络结构图控件 层次沿 Z 轴排布(输入层在最远端), 各层按近正方形网格铺开; @@ -2062,8 +2028,7 @@ class Graph3D: _w_set_enabled(self._ptr, enabled) -@t.NoVTable -class ChartView: +novirtual class ChartView: """Qt Charts 折线图控件(右侧 Y 轴可选) 典型用法: diff --git a/vqt6/_qtcore.vp b/vqt6/_qtcore.vp index f9f44b6..6da2194 100644 --- a/vqt6/_qtcore.vp +++ b/vqt6/_qtcore.vp @@ -13,11 +13,11 @@ from vqt6._types import * # QString — UTF-16 字符串 # ============================================================ # 创建 QString(从 UTF-8 C 字符串) -def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass +def vqt6_qstring_create(utf8: char | t.CPtr) -> QtStringPtr | t.State: pass # 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0) # buf 需足够大(建议 4 * qstring.length() + 1) -def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: char | t.CPtr, buf_size: sizet) -> sizet | t.State: pass # 释放 QString def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass @@ -33,15 +33,15 @@ def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.Sta # QString 拼接(返回新 QString) def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass -def vqt6_asset_url_utf8(buf: t.CChar | t.CPtr, buf_size: t.CSizeT, name: t.CChar | t.CPtr) -> t.State: pass +def vqt6_asset_url_utf8(buf: char | t.CPtr, buf_size: sizet, name: char | t.CPtr) -> t.State: pass # ============================================================ # QByteArray — 字节数组 # ============================================================ -def vqt6_qbytearray_create(data: t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass -def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CPtr | t.State: pass -def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass +def vqt6_qbytearray_create(data: t.CPtr, size: sizet) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: sizet*) -> t.CPtr | t.State: pass +def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> sizet | t.State: pass def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass @@ -60,11 +60,11 @@ def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass # typedef void (*vqt6_callback_t)(void* user_data); # vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理 # 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表 -def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, - receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: char | t.CPtr, + receiver: QtObjectPtr, slot_name: char | t.CPtr) -> t.CInt | t.State: pass -def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, - receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: char | t.CPtr, + receiver: QtObjectPtr, slot_name: char | t.CPtr) -> t.CInt | t.State: pass # 事件过滤器 def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass @@ -74,7 +74,7 @@ def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) # ============================================================ # QCoreApplication — 事件循环基类 # ============================================================ -def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_create(app_name: char | t.CPtr) -> QtCoreAppPtr | t.State: pass def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass @@ -163,5 +163,5 @@ def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用 # ============================================================ # 剪贴板 — 复制链接等 # ============================================================ -def vqt6_clipboard_set_text_utf8(text: t.CChar | t.CPtr) -> t.State: pass -def vqt6_clipboard_text_utf8(buf: t.CChar | t.CPtr, buf_size: t.CInt) -> t.CInt | t.State: pass +def vqt6_clipboard_set_text_utf8(text: char | t.CPtr) -> t.State: pass +def vqt6_clipboard_text_utf8(buf: char | t.CPtr, buf_size: t.CInt) -> t.CInt | t.State: pass diff --git a/vqt6/_qtgui.vp b/vqt6/_qtgui.vp index 2f597a9..a1ab457 100644 --- a/vqt6/_qtgui.vp +++ b/vqt6/_qtgui.vp @@ -70,7 +70,7 @@ extern def vqt6_qfontmetrics_free(fm: QtFontMetricsPtr) extern def vqt6_qpixmap_create() -> QtPixmapPtr extern def vqt6_qpixmap_create_with_size(w: t.CInt, h: t.CInt) -> QtPixmapPtr extern def vqt6_qpixmap_load(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt -extern def vqt6_qpixmap_load_from_data(pm: QtPixmapPtr, data: t.CPtr, size: t.CSizeT) -> t.CInt +extern def vqt6_qpixmap_load_from_data(pm: QtPixmapPtr, data: t.CPtr, size: sizet) -> t.CInt extern def vqt6_qpixmap_save(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt extern def vqt6_qpixmap_width(pm: QtPixmapPtr) -> t.CInt extern def vqt6_qpixmap_height(pm: QtPixmapPtr) -> t.CInt diff --git a/vqt6/_qtnetwork.vp b/vqt6/_qtnetwork.vp index c82b864..dd7b164 100644 --- a/vqt6/_qtnetwork.vp +++ b/vqt6/_qtnetwork.vp @@ -60,11 +60,11 @@ def vqt6_qabstractsocket_is_open(socket: QtAbstractSocketPtr) -> t.CInt | t.Stat def vqt6_qabstractsocket_flush(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass def vqt6_qabstractsocket_close(socket: QtAbstractSocketPtr) -> t.State: pass def vqt6_qabstractsocket_abort(socket: QtAbstractSocketPtr) -> t.State: pass -def vqt6_qabstractsocket_read(socket: QtAbstractSocketPtr, buf: t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass -def vqt6_qabstractsocket_read_all(socket: QtAbstractSocketPtr, out_size: t.CSizeT | t.CPtr) -> t.CPtr | t.State: pass -def vqt6_qabstractsocket_write(socket: QtAbstractSocketPtr, data: t.CPtr, size: t.CSizeT) -> t.CSizeT | t.State: pass -def vqt6_qabstractsocket_bytes_available(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass -def vqt6_qabstractsocket_bytes_to_write(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_read(socket: QtAbstractSocketPtr, buf: t.CPtr, max_size: sizet) -> sizet | t.State: pass +def vqt6_qabstractsocket_read_all(socket: QtAbstractSocketPtr, out_size: sizet*) -> t.CPtr | t.State: pass +def vqt6_qabstractsocket_write(socket: QtAbstractSocketPtr, data: t.CPtr, size: sizet) -> sizet | t.State: pass +def vqt6_qabstractsocket_bytes_available(socket: QtAbstractSocketPtr) -> sizet | t.State: pass +def vqt6_qabstractsocket_bytes_to_write(socket: QtAbstractSocketPtr) -> sizet | t.State: pass def vqt6_qabstractsocket_peer_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass def vqt6_qabstractsocket_peer_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass def vqt6_qabstractsocket_local_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass @@ -92,10 +92,10 @@ def vqt6_qudpsocket_create_with_parent(parent: QtObjectPtr) -> QtUdpSocketPtr | def vqt6_qudpsocket_bind(socket: QtUdpSocketPtr, port: t.CUInt16T) -> t.CInt | t.State: pass def vqt6_qudpsocket_bind_with_addr(socket: QtUdpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.CInt | t.State: pass def vqt6_qudpsocket_close(socket: QtUdpSocketPtr) -> t.State: pass -def vqt6_qudpsocket_write_datagram(socket: QtUdpSocketPtr, data: t.CPtr, size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T) -> t.CSizeT | t.State: pass -def vqt6_qudpsocket_read_datagram(socket: QtUdpSocketPtr, data: t.CPtr, max_size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T | t.CPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_write_datagram(socket: QtUdpSocketPtr, data: t.CPtr, size: sizet, host: QtHostAddressPtr, port: t.CUInt16T) -> sizet | t.State: pass +def vqt6_qudpsocket_read_datagram(socket: QtUdpSocketPtr, data: t.CPtr, max_size: sizet, host: QtHostAddressPtr, port: t.CUInt16T | t.CPtr) -> sizet | t.State: pass def vqt6_qudpsocket_has_pending_datagrams(socket: QtUdpSocketPtr) -> t.CInt | t.State: pass -def vqt6_qudpsocket_pending_datagram_size(socket: QtUdpSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_pending_datagram_size(socket: QtUdpSocketPtr) -> sizet | t.State: pass def vqt6_qudpsocket_join_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass def vqt6_qudpsocket_leave_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass @@ -109,8 +109,8 @@ def vqt6_qnetworkrequest_set_url(req: QtNetworkRequestPtr, url: QtStringPtr) -> def vqt6_qnetworkrequest_url(req: QtNetworkRequestPtr) -> QtStringPtr | t.State: pass def vqt6_qnetworkrequest_set_header(req: QtNetworkRequestPtr, header_type: t.CInt, value: QtVariantPtr) -> t.State: pass def vqt6_qnetworkrequest_header(req: QtNetworkRequestPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass -def vqt6_qnetworkrequest_set_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, value: t.CPtr, value_size: t.CSizeT) -> t.State: pass -def vqt6_qnetworkrequest_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CPtr | t.State: pass +def vqt6_qnetworkrequest_set_raw_header(req: QtNetworkRequestPtr, header_name: char | t.CPtr, value: t.CPtr, value_size: sizet) -> t.State: pass +def vqt6_qnetworkrequest_raw_header(req: QtNetworkRequestPtr, header_name: char | t.CPtr, out_size: sizet*) -> t.CPtr | t.State: pass def vqt6_qnetworkrequest_set_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt, value: QtVariantPtr) -> t.State: pass def vqt6_qnetworkrequest_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt) -> QtVariantPtr | t.State: pass def vqt6_qnetworkrequest_free(req: QtNetworkRequestPtr) -> t.State: pass @@ -122,8 +122,8 @@ def vqt6_qnetworkrequest_free(req: QtNetworkRequestPtr) -> t.State: pass def vqt6_qnetworkaccessmanager_create() -> QtNetworkAccessManagerPtr | t.State: pass def vqt6_qnetworkaccessmanager_create_with_parent(parent: QtObjectPtr) -> QtNetworkAccessManagerPtr | t.State: pass def vqt6_qnetworkaccessmanager_get(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass -def vqt6_qnetworkaccessmanager_post(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass -def vqt6_qnetworkaccessmanager_put(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_post(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CPtr, size: sizet) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_put(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CPtr, size: sizet) -> QtNetworkReplyPtr | t.State: pass def vqt6_qnetworkaccessmanager_delete_resource(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass def vqt6_qnetworkaccessmanager_head(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass def vqt6_qnetworkaccessmanager_set_cookie_store(nam: QtNetworkAccessManagerPtr, store: QtObjectPtr) -> t.State: pass @@ -139,14 +139,14 @@ def vqt6_qnetworkreply_error_string(reply: QtNetworkReplyPtr) -> QtStringPtr | t def vqt6_qnetworkreply_is_finished(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass def vqt6_qnetworkreply_is_running(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass def vqt6_qnetworkreply_abort(reply: QtNetworkReplyPtr) -> t.State: pass -def vqt6_qnetworkreply_read(reply: QtNetworkReplyPtr, buf: t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass -def vqt6_qnetworkreply_read_all(reply: QtNetworkReplyPtr, out_size: t.CSizeT | t.CPtr) -> t.CPtr | t.State: pass -def vqt6_qnetworkreply_bytes_available(reply: QtNetworkReplyPtr) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_read(reply: QtNetworkReplyPtr, buf: t.CPtr, max_size: sizet) -> sizet | t.State: pass +def vqt6_qnetworkreply_read_all(reply: QtNetworkReplyPtr, out_size: sizet*) -> t.CPtr | t.State: pass +def vqt6_qnetworkreply_bytes_available(reply: QtNetworkReplyPtr) -> sizet | t.State: pass def vqt6_qnetworkreply_header(reply: QtNetworkReplyPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass -def vqt6_qnetworkreply_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CPtr | t.State: pass +def vqt6_qnetworkreply_raw_header(reply: QtNetworkReplyPtr, header_name: char | t.CPtr, out_size: sizet*) -> t.CPtr | t.State: pass def vqt6_qnetworkreply_attribute(reply: QtNetworkReplyPtr, attribute_code: t.CInt) -> QtVariantPtr | t.State: pass def vqt6_qnetworkreply_attribute_int(reply: QtNetworkReplyPtr, attribute_code: t.CInt, default_value: t.CInt) -> t.CInt | t.State: pass -def vqt6_qnetworkreply_set_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, value: t.CPtr, value_size: t.CSizeT) -> t.State: pass +def vqt6_qnetworkreply_set_raw_header(reply: QtNetworkReplyPtr, header_name: char | t.CPtr, value: t.CPtr, value_size: sizet) -> t.State: pass # ============================================================ diff --git a/vqt6/_qtwidgets.vp b/vqt6/_qtwidgets.vp index 5252f4a..0aa0279 100644 --- a/vqt6/_qtwidgets.vp +++ b/vqt6/_qtwidgets.vp @@ -21,7 +21,7 @@ def vqt6_qapplication_desktop_height(app: QtAppPtr) -> t.CInt | t.State: pass def vqt6_qapplication_set_quit_on_last_window_closed(app: QtAppPtr, quit: t.CInt) -> t.State: pass def vqt6_qapplication_quit_on_last_window_closed(app: QtAppPtr) -> t.CInt | t.State: pass def vqt6_qapplication_set_theme_palette(app: QtAppPtr, theme: t.CInt) -> t.State: pass -def vqt6_qapplication_set_font_family_utf8(app: QtAppPtr, family: t.CChar | t.CPtr) -> t.State: pass +def vqt6_qapplication_set_font_family_utf8(app: QtAppPtr, family: char | t.CPtr) -> t.State: pass def vqt6_enable_custom_item_checks(app: QtAppPtr) -> t.State: pass @@ -85,7 +85,7 @@ def vqt6_qwidget_unset_cursor(widget: QtWidgetPtr) -> t.State: pass # 工具提示 def vqt6_qwidget_set_tool_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass # Qt 样式表(QSS):直接传 Viper str -def vqt6_qwidget_set_stylesheet_utf8(widget: QtWidgetPtr, qss: t.CChar | t.CPtr) -> t.State: pass +def vqt6_qwidget_set_stylesheet_utf8(widget: QtWidgetPtr, qss: char | t.CPtr) -> t.State: pass def vqt6_qwidget_tool_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass # 状态栏提示 @@ -138,7 +138,7 @@ def vqt6_qlabel_create_with_text(text: QtStringPtr) -> QtLabelPtr | t.State: pas def vqt6_qlabel_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLabelPtr | t.State: pass def vqt6_qlabel_set_text(label: QtLabelPtr, text: QtStringPtr) -> t.State: pass # UTF-8 便捷版:直接传 Viper str,避免手动创建/释放 QString -def vqt6_qlabel_set_text_utf8(label: QtLabelPtr, text: t.CChar | t.CPtr) -> t.State: pass +def vqt6_qlabel_set_text_utf8(label: QtLabelPtr, text: char | t.CPtr) -> t.State: pass def vqt6_qlabel_text(label: QtLabelPtr) -> QtStringPtr | t.State: pass def vqt6_qlabel_set_alignment(label: QtLabelPtr, alignment: t.CInt) -> t.State: pass def vqt6_qlabel_alignment(label: QtLabelPtr) -> t.CInt | t.State: pass @@ -211,8 +211,8 @@ def vqt6_qplaintextedit_to_plain_text(pte: QtPlainTextEditPtr) -> QtStringPtr | def vqt6_qplaintextedit_set_plain_text(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass def vqt6_qplaintextedit_append(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass # UTF-8 便捷版:直接传 Viper str,避免手动创建/释放 QString -def vqt6_qplaintextedit_append_utf8(pte: QtPlainTextEditPtr, text: t.CChar | t.CPtr) -> t.State: pass -def vqt6_qplaintextedit_set_plain_text_utf8(pte: QtPlainTextEditPtr, text: t.CChar | t.CPtr) -> t.State: pass +def vqt6_qplaintextedit_append_utf8(pte: QtPlainTextEditPtr, text: char | t.CPtr) -> t.State: pass +def vqt6_qplaintextedit_set_plain_text_utf8(pte: QtPlainTextEditPtr, text: char | t.CPtr) -> t.State: pass def vqt6_qplaintextedit_clear(pte: QtPlainTextEditPtr) -> t.State: pass def vqt6_qplaintextedit_set_read_only(pte: QtPlainTextEditPtr, ro: t.CInt) -> t.State: pass def vqt6_qplaintextedit_line_count(pte: QtPlainTextEditPtr) -> t.CInt | t.State: pass @@ -597,14 +597,14 @@ def vqt6_graph3d_reset_view(g: QtGraph3DPtr) -> t.State: pass # ============================================================ def vqt6_chartview_create() -> QtChartViewPtr | t.State: pass def vqt6_chartview_create_with_parent(parent: QtWidgetPtr) -> QtChartViewPtr | t.State: pass -def vqt6_chartview_add_line(view: QtChartViewPtr, name: t.CChar | t.CPtr, r: t.CInt, g: t.CInt, b: t.CInt, right_axis: t.CInt) -> QtChartSeriesPtr | t.State: pass +def vqt6_chartview_add_line(view: QtChartViewPtr, name: char | t.CPtr, r: t.CInt, g: t.CInt, b: t.CInt, right_axis: t.CInt) -> QtChartSeriesPtr | t.State: pass def vqt6_chartview_append(view: QtChartViewPtr, series: QtChartSeriesPtr, x: t.CDouble, y: t.CDouble) -> t.State: pass def vqt6_chartview_clear_series(view: QtChartViewPtr, series: QtChartSeriesPtr) -> t.State: pass def vqt6_chartview_clear_all(view: QtChartViewPtr) -> t.State: pass def vqt6_chartview_autoscale(view: QtChartViewPtr) -> t.State: pass -def vqt6_chartview_set_title(view: QtChartViewPtr, title: t.CChar | t.CPtr) -> t.State: pass +def vqt6_chartview_set_title(view: QtChartViewPtr, title: char | t.CPtr) -> t.State: pass def vqt6_chartview_set_legend_visible(view: QtChartViewPtr, visible: t.CInt) -> t.State: pass def vqt6_chartview_set_background(view: QtChartViewPtr, r: t.CInt, g: t.CInt, b: t.CInt) -> t.State: pass def vqt6_chartview_set_max_points(view: QtChartViewPtr, max_points: t.CInt) -> t.State: pass -def vqt6_chartview_open_zoom(view: QtChartViewPtr, title: t.CChar | t.CPtr) -> QtWidgetPtr | t.State: pass +def vqt6_chartview_open_zoom(view: QtChartViewPtr, title: char | t.CPtr) -> QtWidgetPtr | t.State: pass def vqt6_chartview_sync_zoom(view: QtChartViewPtr) -> t.State: pass diff --git a/vrandom.vp b/vrandom.vp deleted file mode 100644 index ecfa119..0000000 --- a/vrandom.vp +++ /dev/null @@ -1,379 +0,0 @@ -# vrandom - Hardware Random Number Generation Library -# Implemented using inline assembly based on x86 RDRAND / RDSEED instructions -import t, c -import vipermath - - -# Retry limit (RDRAND usually doesn't need retries, RDSEED might) -RDRAND_RETRY_LIMIT: t.CDefine = 10 -RDSEED_RETRY_LIMIT: t.CDefine = 100 - - -# ============================================================ -# RDRAND - Hardware random numbers (output from a pseudo-random number generator) -# ============================================================ - -def rdrand16() -> t.CUInt16T: - val: t.CUInt32T = 0 - c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC]) - return t.CUInt16T(val) - - -def rdrand32() -> t.CUInt32T: - val: t.CUInt32T = 0 - c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC]) - return val - - -def rdrand64() -> t.CUInt64T: - val: t.CUInt64T = 0 - c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC]) - return val - - -# ============================================================ -# RDSEED - Hardware random seeds (direct output from entropy source) -# ============================================================ - -def rdseed16() -> t.CUInt16T: - val: t.CUInt32T = 0 - c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC]) - return t.CUInt16T(val) - - -def rdseed32() -> t.CUInt32T: - val: t.CUInt32T = 0 - c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC]) - return val - - -def rdseed64() -> t.CUInt64T: - val: t.CUInt64T = 0 - c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC]) - return val - - -# ============================================================ -# Step version (with success flag, matching GCC builtin interface) -# Returns success flag: 1 on success, 0 on failure; random value written to *p -# ============================================================ - -def rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt: - val: t.CUInt32T = 0 - ok: t.CUInt32T = 0 - c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} - setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) - p[0] = t.CUInt16T(val) - return t.CInt(ok) - - -def rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt: - val: t.CUInt32T = 0 - ok: t.CUInt32T = 0 - c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} - setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) - p[0] = val - return t.CInt(ok) - - -def rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt: - val: t.CUInt64T = 0 - ok: t.CUInt32T = 0 - c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} - setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) - p[0] = val - return t.CInt(ok) - - -def rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt: - val: t.CUInt32T = 0 - ok: t.CUInt32T = 0 - c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} - setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) - p[0] = t.CUInt16T(val) - return t.CInt(ok) - - -def rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt: - val: t.CUInt32T = 0 - ok: t.CUInt32T = 0 - c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} - setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) - p[0] = val - return t.CInt(ok) - - -def rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt: - val: t.CUInt64T = 0 - ok: t.CUInt32T = 0 - c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} - setc al - movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", - out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], - op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) - p[0] = val - return t.CInt(ok) - - -# ============================================================ -# Convenient interface with retry (automatically retries until it succeeds or reaches the limit) -# ============================================================ - -def random_u16() -> t.CUInt16T: - r: t.CUInt16T = 0 - i: t.CInt = 0 - while i < RDRAND_RETRY_LIMIT: - if rdrand16_step(c.Addr(r)) == 1: - return r - i += 1 - return 0 - - -def random_u32() -> t.CUInt32T: - r: t.CUInt32T = 0 - i: t.CInt = 0 - while i < RDRAND_RETRY_LIMIT: - if rdrand32_step(c.Addr(r)) == 1: - return r - i += 1 - return 0 - - -def random_u64() -> t.CUInt64T: - r: t.CUInt64T = 0 - i: t.CInt = 0 - while i < RDRAND_RETRY_LIMIT: - if rdrand64_step(c.Addr(r)) == 1: - return r - i += 1 - return 0 - - -def seed_u16() -> t.CUInt16T: - r: t.CUInt16T = 0 - i: t.CInt = 0 - while i < RDSEED_RETRY_LIMIT: - if rdseed16_step(c.Addr(r)) == 1: - return r - i += 1 - return 0 - - -def seed_u32() -> t.CUInt32T: - r: t.CUInt32T = 0 - i: t.CInt = 0 - while i < RDSEED_RETRY_LIMIT: - if rdseed32_step(c.Addr(r)) == 1: - return r - i += 1 - return 0 - - -def seed_u64() -> t.CUInt64T: - r: t.CUInt64T = 0 - i: t.CInt = 0 - while i < RDSEED_RETRY_LIMIT: - if rdseed64_step(c.Addr(r)) == 1: - return r - i += 1 - return 0 - - -# ============================================================ -# Python random standard library function implementations -# Default types: t.CUInt64T (u64), t.CDouble (f64), t.CInt (i32) -# ============================================================ - -# ---------- ONE, Random integers ---------- - -def randint(a: t.CInt, b: t.CInt) -> t.CInt: - return t.CInt(a + t.CInt(random_u64() % t.CUInt64T(b - a + 1))) - - -def randrange(start: t.CInt, stop: t.CInt, step: t.CInt = 1) -> t.CInt: - width: t.CInt = 0 - if step > 0: - width = (stop - start + step - 1) // step - else: - width = (start - stop - step - 1) // (-step) - return t.CInt(start + t.CInt(random_u64() % t.CUInt64T(width)) * step) - - -def getrandbits(k: t.CInt) -> t.CUInt64T: - r: t.CUInt64T = rdrand64() - if k >= 64: - return r - mask: t.CUInt64T = (t.CUInt64T(1) << k) - t.CUInt64T(1) - return r & mask - - -# ---------- TWO, Random floating-point numbers ---------- - -def random() -> t.CDouble: - return t.CDouble(rdrand64() >> 11) * (t.CDouble(1.0) / t.CDouble(9007199254740992.0)) - - -def uniform(a: t.CDouble, b: t.CDouble) -> t.CDouble: - return a + (b - a) * random() - - -def triangular(low: t.CDouble, high: t.CDouble, mode: t.CDouble) -> t.CDouble: - u: t.CDouble = random() - c: t.CDouble = (mode - low) / (high - low) - if u > c: - u = t.CDouble(1.0) - u - c = t.CDouble(1.0) - c - tmp: t.CDouble = low - low = high - high = tmp - return low + (high - low) * vipermath.sqrt(u * c) - - -def betavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: - y: t.CDouble = gammavariate(alpha, t.CDouble(1.0)) - if y != t.CDouble(0.0): - return y / (y + gammavariate(beta, t.CDouble(1.0))) - return t.CDouble(0.0) - - -def expovariate(lambd: t.CDouble) -> t.CDouble: - u: t.CDouble = random() - if u < t.CDouble(1e-300): - u = t.CDouble(1e-300) - return -vipermath.log(t.CDouble(1.0) - u) / lambd - - -def gammavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: - u: t.CDouble = t.CDouble(0.0) - d: t.CDouble = t.CDouble(0.0) - c: t.CDouble = t.CDouble(0.0) - x: t.CDouble = t.CDouble(0.0) - v: t.CDouble = t.CDouble(0.0) - if alpha <= t.CDouble(0.0) or beta <= t.CDouble(0.0): - return t.CDouble(0.0) - if alpha < t.CDouble(1.0): - u = random() - if u < t.CDouble(1e-300): - u = t.CDouble(1e-300) - return gammavariate(alpha + t.CDouble(1.0), beta) * vipermath.pow(u, t.CDouble(1.0) / alpha) - d = alpha - t.CDouble(1.0) / t.CDouble(3.0) - c = t.CDouble(1.0) / vipermath.sqrt(t.CDouble(9.0) * d) - while 1: - x = gauss(t.CDouble(0.0), t.CDouble(1.0)) - v = t.CDouble(1.0) + c * x - if v > t.CDouble(0.0): - v = v * v * v - u = random() - if u < t.CDouble(1.0) - t.CDouble(0.0331) * x * x * x * x: - return d * v * beta - if vipermath.log(u) < t.CDouble(0.5) * x * x + d * (t.CDouble(1.0) - v + vipermath.log(v)): - return d * v * beta - - -def gauss(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: - u1: t.CDouble = random() - u2: t.CDouble = random() - if u1 < t.CDouble(1e-300): - u1 = t.CDouble(1e-300) - z0: t.CDouble = vipermath.sqrt(t.CDouble(-2.0) * vipermath.log(u1)) * vipermath.cos(t.CDouble(2.0) * vipermath.U_M_PI * u2) - return mu + sigma * z0 - - -def normalvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: - NV_MAGICCONST: t.CDouble = t.CDouble(1.7155277699214135) - u1: t.CDouble = t.CDouble(0.0) - u2: t.CDouble = t.CDouble(0.0) - z: t.CDouble = t.CDouble(0.0) - zz: t.CDouble = t.CDouble(0.0) - while 1: - u1 = random() - u2 = random() - if u2 < t.CDouble(1e-300): - continue - z = NV_MAGICCONST * (u1 - t.CDouble(0.5)) / u2 - zz = z * z / t.CDouble(4.0) - if zz <= t.CDouble(0.0) - vipermath.log(u2): - break - return mu + z * sigma - - -def lognormvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: - return vipermath.exp(gauss(mu, sigma)) - - -def vonmisesvariate(mu: t.CDouble, kappa: t.CDouble) -> t.CDouble: - if kappa <= t.CDouble(1e-6): - return vipermath.U_M_PI * t.CDouble(2.0) * random() - s: t.CDouble = t.CDouble(0.5) / kappa - r: t.CDouble = s + vipermath.sqrt(t.CDouble(1.0) + s * s) - u1: t.CDouble = t.CDouble(0.0) - u2: t.CDouble = t.CDouble(0.0) - u3: t.CDouble = t.CDouble(0.0) - z: t.CDouble = t.CDouble(0.0) - d: t.CDouble = t.CDouble(0.0) - q: t.CDouble = t.CDouble(0.0) - f: t.CDouble = t.CDouble(0.0) - theta: t.CDouble = t.CDouble(0.0) - two_pi: t.CDouble = vipermath.U_M_PI * t.CDouble(2.0) - while 1: - u1 = random() - z = vipermath.cos(vipermath.U_M_PI * u1) - d = t.CDouble(1.0) / (r + z) - u2 = random() - if u2 < t.CDouble(1.0) - d * d: - break - if u2 < (t.CDouble(1.0) - z) * vipermath.exp(kappa * (z - t.CDouble(1.0)) - d * kappa * r): - break - q = t.CDouble(1.0) / r - f = (q + z) / (t.CDouble(1.0) + q * z) - u3 = random() - if u3 > t.CDouble(0.5): - theta = mu + vipermath.acos(f) - else: - theta = mu - vipermath.acos(f) - while theta < t.CDouble(0.0): - theta += two_pi - while theta >= two_pi: - theta -= two_pi - return theta - - -def paretovariate(alpha: t.CDouble) -> t.CDouble: - u: t.CDouble = random() - if u < t.CDouble(1e-300): - u = t.CDouble(1e-300) - return t.CDouble(1.0) / vipermath.pow(t.CDouble(1.0) - u, t.CDouble(1.0) / alpha) - - -def weibullvariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: - u: t.CDouble = random() - if u < t.CDouble(1e-300): - u = t.CDouble(1e-300) - return alpha * vipermath.pow(t.CDouble(-1.0) * vipermath.log(t.CDouble(1.0) - u), t.CDouble(1.0) / beta) diff --git a/vthreading.vp b/vthreading.vp index c3bfe78..954b228 100644 --- a/vthreading.vp +++ b/vthreading.vp @@ -70,14 +70,13 @@ class Thread: def wait_handle(h: HANDLE, ms: ULONG) -> BOOL: - """等待线程/进程句柄变为有信号(超时 ms),返回是否成功等待到。""" + """Wait for a thread/process handle to become signaled (timeout in ms), returns whether it was successfully waited on.""" return WaitForSingleObject(h, ms) == WAIT_OBJECT_0 def close_handle(h: HANDLE): - """关闭线程/进程句柄(配合 wait_handle 使用,避免句柄泄漏)。""" - if h != NULL: - CloseHandle(h) + """Close a thread/process handle (used together with wait_handle to avoid handle leaks).""" + if h != NULL: CloseHandle(h) class local: diff --git a/w32/fileio.vp b/w32/fileio.vp index 54677d2..3b3239e 100644 --- a/w32/fileio.vp +++ b/w32/fileio.vp @@ -2,6 +2,7 @@ import t, c from stdint import * import stdio import stdlib +import string import w32.win32base import w32.win32file @@ -36,24 +37,75 @@ SHARE_READ: t.CDefine = 0x00000001 SHARE_WRITE: t.CDefine = 0x00000002 SHARE_DELETE: t.CDefine = 0x00000004 +# ============================================================================= +# 环境变量展开(路径层唯一实现) +# +# 用途:工程配置里的路径可写成 %temp%/viperepl/.tpv_build 这类形式,需在打开 +# 文件前展开为实路径。ExpandEnvironmentStringsA 由 kernel32 提供,与 +# SetConsoleOutputCP 同属进程启动即可用的 API(无额外初始化时序要求)。 +# +# 安全约束(保证既有路径语义逐字不变): +# * 只在路径含 '%' 时才调用 Win32(无 '%' 的绝大多数路径零开销); +# * 展开失败(返回 0)或结果长度超过缓冲上限(返回所需长度 > 上限,此时 +# 目标缓冲内容不可用)一律返回 None,调用方沿用原路径; +# * 不做任何前缀/分隔符规范化:UNC(\\server\share)、相对路径、盘符、 +# ".." 段、长路径都原样交给 Win32,展开成功时也只替换 %VAR% 片段; +# * A 系列展开结果与 CreateDirectoryA / CreateProcessA / FindFirstFileA 等 +# 既有 A 系列调用点同编码(系统 ANSI 代码页),不会引入编码错配。 +# 返回 stdlib.malloc 的新串(调用方负责 stdlib.free);无需展开或失败返回 None。 +# ============================================================================= +extern def ExpandEnvironmentStringsA(lpSrc: LPCSTR, lpDst: CHARPTR, nSize: ULONG) -> ULONG + +# 展开结果缓冲上限(含 NUL;超过即视为失败并退回原路径) +EXPAND_ENV_CAP: t.CDefine = 4096 + + +def ExpandEnvironmentPath(path: str) -> str: + """路径含 '%' 时按环境变量展开:返回新串(调用方 stdlib.free);无需/失败返回 None""" + if path is None: + return None + # 快速路径:无 '%' 直接返回 None(不调用 Win32,路径逐字不变) + if string.strchr(path, '%') is None: + return None + buf: str = stdlib.malloc(EXPAND_ENV_CAP) + if buf is None: + return None + n: ULONG = ExpandEnvironmentStringsA(path, buf, ULONG(EXPAND_ENV_CAP)) + # n == 0:失败;n > 上限:结果所需的 TCHAR 数(含 NUL)超过缓冲,内容不可用 + if n == 0 or int(n) > EXPAND_ENV_CAP: + stdlib.free(buf) + return None + return buf + def create_file_utf8(path: str, access: ULONG, share: ULONG, disposition: ULONG, flags: ULONG) -> w32.win32base.HANDLE: """按路径编码打开/创建文件。 + 含 '%' 的路径先做环境变量展开(ExpandEnvironmentPath,失败则原样使用); 合法 UTF-8(源码字面量、Qt 返回的中文目录) → 转 UTF-16 走 CreateFileW; 非法 UTF-8(如命令行 argv 的 ANSI 串) → 退回 CreateFileA。详见 win32base""" - if w32.win32base.utf8_is_valid(path) == 0: - return w32.win32file.CreateFileA(path, access, share, None, disposition, - flags, None) - wp: w32.win32base.WCHARPTR = w32.win32base.utf8_to_utf16_dup(path) - if wp is None: - # 宽字符缓冲分配失败: 走 A 路径, 非 ASCII 路径在此自然失败并返回 - # INVALID_HANDLE_VALUE(不掩盖错误, 只是复用同一失败出口) - return w32.win32file.CreateFileA(path, access, share, None, disposition, - flags, None) - h: w32.win32base.HANDLE = w32.win32file.CreateFileW( - t.CPtr(wp), access, share, None, disposition, flags, None) - stdlib.free(wp) + # 展开结果的生命周期覆盖到 CreateFile 调用之后(句柄由内核持有,串用完即弃) + ep: str = ExpandEnvironmentPath(path) + use_path: str = path + if ep is not None: + use_path = ep + h: w32.win32base.HANDLE = None + if w32.win32base.utf8_is_valid(use_path) == 0: + h = w32.win32file.CreateFileA(use_path, access, share, None, disposition, + flags, None) + else: + wp: w32.win32base.WCHARPTR = w32.win32base.utf8_to_utf16_dup(use_path) + if wp is None: + # 宽字符缓冲分配失败: 走 A 路径, 非 ASCII 路径在此自然失败并返回 + # INVALID_HANDLE_VALUE(不掩盖错误, 只是复用同一失败出口) + h = w32.win32file.CreateFileA(use_path, access, share, None, disposition, + flags, None) + else: + h = w32.win32file.CreateFileW( + t.CPtr(wp), access, share, None, disposition, flags, None) + stdlib.free(wp) + if ep is not None: + stdlib.free(ep) return h @@ -203,7 +255,10 @@ class File: 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) + # 明确字节读:下标访问按指针元素类型(i8)load 1 字节(Repl.vp + # _read_line 同款)。不用 c.Deref(buf + total)——后者的宽度取决于 + # 指针类型是否为 i8*,此处语义明确要求 1 字节。 + ch = buf[total] total += 1 if ch == 10: break if total < max_count: @@ -384,7 +439,10 @@ class FileW: 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) + # 明确字节读:下标访问按指针元素类型(i8)load 1 字节(Repl.vp + # _read_line 同款)。不用 c.Deref(buf + total)——后者的宽度取决于 + # 指针类型是否为 i8*,此处语义明确要求 1 字节。 + ch = buf[total] total += 1 if ch == 10: break if total < max_count: diff --git a/w32/win32base.vp b/w32/win32base.vp index d1b09d9..ef32b07 100644 --- a/w32/win32base.vp +++ b/w32/win32base.vp @@ -115,7 +115,7 @@ def utf8_to_utf16_dup(s: str) -> WCHARPTR: n: int = MultiByteToWideChar(UTF8_CODEPAGE, 0, s, -1, t.CPtr(0), 0) if n <= 0: return None - buf: WCHARPTR = stdlib.malloc(t.CSizeT(n) * 2) + buf: WCHARPTR = stdlib.malloc(sizet(n) * 2) if buf is None: return None MultiByteToWideChar(UTF8_CODEPAGE, 0, s, -1, buf, n) diff --git a/w32/win32memory.vp b/w32/win32memory.vp index ebeb811..5dd3482 100644 --- a/w32/win32memory.vp +++ b/w32/win32memory.vp @@ -35,30 +35,30 @@ class MEMORY_BASIC_INFORMATION(): BaseAddress: VOIDPTR AllocationBase: VOIDPTR AllocationProtect: DWORD - RegionSize: t.CSizeT + RegionSize: sizet State: DWORD Protect: DWORD Type: DWORD -extern def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR -extern def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL -extern def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL -extern def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT -extern def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL -extern def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL +extern def VirtualAlloc(lpAddress: VOIDPTR, dwSize: sizet, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR +extern def VirtualFree(lpAddress: VOIDPTR, dwSize: sizet, dwFreeType: ULONG) -> BOOL +extern def VirtualProtect(lpAddress: VOIDPTR, dwSize: sizet, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL +extern def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: sizet) -> sizet +extern def VirtualLock(lpAddress: VOIDPTR, dwSize: sizet) -> BOOL +extern def VirtualUnlock(lpAddress: VOIDPTR, dwSize: sizet) -> BOOL extern def GetProcessHeap() -> HANDLE -extern def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE +extern def HeapCreate(flOptions: ULONG, dwInitialSize: sizet, dwMaximumSize: sizet) -> HANDLE extern def HeapDestroy(hHeap: HANDLE) -> BOOL -extern def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR -extern def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR +extern def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: sizet) -> VOIDPTR +extern def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: sizet) -> VOIDPTR extern def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL -extern def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT +extern def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> sizet extern def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL -extern def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT -extern def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR +extern def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> sizet +extern def GlobalAlloc(uFlags: UINT, dwBytes: sizet) -> VOIDPTR extern def GlobalFree(hMem: VOIDPTR) -> VOIDPTR extern def GlobalLock(hMem: VOIDPTR) -> VOIDPTR extern def GlobalUnlock(hMem: VOIDPTR) -> BOOL -extern def GlobalSize(hMem: VOIDPTR) -> t.CSizeT -extern def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR +extern def GlobalSize(hMem: VOIDPTR) -> sizet +extern def LocalAlloc(uFlags: UINT, dwBytes: sizet) -> VOIDPTR extern def LocalFree(hMem: VOIDPTR) -> VOIDPTR diff --git a/w32/win32process.vp b/w32/win32process.vp index 89ed3e3..dff950f 100644 --- a/w32/win32process.vp +++ b/w32/win32process.vp @@ -39,7 +39,7 @@ ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 STILL_ACTIVE: t.CDefine = 259 -class STARTUPINFOA(): +class STARTUPINFOA: cb: DWORD lpReserved: CHARPTR lpDesktop: CHARPTR @@ -93,7 +93,7 @@ extern def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOO extern def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE extern def GetCurrentProcess() -> HANDLE extern def GetCurrentProcessId() -> ULONG -extern def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE +extern def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: sizet, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE extern def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE extern def SuspendThread(hThread: HANDLE) -> ULONG extern def ResumeThread(hThread: HANDLE) -> ULONG diff --git a/w32/win32sync.vp b/w32/win32sync.vp index a054423..cb440a7 100644 --- a/w32/win32sync.vp +++ b/w32/win32sync.vp @@ -2,7 +2,8 @@ import t from stdint import * from w32.win32base import * -class CRITICAL_SECTION(): + +class CRITICAL_SECTION: DebugInfo: VOIDPTR LockCount: LONG RecursionCount: LONG @@ -10,30 +11,30 @@ class CRITICAL_SECTION(): LockSemaphore: HANDLE SpinCount: QWORD -extern def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID -extern def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID -extern def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID -extern def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID -extern def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL -extern def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG -extern def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL -extern def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE -extern def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE +extern def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION*) +extern def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION*) +extern def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION*) +extern def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION*) +extern def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION*) -> BOOL +extern def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION*, dwSpinCount: ULONG) -> ULONG +extern def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION*, dwSpinCount: ULONG) -> BOOL +extern def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES*, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE +extern def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES*, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE extern def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE extern def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE extern def ReleaseMutex(hMutex: HANDLE) -> BOOL -extern def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE -extern def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE +extern def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES*, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE +extern def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES*, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE extern def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE extern def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE extern def SetEvent(hEvent: HANDLE) -> BOOL extern def ResetEvent(hEvent: HANDLE) -> BOOL extern def PulseEvent(hEvent: HANDLE) -> BOOL -extern def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE -extern def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE +extern def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES*, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE +extern def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES*, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE extern def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE extern def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE -extern def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL +extern def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG*) -> BOOL extern def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG extern def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG extern def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG @@ -48,18 +49,18 @@ extern def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID CONDITION_VARIABLE_LOCKMODE_SHARED: t.CDefine = 0x1 extern def InitializeConditionVariable(ConditionVariable: VOIDPTR) -> VOID -extern def SleepConditionVariableCS(ConditionVariable: VOIDPTR, CriticalSection: CRITICAL_SECTION | t.CPtr, dwMilliseconds: ULONG) -> BOOL +extern def SleepConditionVariableCS(ConditionVariable: VOIDPTR, CriticalSection: CRITICAL_SECTION*, dwMilliseconds: ULONG) -> BOOL extern def SleepConditionVariableSRW(ConditionVariable: VOIDPTR, SRWLock: VOIDPTR, dwMilliseconds: ULONG, Flags: ULONG) -> BOOL extern def WakeConditionVariable(ConditionVariable: VOIDPTR) -> VOID extern def WakeAllConditionVariable(ConditionVariable: VOIDPTR) -> VOID # 一次性初始化 (One-Time Initialization) - Vista+ -INIT_ONCE_STATIC_INIT: t.CDefine = 0x00000001 -INIT_ONCE_CHECK_ONLY: t.CDefine = 0x00000002 -INIT_ONCE_ASYNC: t.CDefine = 0x00000004 -INIT_ONCE_INIT_FAILED: t.CDefine = 0x00000008 +define INIT_ONCE_STATIC_INIT = 0x00000001 +define INIT_ONCE_CHECK_ONLY = 0x00000002 +define INIT_ONCE_ASYNC = 0x00000004 +define INIT_ONCE_INIT_FAILED = 0x00000008 class INIT_ONCE: - Ptr: t.CPtr + Ptr: VOIDPTR -extern def InitOnceExecuteOnce(InitOnce: INIT_ONCE | t.CPtr, InitFn: VOIDPTR, Parameter: VOIDPTR, Context: VOIDPTR | t.CPtr) -> BOOL +extern def InitOnceExecuteOnce(InitOnce: INIT_ONCE*, InitFn: VOIDPTR, Parameter: VOIDPTR, Context: VOIDPTR) -> BOOL diff --git a/zipfile.vp b/zipfile.vp index 35ee28d..81d817e 100644 --- a/zipfile.vp +++ b/zipfile.vp @@ -16,12 +16,11 @@ # w.close() # # r: rawptr[zipfile.ZipFile] = zipfile.ZipFile("out.zip", "r") -# olen: t.CSizeT = 0 -# data: bytes = r.read("a.txt", c.Addr(olen)) # malloc 缓冲,用后 free +# olen: sizet = 0 +# data: bytes = r.read("a.txt", &olen) # malloc 缓冲,用后 free # err = zipfile.error_code() / zipfile.error() import t, c -from stdint import * import stdlib import string import viperlib @@ -31,39 +30,37 @@ import zlib.pyzlib as zpy # ============================================================ -# 常量(对齐 Python zipfile) +# constants # ============================================================ +define ZIP_STORED = 0 +define ZIP_DEFLATED = 8 +define ZIP_LEVEL_DEFAULT = 6 # compression level (zlib default 6) +define _ZIP_FLAG_UTF8 = 0x0800 # filename in UTF-8 (flag bit 11) +define _ZIP_VERSION = 20 # version needed 2.0 +define _ZIP_DOS_DATE_EPOCH = 0x21 # 1980-01-01 +define _ZIP_MAX_COMMENT = 65535 -ZIP_STORED: t.CDefine = 0 -ZIP_DEFLATED: t.CDefine = 8 -ZIP_LEVEL_DEFAULT: t.CDefine = 6 # 压缩级别(zlib 默认 6) -_ZIP_FLAG_UTF8: t.CDefine = 0x0800 # 文件名按 UTF-8(flag bit 11) -_ZIP_VERSION: t.CDefine = 20 # 所需版本 2.0 -_ZIP_DOS_DATE_EPOCH: t.CDefine = 0x21 # 1980-01-01 -_ZIP_MAX_COMMENT: t.CDefine = 65535 - -# 错误码(方法返回值;全局最后错误见 error_code()/error()) -ZIP_ERR_OK: t.CDefine = 0 -ZIP_ERR_OPEN: t.CDefine = -1 -ZIP_ERR_NOT_ZIP: t.CDefine = -2 -ZIP_ERR_MEMORY: t.CDefine = -3 -ZIP_ERR_NOT_FOUND: t.CDefine = -4 -ZIP_ERR_INVALID: t.CDefine = -5 -ZIP_ERR_UNSUPPORTED: t.CDefine = -6 -ZIP_ERR_CRC: t.CDefine = -7 -ZIP_ERR_IO: t.CDefine = -8 -ZIP_ERR_MODE: t.CDefine = -9 -ZIP_ERR_CLOSED: t.CDefine = -10 +# error codes (method return values; for global last error see error_code()/error()) +define ZIP_ERR_OK = 0 +define ZIP_ERR_OPEN = -1 +define ZIP_ERR_NOT_ZIP = -2 +define ZIP_ERR_MEMORY = -3 +define ZIP_ERR_NOT_FOUND = -4 +define ZIP_ERR_INVALID = -5 +define ZIP_ERR_UNSUPPORTED = -6 +define ZIP_ERR_CRC = -7 +define ZIP_ERR_IO = -8 +define ZIP_ERR_MODE = -9 +define ZIP_ERR_CLOSED = -10 # ============================================================ -# 模块级错误状态(仿 zlib.pyzlib) +# module-level error state # ============================================================ - -zipfile_error_code_val: t.CInt = 0 -zipfile_error_msg: t.CArray[t.CChar, 256] = "" +zipfile_error_code_val: int = 0 +zipfile_error_msg: [256]char = "" -def zipfile_set_error(code: t.CInt, msg: str): +def zipfile_set_error(code: int, msg: str): global zipfile_error_code_val, zipfile_error_msg zipfile_error_code_val = code if msg: @@ -73,7 +70,7 @@ def zipfile_set_error(code: t.CInt, msg: str): zipfile_error_msg[0] = '\0' -def zipfile_set_error_win(code: t.CInt, msg: str, err: ULONG): +def zipfile_set_error_win(code: int, msg: str, err: ulong): global zipfile_error_code_val, zipfile_error_msg zipfile_error_code_val = code if err != 0: @@ -83,7 +80,7 @@ def zipfile_set_error_win(code: t.CInt, msg: str, err: ULONG): zipfile_error_msg[255] = '\0' -def error_code() -> t.CInt: +def error_code() -> int: return zipfile_error_code_val @@ -92,95 +89,88 @@ def error() -> str: # ============================================================ -# 小工具 +# small utilities # ============================================================ - -def zf_strlen(s: bytes) -> t.CSizeT: - n: t.CSizeT = 0 +def zf_strlen(s: bytes) -> sizet: + n: sizet = 0 while s is not None and c.Deref(s) != 0: n += 1 s += 1 return n -def zf_dup_name(src: bytes, length: t.CSizeT) -> bytes: - buf: BYTEPTR = BYTEPTR(stdlib.malloc(length + 1)) - if not buf: - return None - if length > 0: - string.memcpy(buf, src, length) +def zf_dup_name(src: bytes, length: sizet) -> bytes: + buf: bytes = bytes(stdlib.malloc(length + 1)) + if not buf: return None + if length > 0: string.memcpy(buf, src, length) buf[length] = 0 return buf -def zf_u16le(p: UINT8PTR) -> t.CUInt32T: - return t.CUInt32T(p[0]) | (t.CUInt32T(p[1]) << 8) +def zf_u16le(p: uint8*) -> uint32: + return uint32(p[0]) | (uint32(p[1]) << 8) -def zf_u32le(p: UINT8PTR) -> t.CUInt32T: - return (t.CUInt32T(p[0]) | - (t.CUInt32T(p[1]) << 8) | - (t.CUInt32T(p[2]) << 16) | - (t.CUInt32T(p[3]) << 24)) +def zf_u32le(p: uint8*) -> uint32: + return (uint32(p[0]) | (uint32(p[1]) << 8) | (uint32(p[2]) << 16) | (uint32(p[3]) << 24)) -def zf_w16le(h: BYTEPTR, v: t.CUInt32T): +def zf_w16le(h: uint8*, v: uint32): h[0] = v & 0xFF h[1] = (v >> 8) & 0xFF -def zf_w32le(h: BYTEPTR, v: t.CUInt32T): +def zf_w32le(h: uint8*, v: uint32): h[0] = v & 0xFF h[1] = (v >> 8) & 0xFF h[2] = (v >> 16) & 0xFF h[3] = (v >> 24) & 0xFF -# 所有文件打开都允许读/写/删共享,避免句柄互斥 -_ZF_SHARE: t.CDefine = 7 # FILE_SHARE_READ|WRITE|DELETE +# All file openings allow read/write/delete sharing, avoiding mutually exclusive handles +define _ZF_SHARE = 7 # FILE_SHARE_READ|WRITE|DELETE -def zf_share_flags() -> ULONG: - return ULONG(_ZF_SHARE) +def zf_share_flags() -> ulong: + return ulong(_ZF_SHARE) -def zf_write_all(h: wb.HANDLE, p: BYTEPTR, n: t.CSizeT) -> t.CInt: - done: t.CSizeT = 0 +def zf_write_all(h: wb.HANDLE, p: uint8*, n: sizet) -> int: + done: sizet = 0 while done < n: - chunk: t.CSizeT = n - done + chunk: sizet = n - done if chunk > 0xFFFFFF00: chunk = 0xFFFFFF00 - written: ULONG = 0 - ok: BOOL = wf.WriteFile(h, p + done, ULONG(chunk), c.Addr(written), None) + written: ulong = 0 + ok: int = wf.WriteFile(h, p + done, ulong(chunk), &written, None) if ok == 0 or written == 0: global zipfile_error_code_val, zipfile_error_msg zipfile_error_code_val = ZIP_ERR_IO - viperlib.snprintf(zipfile_error_msg, 256, - "write failed (win32_err=%u)", wb.GetLastError()) + viperlib.snprintf(zipfile_error_msg, 256, "write failed (win32_err=%u)", wb.GetLastError()) return ZIP_ERR_IO - done += t.CSizeT(written) + done += sizet(written) return ZIP_ERR_OK -def zf_read_all(h: wb.HANDLE, p: BYTEPTR, n: t.CSizeT) -> t.CInt: - done: t.CSizeT = 0 +def zf_read_all(h: wb.HANDLE, p: uint8*, n: sizet) -> int: + done: sizet = 0 while done < n: - chunk: t.CSizeT = n - done + chunk: sizet = n - done if chunk > 0xFFFFFF00: chunk = 0xFFFFFF00 - bytes_read: ULONG = 0 - ok: BOOL = wf.ReadFile(h, p + done, ULONG(chunk), c.Addr(bytes_read), None) + bytes_read: ulong = 0 + ok: int = wf.ReadFile(h, p + done, ulong(chunk), c.Addr(bytes_read), None) if ok == 0 or bytes_read == 0: global zipfile_error_code_val, zipfile_error_msg zipfile_error_code_val = ZIP_ERR_IO viperlib.snprintf(zipfile_error_msg, 256, "read failed (win32_err=%u)", wb.GetLastError()) return ZIP_ERR_IO - done += t.CSizeT(bytes_read) + done += sizet(bytes_read) return ZIP_ERR_OK -def zf_read_whole(path: str, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: +def zf_read_whole(path: str, out_len: rawptr[sizet]) -> uint8*: if not out_len: zipfile_set_error(ZIP_ERR_OPEN, "out_len is None") return None @@ -191,90 +181,75 @@ def zf_read_whole(path: str, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: zipfile_set_error_win(ZIP_ERR_OPEN, "cannot open file for reading", wb.GetLastError()) return None li: wb.LARGE_INTEGER = wb.LARGE_INTEGER() - ok_size: BOOL = wf.GetFileSizeEx(h, t.CPtr(c.Addr(li))) + ok_size: int = wf.GetFileSizeEx(h, t.CPtr(c.Addr(li))) if ok_size == 0: wb.CloseHandle(h) zipfile_set_error(ZIP_ERR_IO, "cannot get file size") return None - sz: t.CSizeT = t.CSizeT(li.QuadPart) + sz: sizet = sizet(li.QuadPart) if sz == 0: wb.CloseHandle(h) zipfile_set_error(ZIP_ERR_NOT_ZIP, "empty file is not a zip archive") return None - buf: BYTEPTR = BYTEPTR(stdlib.malloc(sz)) + buf: bytes = bytes(stdlib.malloc(sz)) if not buf: wb.CloseHandle(h) zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return None - rc: t.CInt = zf_read_all(h, buf, sz) + rc: int = zf_read_all(h, buf, sz) wb.CloseHandle(h) if rc != ZIP_ERR_OK: stdlib.free(buf) return None - c.Set(c.Deref(out_len), sz) + *out_len = sz return buf # ============================================================ # 条目信息(目录项) -# 注意: 节点为显式 calloc 分配(@t.Object 裸结构,无 GC 追踪), +# 注意: 节点为显式 calloc 分配 # 由 ZipFile 负责释放——避免 GC 实例经 | t.CPtr 联合字段引用被回收。 # ============================================================ - -@t.Object class ZipInfo: - filename: bytes # 原始字节名(含 \0,zipfile 持有并负责释放) - name_len: t.CSizeT - compress_type: t.CInt # ZIP_STORED / ZIP_DEFLATED - crc32: t.CUInt32T - compress_size: t.CSizeT - file_size: t.CSizeT - header_offset: t.CSizeT # 本地文件头偏移 - next: "ZipInfo" | t.CPtr # 链表(保持写入/目录顺序) + filename: bytes # 原始字节名(含 \0,zipfile 持有并负责释放) + name_len: sizet + compress_type: int # ZIP_STORED / ZIP_DEFLATED + crc32: uint32 + compress_size: sizet + file_size: sizet + header_offset: sizet # 本地文件头偏移 + next: rawptr[ZipInfo] # 链表(保持写入/目录顺序) # ============================================================ # ZipFile # ============================================================ - class ZipFile: path: bytes - mode: t.CInt # 0 = 读,1 = 写 - compression: t.CInt # write() 未显式指定时的压缩类型 - fh: wb.HANDLE # 写模式句柄(裸 win32 CreateFileA) - data: BYTEPTR # 读模式:整个归档的内存副本 - data_len: t.CSizeT - info_head: ZipInfo | t.CPtr - info_tail: ZipInfo | t.CPtr - info_count: t.CSizeT - pos: t.CSizeT # 写模式当前偏移 - ok: t.CInt # 1 = 可正常使用 - closed: t.CInt + mode: int = -1 # 0 = 读,1 = 写 + compression: int # write() 未显式指定时的压缩类型 + fh: wb.HANDLE = None # 写模式句柄(裸 win32 CreateFileA) + data: bytes = None # 读模式:整个归档的内存副本 + data_len: sizet = 0 + info_head: rawptr[ZipInfo] = None + info_tail: rawptr[ZipInfo] = None + info_count: sizet = 0 + pos: sizet = 0 # 写模式当前偏移 + ok: int = 0 # 1 = 可正常使用 + closed: int = 0 - def __init__(self, path: str, mode: str = "r", compression: t.CInt = ZIP_DEFLATED): + def __init__(self, path: str, mode: str = "r", compression: int = ZIP_DEFLATED): self.path = path - self.mode = -1 self.compression = compression - self.fh = None - self.data = None - self.data_len = 0 - self.info_head = None - self.info_tail = None - self.info_count = 0 - self.pos = 0 - self.ok = 0 - self.closed = 0 # 注意: 字符串必须用 strcmp 比较(== 只会比较指针) - if string.strcmp(mode, "r") == 0: - self.mode = 0 - elif string.strcmp(mode, "w") == 0: - self.mode = 1 + if string.strcmp(mode, "r") == 0: self.mode = 0 + elif string.strcmp(mode, "w") == 0: self.mode = 1 else: zipfile_set_error(ZIP_ERR_OPEN, "mode must be 'r' or 'w'") self.closed = 1 return if self.mode == 0: - self.data = zf_read_whole(path, c.Addr(self.data_len)) + self.data = zf_read_whole(path, &self.data_len) if not self.data: self.closed = 1 return @@ -298,12 +273,12 @@ class ZipFile: self.ok = 1 def _clear_infos(self): - n: ZipInfo | t.CPtr = self.info_head + n: rawptr[ZipInfo] = self.info_head while n is not None: if n.filename is not None: stdlib.free(n.filename) n.filename = None - nxt: ZipInfo | t.CPtr = n.next + nxt: rawptr[ZipInfo] = n.next n.next = None stdlib.free(n) n = nxt @@ -311,8 +286,8 @@ class ZipFile: self.info_tail = None self.info_count = 0 - def _append_info(self) -> ZipInfo | t.CPtr: - node: ZipInfo | t.CPtr = stdlib.calloc(1, ZipInfo.__sizeof__()) + def _append_info(self) -> rawptr[ZipInfo]: + node: rawptr[ZipInfo] = stdlib.calloc(1, ZipInfo.__sizeof__()) if not node: zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return None @@ -326,21 +301,21 @@ class ZipFile: return node # ---- 读模式:解析中央目录 ---- - def _parse(self) -> t.CInt: + def _parse(self) -> int: if self.data_len < 22: zipfile_set_error(ZIP_ERR_NOT_ZIP, "file too small to be a zip") return ZIP_ERR_NOT_ZIP - d: UINT8PTR = UINT8PTR(self.data) + d: bytes = self.data # 从尾部回扫 EOCD(容忍尾部注释) - max_back: t.CSizeT = self.data_len - 22 + max_back: sizet = self.data_len - 22 if max_back > _ZIP_MAX_COMMENT + 20: max_back = _ZIP_MAX_COMMENT + 20 - eocd: t.CSizeT = 0 - found: t.CInt = 0 - i: t.CSizeT = 0 + eocd: sizet = 0 + found: int = 0 + i: sizet = 0 while i <= max_back and found == 0: - p: t.CSizeT = self.data_len - 22 - i + p: sizet = self.data_len - 22 - i if d[p] == 0x50 and d[p + 1] == 0x4B and d[p + 2] == 0x05 and d[p + 3] == 0x06: eocd = p found = 1 @@ -349,16 +324,16 @@ class ZipFile: zipfile_set_error(ZIP_ERR_NOT_ZIP, "EOCD not found") return ZIP_ERR_NOT_ZIP - total: t.CUInt32T = zf_u16le(d + eocd + 10) - cd_off: t.CUInt32T = zf_u32le(d + eocd + 16) - cd_size: t.CUInt32T = zf_u32le(d + eocd + 12) - if t.CSizeT(cd_off) + t.CSizeT(cd_size) > self.data_len: + total: uint32 = zf_u16le(d + eocd + 10) + cd_off: uint32 = zf_u32le(d + eocd + 16) + cd_size: uint32 = zf_u32le(d + eocd + 12) + if sizet(cd_off) + sizet(cd_size) > self.data_len: zipfile_set_error(ZIP_ERR_NOT_ZIP, "central directory out of range") return ZIP_ERR_NOT_ZIP - cp: t.CSizeT = t.CSizeT(cd_off) - end: t.CSizeT = t.CSizeT(cd_off) + t.CSizeT(cd_size) - idx: t.CSizeT = 0 + cp: sizet = sizet(cd_off) + end: sizet = sizet(cd_off) + sizet(cd_size) + idx: sizet = 0 while idx < total: if cp + 46 > end: zipfile_set_error(ZIP_ERR_NOT_ZIP, "central directory entry truncated") @@ -366,46 +341,46 @@ class ZipFile: if zf_u32le(d + cp) != 0x02014B50: zipfile_set_error(ZIP_ERR_NOT_ZIP, "bad central directory signature") return ZIP_ERR_NOT_ZIP - method: t.CUInt32T = zf_u16le(d + cp + 10) - crc: t.CUInt32T = zf_u32le(d + cp + 16) - csize: t.CUInt32T = zf_u32le(d + cp + 20) - usize: t.CUInt32T = zf_u32le(d + cp + 24) - nlen: t.CUInt32T = zf_u16le(d + cp + 28) - elen: t.CUInt32T = zf_u16le(d + cp + 30) - clen: t.CUInt32T = zf_u16le(d + cp + 32) - hoff: t.CUInt32T = zf_u32le(d + cp + 42) - rec_len: t.CSizeT = 46 + t.CSizeT(nlen) + t.CSizeT(elen) + t.CSizeT(clen) + method: uint32 = zf_u16le(d + cp + 10) + crc: uint32 = zf_u32le(d + cp + 16) + csize: uint32 = zf_u32le(d + cp + 20) + usize: uint32 = zf_u32le(d + cp + 24) + nlen: uint32 = zf_u16le(d + cp + 28) + elen: uint32 = zf_u16le(d + cp + 30) + clen: uint32 = zf_u16le(d + cp + 32) + hoff: uint32 = zf_u32le(d + cp + 42) + rec_len: sizet = 46 + sizet(nlen) + sizet(elen) + sizet(clen) if cp + rec_len > end: zipfile_set_error(ZIP_ERR_NOT_ZIP, "central directory entry out of range") return ZIP_ERR_NOT_ZIP if nlen == 0: zipfile_set_error(ZIP_ERR_NOT_ZIP, "central directory entry has empty name") return ZIP_ERR_NOT_ZIP - dup: BYTEPTR = zf_dup_name(BYTEPTR(d + cp + 46), t.CSizeT(nlen)) + dup: bytes = zf_dup_name(d + cp + 46, sizet(nlen)) if not dup: zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return ZIP_ERR_MEMORY - node: ZipInfo | t.CPtr = self._append_info() + node: rawptr[ZipInfo] = self._append_info() if node is None: stdlib.free(dup) return ZIP_ERR_MEMORY - node.filename = dup - node.name_len = t.CSizeT(nlen) - node.compress_type = t.CInt(method) - node.crc32 = crc - node.compress_size = t.CSizeT(csize) - node.file_size = t.CSizeT(usize) - node.header_offset = t.CSizeT(hoff) + node.filename = dup + node.name_len = sizet(nlen) + node.compress_type = int(method) + node.crc32 = crc + node.compress_size = sizet(csize) + node.file_size = sizet(usize) + node.header_offset = sizet(hoff) cp = cp + rec_len idx += 1 return ZIP_ERR_OK # ---- 公共查询 ---- - def namelist_at(self, i: t.CSizeT) -> bytes: + def namelist_at(self, i: sizet) -> bytes: if self.ok == 0 or self.info_count == 0 or i >= self.info_count: return None - n: ZipInfo | t.CPtr = self.info_head - k: t.CSizeT = 0 + n: rawptr[ZipInfo] = self.info_head + k: sizet = 0 while n is not None: if k == i: return n.filename @@ -413,10 +388,10 @@ class ZipFile: k += 1 return None - def getinfo(self, name: str) -> ZipInfo | t.CPtr: + def getinfo(self, name: str) -> rawptr[ZipInfo]: if self.ok == 0: return None - n: ZipInfo | t.CPtr = self.info_head + n: rawptr[ZipInfo] = self.info_head while n is not None: if n.filename is not None and string.strcmp(n.filename, name) == 0: return n @@ -424,77 +399,77 @@ class ZipFile: return None # ---- 读成员:解压 + CRC32 校验 ---- - def read(self, name: str, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + def read(self, name: str, out_len: sizet*) -> bytes: if not out_len: zipfile_set_error(ZIP_ERR_INVALID, "out_len is None") return None - c.Set(c.Deref(out_len), 0) + *out_len = 0 if self.closed or self.ok == 0: zipfile_set_error(ZIP_ERR_CLOSED, "zip file is closed") return None if self.mode != 0: zipfile_set_error(ZIP_ERR_MODE, "zip file is not open for reading") return None - info: ZipInfo | t.CPtr = self.getinfo(name) + info: rawptr[ZipInfo] = self.getinfo(name) if info is None: zipfile_set_error(ZIP_ERR_NOT_FOUND, "member not found") return None - d: UINT8PTR = UINT8PTR(self.data) - off: t.CSizeT = t.CSizeT(info.header_offset) + d: bytes = self.data + off: sizet = sizet(info.header_offset) if off + 30 > self.data_len: zipfile_set_error(ZIP_ERR_NOT_ZIP, "local file header out of range") return None if zf_u32le(d + off) != 0x04034B50: zipfile_set_error(ZIP_ERR_NOT_ZIP, "bad local file header signature") return None - nlen: t.CUInt32T = zf_u16le(d + off + 26) - elen: t.CUInt32T = zf_u16le(d + off + 28) - start: t.CSizeT = off + 30 + t.CSizeT(nlen) + t.CSizeT(elen) - csz: t.CSizeT = t.CSizeT(info.compress_size) + nlen: uint32 = zf_u16le(d + off + 26) + elen: uint32 = zf_u16le(d + off + 28) + start: sizet = off + 30 + sizet(nlen) + sizet(elen) + csz: sizet = sizet(info.compress_size) if start + csz > self.data_len: zipfile_set_error(ZIP_ERR_NOT_ZIP, "member data out of range") return None - payload: BYTEPTR = BYTEPTR(d + start) - out: BYTEPTR = None - ctype: t.CInt = info.compress_type + payload: bytes = d + start + out: bytes = None + ctype: int = info.compress_type if ctype == ZIP_STORED: - out = BYTEPTR(stdlib.malloc(t.CSizeT(info.file_size) + 1)) + out = bytes(stdlib.malloc(sizet(info.file_size) + 1)) if not out: zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return None if csz > 0: string.memcpy(out, payload, csz) - c.Set(c.Deref(out_len), t.CSizeT(info.file_size)) + *out_len = sizet(info.file_size) elif ctype == ZIP_DEFLATED: - olen: t.CSizeT = 0 - out = zpy.decompress(None, payload, csz, -15, 0, c.Addr(olen)) + olen: sizet = 0 + out = zpy.decompress(None, payload, csz, -15, 0, &olen) if not out: zipfile_set_error(ZIP_ERR_IO, "deflate decompression failed") return None - c.Set(c.Deref(out_len), olen) + *out_len = olen else: zipfile_set_error(ZIP_ERR_UNSUPPORTED, "unsupported compression method") return None - got_len: t.CSizeT = c.Deref(out_len) - if got_len != t.CSizeT(info.file_size): + got_len: sizet = *out_len + if got_len != sizet(info.file_size): stdlib.free(out) - c.Set(c.Deref(out_len), 0) + *out_len = 0 zipfile_set_error(ZIP_ERR_NOT_ZIP, "member size mismatch") return None - crc_calc: t.CUInt32T = t.CUInt32T(zpy.zlib_crc32(out, got_len, 0)) + crc_calc: uint32 = uint32(zpy.zlib_crc32(out, got_len, 0)) if crc_calc != info.crc32: stdlib.free(out) - c.Set(c.Deref(out_len), 0) + *out_len = 0 zipfile_set_error(ZIP_ERR_CRC, "CRC32 mismatch") return None return out # ---- 写成员 ---- - def write(self, arcname: str, data: BYTEPTR, data_len: t.CSizeT, - compress_type: t.CInt = -1) -> t.CInt: + def write(self, arcname: str, data: bytes, data_len: sizet, + compress_type: int = -1) -> int: if self.closed or self.ok == 0: zipfile_set_error(ZIP_ERR_CLOSED, "zip file is closed") return ZIP_ERR_CLOSED @@ -504,7 +479,7 @@ class ZipFile: if not arcname: zipfile_set_error(ZIP_ERR_INVALID, "arcname is required") return ZIP_ERR_INVALID - ctype: t.CInt = compress_type + ctype: int = compress_type if ctype == -1: ctype = self.compression if ctype != ZIP_STORED and ctype != ZIP_DEFLATED: @@ -513,7 +488,7 @@ class ZipFile: if data_len > 0 and not data: zipfile_set_error(ZIP_ERR_INVALID, "data is None but data_len > 0") return ZIP_ERR_INVALID - name_len: t.CSizeT = zf_strlen(arcname) + name_len: sizet = zf_strlen(arcname) if name_len == 0: zipfile_set_error(ZIP_ERR_INVALID, "arcname is empty") return ZIP_ERR_INVALID @@ -521,19 +496,19 @@ class ZipFile: zipfile_set_error(ZIP_ERR_UNSUPPORTED, "name or data too large for zip32") return ZIP_ERR_UNSUPPORTED - crc: t.CUInt32T = t.CUInt32T(zpy.zlib_crc32(data, data_len, 0)) - payload: BYTEPTR = data - plen: t.CSizeT = data_len + crc: uint32 = uint32(zpy.zlib_crc32(data, data_len, 0)) + payload: bytes = data + plen: sizet = data_len if ctype == ZIP_DEFLATED: - tmp: t.CSizeT = 0 - payload = zpy.compress(None, data, data_len, ZIP_LEVEL_DEFAULT, -15, c.Addr(tmp)) + tmp: sizet = 0 + payload = zpy.compress(None, data, data_len, ZIP_LEVEL_DEFAULT, -15, &tmp) if not payload: zipfile_set_error(ZIP_ERR_IO, "deflate compression failed") return ZIP_ERR_IO plen = tmp - hoff: t.CSizeT = self.pos - hdr: BYTEPTR = BYTEPTR(stdlib.malloc(30)) + hoff: sizet = self.pos + hdr: bytes = bytes(stdlib.malloc(30)) if not hdr: if ctype == ZIP_DEFLATED: stdlib.free(payload) @@ -543,13 +518,13 @@ class ZipFile: zf_w32le(hdr, 0x04034B50) zf_w16le(hdr + 4, _ZIP_VERSION) zf_w16le(hdr + 6, _ZIP_FLAG_UTF8) - zf_w16le(hdr + 8, t.CUInt32T(ctype)) + zf_w16le(hdr + 8, uint32(ctype)) zf_w16le(hdr + 12, _ZIP_DOS_DATE_EPOCH) zf_w32le(hdr + 14, crc) - zf_w32le(hdr + 18, t.CUInt32T(plen)) - zf_w32le(hdr + 22, t.CUInt32T(data_len)) - zf_w16le(hdr + 26, t.CUInt32T(name_len)) - rc: t.CInt = zf_write_all(self.fh, hdr, 30) + zf_w32le(hdr + 18, uint32(plen)) + zf_w32le(hdr + 22, uint32(data_len)) + zf_w16le(hdr + 26, uint32(name_len)) + rc: int = zf_write_all(self.fh, hdr, 30) stdlib.free(hdr) if rc == ZIP_ERR_OK: rc = zf_write_all(self.fh, arcname, name_len) @@ -561,11 +536,11 @@ class ZipFile: return rc self.pos = self.pos + 30 + name_len + plen - dup: BYTEPTR = zf_dup_name(arcname, name_len) + dup: bytes = zf_dup_name(arcname, name_len) if not dup: zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return ZIP_ERR_MEMORY - node: ZipInfo | t.CPtr = self._append_info() + node: rawptr[ZipInfo] = self._append_info() if node is None: stdlib.free(dup) return ZIP_ERR_MEMORY @@ -579,30 +554,30 @@ class ZipFile: return ZIP_ERR_OK # ---- 写模式收尾:中央目录 + EOCD ---- - def _finish_write(self) -> t.CInt: + def _finish_write(self) -> int: if self.info_count > _ZIP_MAX_COMMENT: zipfile_set_error(ZIP_ERR_UNSUPPORTED, "too many entries (>65535)") return ZIP_ERR_UNSUPPORTED - cd_start: t.CSizeT = self.pos - hdr: BYTEPTR = BYTEPTR(stdlib.malloc(46)) + cd_start: sizet = self.pos + hdr: bytes = stdlib.malloc(46) if not hdr: zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return ZIP_ERR_MEMORY - rc: t.CInt = ZIP_ERR_OK - n: ZipInfo | t.CPtr = self.info_head + rc: int = ZIP_ERR_OK + n: rawptr[ZipInfo] = self.info_head while n is not None and rc == ZIP_ERR_OK: string.memset(hdr, 0, 46) zf_w32le(hdr, 0x02014B50) zf_w16le(hdr + 4, _ZIP_VERSION) # version made by zf_w16le(hdr + 6, _ZIP_VERSION) # version needed zf_w16le(hdr + 8, _ZIP_FLAG_UTF8) - zf_w16le(hdr + 10, t.CUInt32T(n.compress_type)) + zf_w16le(hdr + 10, uint32(n.compress_type)) zf_w16le(hdr + 14, _ZIP_DOS_DATE_EPOCH) zf_w32le(hdr + 16, n.crc32) - zf_w32le(hdr + 20, t.CUInt32T(n.compress_size)) - zf_w32le(hdr + 24, t.CUInt32T(n.file_size)) - zf_w16le(hdr + 28, t.CUInt32T(n.name_len)) - zf_w32le(hdr + 42, t.CUInt32T(n.header_offset)) + zf_w32le(hdr + 20, uint32(n.compress_size)) + zf_w32le(hdr + 24, uint32(n.file_size)) + zf_w16le(hdr + 28, uint32(n.name_len)) + zf_w32le(hdr + 42, uint32(n.header_offset)) rc = zf_write_all(self.fh, hdr, 46) if rc == ZIP_ERR_OK: rc = zf_write_all(self.fh, n.filename, n.name_len) @@ -613,27 +588,25 @@ class ZipFile: if rc != ZIP_ERR_OK: return rc - cd_size: t.CSizeT = self.pos - cd_start - e: BYTEPTR = BYTEPTR(stdlib.malloc(22)) + cd_size: sizet = self.pos - cd_start + e: bytes = stdlib.malloc(22) if not e: zipfile_set_error(ZIP_ERR_MEMORY, "out of memory") return ZIP_ERR_MEMORY string.memset(e, 0, 22) zf_w32le(e, 0x06054B50) - zf_w16le(e + 8, t.CUInt32T(self.info_count)) - zf_w16le(e + 10, t.CUInt32T(self.info_count)) - zf_w32le(e + 12, t.CUInt32T(cd_size)) - zf_w32le(e + 16, t.CUInt32T(cd_start)) + zf_w16le(e + 8, uint32(self.info_count)) + zf_w16le(e + 10, uint32(self.info_count)) + zf_w32le(e + 12, uint32(cd_size)) + zf_w32le(e + 16, uint32(cd_start)) rc = zf_write_all(self.fh, e, 22) stdlib.free(e) - if rc != ZIP_ERR_OK: - zipfile_set_error(ZIP_ERR_IO, "write EOCD failed") + if rc != ZIP_ERR_OK: zipfile_set_error(ZIP_ERR_IO, "write EOCD failed") return rc - def close(self) -> t.CInt: - if self.closed: - return ZIP_ERR_OK - rc: t.CInt = ZIP_ERR_OK + def close(self) -> int: + if self.closed: return ZIP_ERR_OK + rc: int = ZIP_ERR_OK if self.mode == 1 and self.fh is not None: rc = self._finish_write() wb.CloseHandle(self.fh) diff --git a/zlib/pyzlib.vp b/zlib/pyzlib.vp index ba6f308..46274dc 100644 --- a/zlib/pyzlib.vp +++ b/zlib/pyzlib.vp @@ -60,13 +60,12 @@ DEF_MEM_LEVEL: t.CDefine = 8 # Version ZLIB_VERSION: t.CDefine = "1.3.2" -pyzlib_error_msg: t.CArray[t.CChar, 512] = "" +pyzlib_error_msg: t.CArray[char, 512] = "" pyzlib_error_code_val: t.CInt = 0 # ============================================================ # Structures # ============================================================ -@t.Object class Compress: pool: rawptr[memhub.MemManager] stream: VOIDPTR @@ -78,16 +77,16 @@ class Compress: memLevel: t.CInt strategy: t.CInt zdict: BYTEPTR - zdict_len: t.CSizeT - last_pos: t.CSizeT + zdict_len: sizet + last_pos: sizet input_buf: BYTEPTR - input_buf_len: t.CSizeT - input_buf_cap: t.CSizeT + input_buf_len: sizet + input_buf_cap: sizet header_written: t.CInt def compress(self, - data: BYTEPTR, data_len: t.CSizeT, - out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + data: BYTEPTR, data_len: sizet, + out_len: sizet*) -> BYTEPTR: if not self.is_initialized: set_error(Z_STREAM_ERROR, "compress object not initialized") return None @@ -134,7 +133,7 @@ class Compress: string.memset(p3, 0, 1) return p3 - def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + def flush(self, mode: t.CInt, out_len: sizet*) -> BYTEPTR: if not self.is_initialized: set_error(Z_STREAM_ERROR, "compress object not initialized") return None @@ -146,7 +145,7 @@ class Compress: if not self.header_written: self.header_written = 1 input_data: BYTEPTR = self.input_buf - input_len: t.CSizeT = self.input_buf_len + input_len: sizet = self.input_buf_len if input_len == 0: s.writer.write_bits(1, 1) s.writer.write_bits(1, 2) @@ -166,7 +165,7 @@ class Compress: 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() + total: sizet = s.writer.total() if self.pool == None: result: BYTEPTR = BYTEPTR(stdlib.malloc(total)) else: @@ -183,7 +182,7 @@ class Compress: 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 + input_len: sizet = 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) @@ -191,9 +190,9 @@ class Compress: 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 + prev_pos: sizet = self.last_pos + total: sizet = s.writer.total() + delta: sizet = total - prev_pos self.last_pos = s.writer.byte_pos if delta == 0: c.Set(c.Deref(out_len), 0) @@ -290,7 +289,6 @@ class Compress: self.delete() -@t.Object class Decompress: pool: rawptr[memhub.MemManager] stream: VOIDPTR @@ -298,19 +296,19 @@ class Decompress: eof: t.CInt wbits: t.CInt zdict: BYTEPTR - zdict_len: t.CSizeT + zdict_len: sizet _unused_data: BYTEPTR - _unused_data_len: t.CSizeT - _unused_data_cap: t.CSizeT + _unused_data_len: sizet + _unused_data_cap: sizet _unconsumed_tail: BYTEPTR - _unconsumed_tail_len: t.CSizeT - _unconsumed_tail_cap: t.CSizeT + _unconsumed_tail_len: sizet + _unconsumed_tail_cap: sizet input_buf: BYTEPTR - input_buf_len: t.CSizeT - input_buf_cap: t.CSizeT + input_buf_len: sizet + input_buf_cap: sizet - def decompress(self, data: BYTEPTR, data_len: t.CSizeT, - max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + def decompress(self, data: BYTEPTR, data_len: sizet, + max_length: sizet, out_len: sizet*) -> BYTEPTR: if not self.is_initialized: set_error(Z_STREAM_ERROR, "decompress object not initialized") return None @@ -362,9 +360,9 @@ class Decompress: s.input_len - s.input_pos) self.input_buf_len = 0 else: - consumed: t.CSizeT = s.input_pos + consumed: sizet = s.input_pos if consumed < self.input_buf_len: - remaining: t.CSizeT = self.input_buf_len - consumed + remaining: sizet = self.input_buf_len - consumed string.memmove(self.input_buf, self.input_buf + consumed, remaining) self.input_buf_len = remaining else: @@ -372,7 +370,7 @@ class Decompress: s.destroy() return out - def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + def flush(self, length: sizet, out_len: sizet*) -> BYTEPTR: if not self.is_initialized: set_error(Z_STREAM_ERROR, "decompress object not initialized") return None @@ -442,7 +440,7 @@ class Decompress: self.pool.free(self.input_buf) self.pool.free(self) - def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + def unused_data(self, length: sizet*) -> BYTEPTR: #if not self: # if length: # c.Set(c.Deref(length), 0) @@ -451,7 +449,7 @@ class Decompress: c.Set(c.Deref(length), self._unused_data_len) return self._unused_data - def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + def unconsumed_tail(self, length: sizet*) -> BYTEPTR: #if not self: # if length: # c.Set(c.Deref(length), 0) @@ -475,7 +473,7 @@ def set_error(code: int, msg: str): else: pyzlib_error_msg[0] = '\0' -def clone_bytes(pool: rawptr[memhub.MemManager], src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: +def clone_bytes(pool: rawptr[memhub.MemManager], src: BYTEPTR, length: sizet) -> BYTEPTR: if not src or length == 0: return None if pool == None: dst: BYTEPTR = BYTEPTR(stdlib.malloc(length)) @@ -488,12 +486,12 @@ def clone_bytes(pool: rawptr[memhub.MemManager], src: BYTEPTR, length: t.CSizeT) # `t.CPtr[...]` 下标时声明侧(StubGen/VpiReader)不认作 CPtr 标记,会坍缩成 # 首段 BYTE = i8,与定义侧 i8** 不一致(跨模块调用即 ABI 错位,见 # includes/zlib/zinflate.vp decompress 处说明)。改用"指针别名 | t.CPtr"。 -def append_bytes(pool: rawptr[memhub.MemManager], buf: BYTEPTR | t.CPtr, length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, - data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: +def append_bytes(pool: rawptr[memhub.MemManager], buf: BYTEPTR | t.CPtr, length: sizet*, cap: sizet*, + data: BYTEPTR, data_len: sizet) -> t.CInt: if not data or data_len == 0: return 0 - needed: t.CSizeT = c.Deref(length) + data_len + needed: sizet = c.Deref(length) + data_len if needed > c.Deref(cap): - new_cap: t.CSizeT = c.Deref(cap) * 2 + new_cap: sizet = c.Deref(cap) * 2 if new_cap < needed: new_cap = needed if pool == None: new_buf: BYTEPTR = BYTEPTR(stdlib.realloc(c.Deref(buf), new_cap)) @@ -510,7 +508,7 @@ def append_bytes(pool: rawptr[memhub.MemManager], buf: BYTEPTR | t.CPtr, length: return 0 -def shrink_to_fit(pool: rawptr[memhub.MemManager], buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: +def shrink_to_fit(pool: rawptr[memhub.MemManager], buf: BYTEPTR, length: sizet) -> BYTEPTR: if length == 0: if pool == None: stdlib.free(buf) @@ -546,8 +544,8 @@ def clear_error(): pyzlib_error_msg[0] = '\0' pyzlib_error_code_val = 0 -def compress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: t.CSizeT, - level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: +def compress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: sizet, + level: t.CInt, wbits: t.CInt, out_len: sizet*) -> BYTEPTR: if not data and data_len > 0: set_error(Z_STREAM_ERROR, "data is None but data_len > 0") return None @@ -562,7 +560,7 @@ def compress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: t.CSizeT, set_error(Z_DATA_ERROR, "compression failed") return None if wbits > MAX_WBITS: - gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8 + gzip_len: sizet = 10 + c.Deref(out_len) + 8 if pool == None: gzip_buf: BYTEPTR = BYTEPTR(stdlib.malloc(gzip_len)) else: @@ -574,7 +572,7 @@ def compress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: t.CSizeT, pool.free(raw_result) set_error(Z_MEM_ERROR, "out of memory") return None - pos: t.CSizeT = 0 + pos: sizet = 0 gzip_buf[pos + 0] = 0x1F gzip_buf[pos + 1] = 0x8B gzip_buf[pos + 2] = 0x08 @@ -609,8 +607,8 @@ def compress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: t.CSizeT, return shrink_to_fit(pool, raw_result, c.Deref(out_len)) -def decompress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: t.CSizeT, - wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: +def decompress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: sizet, + wbits: t.CInt, bufsize: sizet, out_len: sizet*) -> BYTEPTR: if not data and data_len > 0: set_error(Z_STREAM_ERROR, "data is None but data_len > 0") return None @@ -625,7 +623,7 @@ def decompress(pool: rawptr[memhub.MemManager], data: BYTEPTR, data_len: t.CSize def compressobj(pool: rawptr[memhub.MemManager], level: t.CInt, method: t.CInt, wbits: t.CInt, memLevel: t.CInt, strategy: t.CInt, - zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: + zdict: BYTEPTR, zdict_len: sizet) -> Compress | t.CPtr: if pool == None: obj: Compress | t.CPtr = stdlib.calloc(1, Compress.__sizeof__()) else: @@ -667,7 +665,7 @@ def compressobj(pool: rawptr[memhub.MemManager], level: t.CInt, method: t.CInt, return obj -def decompressobj(pool: rawptr[memhub.MemManager], wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: +def decompressobj(pool: rawptr[memhub.MemManager], wbits: t.CInt, zdict: BYTEPTR, zdict_len: sizet) -> Decompress | t.CPtr: if pool == None: obj: Decompress | t.CPtr = stdlib.calloc(1, Decompress.__sizeof__()) else: @@ -694,8 +692,8 @@ def decompressobj(pool: rawptr[memhub.MemManager], wbits: t.CInt, zdict: BYTEPTR obj.input_buf_len = 0 return obj -def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: +def zlib_adler32(data: BYTEPTR, length: sizet, 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: +def zlib_crc32(data: BYTEPTR, length: sizet, value: t.CUnsignedLong) -> t.CUnsignedLong: return zchecksum.zchecksum_crc32(data, length, UINT32(value)) diff --git a/zlib/zchecksum.vp b/zlib/zchecksum.vp index d46246f..39730fc 100644 --- a/zlib/zchecksum.vp +++ b/zlib/zchecksum.vp @@ -2,12 +2,12 @@ from stdint import * import t, c -def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: +def zchecksum_adler32(data: UINT8PTR, length: sizet, 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 + i: sizet for i in range(length): a = (a + data[i]) % 65521 b = (b + a) % 65521 @@ -80,10 +80,10 @@ crc32_table: t.CArray[t.CUInt32T, 256] = [ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ] -def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: +def zchecksum_crc32(data: UINT8PTR, length: sizet, init: t.CUInt32T) -> t.CUInt32T: crc: t.CUInt32T = init ^ 0xFFFFFFFF if not data or length == 0: return init - i: t.CSizeT + i: sizet for i in range(length): crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8) return crc ^ 0xFFFFFFFF diff --git a/zlib/zdef.vp b/zlib/zdef.vp index c219998..9ce4869 100644 --- a/zlib/zdef.vp +++ b/zlib/zdef.vp @@ -94,12 +94,11 @@ zdeflate_codelen_order: t.CArray[int, 19] = [ # ============================================================ # Bit writer - writes bits LSB first into a byte buffer # ============================================================ -@t.Object class zbit_writer: pool: rawptr[memhub.MemManager] buf: BYTE | t.CPtr - cap: t.CSizeT - byte_pos: t.CSizeT + cap: sizet + byte_pos: sizet bit_pos: t.CInt def __init__(self, pool: rawptr[memhub.MemManager]): @@ -113,9 +112,9 @@ class zbit_writer: self.byte_pos = 0 self.bit_pos = 0 - def ensure(self, need: t.CSizeT): + def ensure(self, need: sizet): while self.byte_pos + need + 4 >= self.cap: - new_cap: t.CSizeT = self.cap * 2 + new_cap: sizet = self.cap * 2 if self.pool == None: new_buf: BYTE | t.CPtr = BYTEPTR(stdlib.realloc(self.buf, new_cap)) else: @@ -148,14 +147,14 @@ class zbit_writer: self.bit_pos = 0 self.byte_pos += 1 - def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + def stored_block(self, data: UINT8PTR, length: sizet, final: t.CInt): self.write_bits(1 if final else 0, 1) self.write_bits(0, 2) self.align() - pos: t.CSizeT = 0 + pos: sizet = 0 while pos < length: - block_length: t.CSizeT = length - pos + block_length: sizet = length - pos if block_length > 65535: block_length = 65535 n: t.CUInt16T = t.CUInt16T(block_length) @@ -164,7 +163,7 @@ class zbit_writer: self.write_bits(ncomp, 16) self.ensure(block_length) - i: t.CSizeT = 0 + i: sizet = 0 for i in range(block_length): self.buf[self.byte_pos] = data[pos + i] self.byte_pos += 1 @@ -210,7 +209,7 @@ class zbit_writer: self.bit_pos = 0 self.byte_pos += 1 - def total(self) -> t.CSizeT: + def total(self) -> sizet: return self.byte_pos + (1 if (self.bit_pos > 0) else 0) def free(self): @@ -229,14 +228,13 @@ class zbit_writer: # ============================================================ # 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 + length: sizet + byte_pos: sizet bit_pos: t.CInt - def init(self, buf: BYTE | t.CPtr, length: t.CSizeT): + def init(self, buf: BYTE | t.CPtr, length: sizet): self.buf = buf self.length = length self.byte_pos = 0 @@ -277,7 +275,7 @@ class zbit_reader: # Memory allocation helper for bare metal # Can be replaced with custom allocator # ============================================================ -def zdef_alloc(pool: rawptr[memhub.MemManager], n: t.CSizeT) -> VOIDPTR: +def zdef_alloc(pool: rawptr[memhub.MemManager], n: sizet) -> VOIDPTR: if pool == None: return stdlib.malloc(n) return pool.alloc(n) def zdef_free(pool: rawptr[memhub.MemManager], p: VOIDPTR): diff --git a/zlib/zdeflate.vp b/zlib/zdeflate.vp index 5fec742..e3ef543 100644 --- a/zlib/zdeflate.vp +++ b/zlib/zdeflate.vp @@ -7,7 +7,6 @@ import memhub import t, c -@t.Object class zdeflate_stream: pool: rawptr[memhub.MemManager] writer: zdef.zbit_writer @@ -22,8 +21,8 @@ class zdeflate_stream: 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: + def find_match(self, data: BYTE | t.CPtr, data_len: sizet, + pos: sizet, 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] @@ -52,7 +51,7 @@ class zdeflate_stream: 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, data_len: t.CSizeT): + def update_hash(self, data: BYTE | t.CPtr, pos: sizet, data_len: sizet): # 只在还能作为匹配起点的位置维护 hash(pos+2 >= data_len 的尾部 # 字节不会再被 find_match 引用,且 zdeflate_hash 会读 pos..pos+2, # 越过末尾则越界——见 ASan heap-buffer-overflow) @@ -61,14 +60,14 @@ class zdeflate_stream: 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): + def write_fixed_block(self, data: UINT8PTR, length: sizet, 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 + pos: sizet = 0 while pos < length: best_dist: t.CInt = 0 match_len: t.CInt = 0 @@ -94,9 +93,9 @@ class zdeflate_stream: pos += 1 lit_tree.encode_symbol(256, c.Addr(self.writer)) - def encode_block_data(self, data: UINT8PTR, length: t.CSizeT, + def encode_block_data(self, data: UINT8PTR, length: sizet, lit_tree: rawptr[zhuff.zhuff_tree], dist_tree: rawptr[zhuff.zhuff_tree]): - pos: t.CSizeT = 0 + pos: sizet = 0 while pos < length: best_dist: t.CInt = 0 match_len: t.CInt = 0 @@ -123,7 +122,7 @@ class zdeflate_stream: lit_tree.encode_symbol(256, c.Addr(self.writer)) - def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + def write_dynamic_block(self, data: UINT8PTR, length: sizet, 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) @@ -155,7 +154,7 @@ class zdeflate_stream: 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): + def compress_block(self, data: UINT8PTR, length: sizet, final: t.CInt): if self.level == 0: self.write_stored_block(data, length, final) elif self.strategy == 4 or length < 128: @@ -163,13 +162,13 @@ class zdeflate_stream: else: self.write_dynamic_block(data, length, final) - def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + def write_stored_block(self, data: UINT8PTR, length: sizet, final: t.CInt): self.writer.stored_block(data, length, final) # out 是"指针的指针"(i8**):见 zinflate.vp decompress 处的说明—— # 联合里嵌 `t.CPtr[...]` 会让声明侧(VpiReader)坍缩成 i8,与定义侧 i8** 不一致。 - def compress(self, data: UINT8PTR, length: t.CSizeT, - out: BYTEPTR | t.CPtr, out_len: t.CSizeT | t.CPtr) -> t.CInt: + def compress(self, data: UINT8PTR, length: sizet, + out: BYTEPTR | t.CPtr, out_len: sizet*) -> t.CInt: if self.is_finished: return -2 if not data or length == 0: c.Set(c.Deref(out), None) @@ -186,7 +185,7 @@ class zdeflate_stream: return 0 # out 同 compress:i8**(声明侧/定义侧必须一致)。 - def flush(self, mode: t.CInt, out: BYTEPTR | t.CPtr, out_len: t.CSizeT | t.CPtr) -> t.CInt: + def flush(self, mode: t.CInt, out: BYTEPTR | t.CPtr, out_len: sizet*) -> t.CInt: if mode == 4: if not self.is_finished: if self.level == 0: @@ -218,9 +217,9 @@ class zdeflate_stream: string.memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) return 0 - def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + def set_dictionary(self, dict: UINT8PTR, length: sizet) -> t.CInt: if not dict: return -2 - use: t.CSizeT = length + use: sizet = length if use > zdef.ZDEFLATE_WINDOW_SIZE: dict += length - zdef.ZDEFLATE_WINDOW_SIZE use = zdef.ZDEFLATE_WINDOW_SIZE @@ -262,10 +261,10 @@ class zdeflate_stream: def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, - s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT): + s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: sizet): string.memset(lit_freqs, 0, 288 * int.__sizeof__()) string.memset(dist_freqs, 0, 32 * int.__sizeof__()) - pos: t.CSizeT = 0 + pos: sizet = 0 while pos < length: best_dist: t.CInt = 0 match_len: t.CInt = 0 @@ -382,7 +381,7 @@ def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, def zdeflate_create(pool: rawptr[memhub.MemManager], level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: - n: t.CSizeT = zdeflate_stream.__sizeof__() + n: sizet = zdeflate_stream.__sizeof__() s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(pool, n) if not s: return None string.memset(s, 0, zdeflate_stream.__sizeof__()) @@ -408,8 +407,8 @@ def zdeflate_create(pool: rawptr[memhub.MemManager], level: t.CInt, wbits: t.CIn return s -def zdeflate_one_shot(pool: rawptr[memhub.MemManager], data: UINT8PTR, length: t.CSizeT, - level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: +def zdeflate_one_shot(pool: rawptr[memhub.MemManager], data: UINT8PTR, length: sizet, + level: t.CInt, wbits: t.CInt, out_len: sizet*) -> t.CUInt8T | t.CPtr: s: zdeflate_stream | t.CPtr = zdeflate_create(pool, level, wbits, 8, 0) if not s: return None diff --git a/zlib/zhuff.vp b/zlib/zhuff.vp index 0b2a159..65ebd11 100644 --- a/zlib/zhuff.vp +++ b/zlib/zhuff.vp @@ -303,7 +303,6 @@ class zhuff_decode_node: symbol: t.CInt -@t.Object class zhuff_decode_tree: pool: rawptr[memhub.MemManager] nodes: t.CArray[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] diff --git a/zlib/zinflate.vp b/zlib/zinflate.vp index c39d103..a5c6577 100644 --- a/zlib/zinflate.vp +++ b/zlib/zinflate.vp @@ -7,7 +7,6 @@ import memhub import t, c -@t.Object class zinflate_stream: pool: rawptr[memhub.MemManager] reader: zdef.zbit_reader @@ -27,14 +26,14 @@ class zinflate_stream: crc: t.CUInt32T output: BYTEPTR - output_len: t.CSizeT - output_cap: t.CSizeT + output_len: sizet + output_cap: sizet input_data: t.CConst | BYTEPTR - input_len: t.CSizeT - input_pos: t.CSizeT + input_len: sizet + input_pos: sizet - max_length: t.CSizeT + max_length: sizet def __init__(self): pass @@ -43,7 +42,7 @@ class zinflate_stream: 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 + new_cap: sizet = 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 @@ -384,8 +383,8 @@ class zinflate_stream: # 改用"指针别名 | t.CPtr":两侧都按"追加 1 层指针"解析,同为 i8**。 # 同形先例:includes/w32/win32sync.vp:65 `Context: VOIDPTR | t.CPtr`、 # includes/posix.vp:199 `argv: CHARPTR | t.CPtr`。 - def decompress(self, data: UINT8PTR, length: t.CSizeT, - max_length: t.CSizeT, out: BYTEPTR | t.CPtr, out_len: t.CSizeT | t.CPtr) -> t.CInt: + def decompress(self, data: UINT8PTR, length: sizet, + max_length: sizet, out: BYTEPTR | t.CPtr, out_len: sizet*) -> t.CInt: if not self.is_initialized: return -2 self.input_data = data self.input_len = length @@ -405,9 +404,9 @@ class zinflate_stream: string.memcpy(dst, self.output, self.output_len) return 0 - def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + def set_dictionary(self, dict: UINT8PTR, length: sizet) -> t.CInt: if not dict: return -2 - use: t.CSizeT = length + use: sizet = length if use > zdef.ZDEFLATE_WINDOW_SIZE: dict += length - zdef.ZDEFLATE_WINDOW_SIZE use = zdef.ZDEFLATE_WINDOW_SIZE @@ -435,8 +434,8 @@ class zinflate_stream: zdef.zdef_free(self.pool, self) -def zinflate_one_shot(pool: rawptr[memhub.MemManager], data: UINT8PTR, length: t.CSizeT, - wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: +def zinflate_one_shot(pool: rawptr[memhub.MemManager], data: UINT8PTR, length: sizet, + wbits: t.CInt, bufsize: sizet, out_len: sizet*) -> t.CUInt8T | t.CPtr: s: zinflate_stream | t.CPtr = zinflate_create(pool, wbits) if not s: return None out: t.CUInt8T | t.CPtr = None