Some simple information syncing

This commit is contained in:
2026-07-28 21:08:58 +08:00
parent 1837339f69
commit 3633be1995
65 changed files with 1132 additions and 368581 deletions

View File

@@ -127,33 +127,26 @@ class ArgumentParser:
def __new__(self, prog: str = "", description: str = "",
pool: memhub.MemBuddy | t.CPtr = None) -> t.CPtr:
stdio.printf("[DBG-argparse] __new__ enter pool=%p\n", pool)
stdio.fflush(0)
mb: memhub.MemBuddy | t.CPtr = pool
if mb is None: mb = _mbuddy
stdio.printf("[DBG-argparse] __new__ mb=%p\n", mb)
stdio.fflush(0)
ret: t.CPtr = mb.alloc(40)
stdio.printf("[DBG-argparse] __new__ ret=%p\n", ret)
stdio.fflush(0)
return ret
def __init__(self, prog: str = "", description: str = "",
pool: memhub.MemBuddy | t.CPtr = None):
stdio.printf("[DBG-argparse] __init__ enter self=%p pool=%p\n", self, pool)
stdio.fflush(0)
mb: memhub.MemBuddy | t.CPtr = pool
if mb is None: mb = _mbuddy
stdio.printf("[DBG-argparse] __init__ mb=%p\n", mb)
stdio.fflush(0)
self.__mbuddy__ = mb
self._prog = prog
self._description = description
self._arg_count = 0
stdio.printf("[DBG-argparse] __init__ before alloc\n")
stdio.fflush(0)
self._args = mb.alloc(MAX_ARGS * Argument.__sizeof__())
stdio.printf("[DBG-argparse] __init__ after alloc _args=%p\n", self._args)
stdio.fflush(0)
def add_argument(self, name: str = "", short: str = None,
arg_type: INT = 0, default: INT = 0,
@@ -172,17 +165,13 @@ class ArgumentParser:
help: 帮助文本
"""
stdio.printf("[DBG-argparse] enter add_argument name=%s args_ptr=%p\n", name, self._args)
stdio.fflush(0)
if self._arg_count >= MAX_ARGS: return
idx: INT = self._arg_count
stdio.printf("[DBG-argparse] idx=%d sizeof(Argument)=%d\n", idx, Argument.__sizeof__())
stdio.fflush(0)
arg: Argument | t.CPtr = t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__())
stdio.printf("[DBG-argparse] arg ptr=%p\n", arg)
stdio.fflush(0)
arg.name = name
stdio.printf("[DBG-argparse] after arg.name=%s\n", arg.name)
stdio.fflush(0)
arg.short_name = short
arg.help_text = help
arg.arg_type = arg_type
@@ -191,7 +180,6 @@ class ArgumentParser:
arg.default_str = default_str
arg.required = required
stdio.printf("[DBG-argparse] before dest logic\n")
stdio.fflush(0)
# 判断是否位置参数
if name is not None and name[0] != '-':
arg.is_positional = True
@@ -203,10 +191,8 @@ class ArgumentParser:
else:
arg.dest = name + 1
stdio.printf("[DBG-argparse] after dest logic\n")
stdio.fflush(0)
self._arg_count = idx + 1
stdio.printf("[DBG-argparse] exit add_argument\n")
stdio.fflush(0)
def _get_arg(self, idx: INT) -> Argument | t.CPtr:
return t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__())

View File

@@ -11,7 +11,7 @@ from .tokens import (
from .base import (
AST, ASTKind, ASTCtx, OpKind, ASTFlag,
# 常量
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR,
# 辅助函数
_init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list,

View File

@@ -148,6 +148,7 @@ 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
# 标志位
FLAG_IS_ASYNC: t.CDefine = 1

View File

@@ -6,7 +6,7 @@ from .base import (
AST, ASTKind, ASTCtx, OpKind,
_init_ast, _copy_str, _set_parent_list,
_emit, _emit_str, _emit_int, _dump_list, _dump_op_list, _op_name,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR
)
@@ -106,6 +106,11 @@ class Constant(AST):
else:
pos = _emit(buf, size, pos, "(null)")
pos = _emit(buf, size, pos, "'")
elif self.const_kind == CONST_CHAR:
# 单引号单字符 → 显示为字符 ASCII 值
pos = _emit(buf, size, pos, "char(")
pos = _emit_int(buf, size, pos, self.int_val)
pos = _emit(buf, size, pos, ")")
elif self.const_kind == CONST_BOOL:
if self.int_val != 0:
pos = _emit(buf, size, pos, "True")

View File

@@ -530,6 +530,8 @@ def _read_string(lx: Lexer | t.CPtr):
tok: Token | t.CPtr = new_token(lx.pool, TokenType.String, start_lineno, start_col)
if tok == None: return
content_len: t.CSizeT = content_end - content_buf_start
# esc_len: 转义后实际字节数(用于判断单字符)
esc_len: t.CSizeT = content_len
# 处理转义序列(非 raw 字符串)
if is_raw == 0 and content_len > 0:
@@ -572,15 +574,22 @@ def _read_string(lx: Lexer | t.CPtr):
rpos += 1
conv_buf[wpos] = '\0'
token_set_str_literal(lx.pool, tok, conv_buf)
esc_len = wpos
else:
token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len)
tok.end_lineno = lx.lineno
tok.end_col_offset = lx.col
# flags 字段复用bit0=raw, bit1=bytes, bit2=fstring, bit3=triple
# flags 字段复用bit0=raw, bit1=bytes, bit2=fstring, bit3=triple, bit4=dquote, bit5=单字符候选
if is_raw: tok.kw_subtype = tok.kw_subtype | 1
if is_bytes: tok.kw_subtype = tok.kw_subtype | 2
if is_fstring: tok.kw_subtype = tok.kw_subtype | 4
if is_triple: tok.kw_subtype = tok.kw_subtype | 8
# bit4 (16) = 双引号0=单引号, 1=双引号)
if quote == '"': tok.kw_subtype = tok.kw_subtype | 16
# bit5 (32) = 单字符候选(非三引号、非 fstring、转义后正好 1 字节)
# 用于 CONST_CHAR 判定,避免 '\0' 等含 NUL 字节被 strlen 误判为空字符串
if is_triple == 0 and is_fstring == 0 and esc_len == 1:
tok.kw_subtype = tok.kw_subtype | 32
_emit(lx, tok)

View File

@@ -7,7 +7,7 @@ from .base import (
AST, ASTCtx, ASTKind, OpKind, ASTFlag,
_set_pos, _binop_from_op, _augop_from_op, _cmpop_from_op, _copy_str, _inherit_pos,
_init_ast,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE,
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
FLAG_IS_ASYNC,
)
from .exprs import (
@@ -169,7 +169,30 @@ def _new_const_float(pool: memhub.MemManager | t.CPtr, val: t.CDouble,
def _new_const_str(pool: memhub.MemManager | t.CPtr, val: str,
lineno: t.CInt, col: t.CInt) -> AST | t.CPtr:
lineno: t.CInt, col: t.CInt,
is_dquote: t.CInt = 1,
is_triple: t.CInt = 0,
is_char: t.CInt = 0) -> AST | t.CPtr:
"""创建字符串/字符常量节点
is_dquote: 0=单引号, 非0=双引号(默认双引号)
is_triple: 非0=三引号字符串
is_char: 非0=单字符候选lexer 已确认转义后正好 1 字节, 含 '\\0'
语义区分:
- 'x' (单引号单字符, 非三引号) → CONST_CHAR (i8 值)
- "x" (双引号, 含\\0终止符) → CONST_STR (i8* 指针, i8 x 2)
- 'ab' (单引号多字符) → CONST_STR (i8* 指针)
- '''x''' / \"\"\"x\"\"\" (三引号) → CONST_STR (i8* 指针)
- '' / \"\" (空字符串) → CONST_STR (i8* 指针)
"""
# 单引号、非三引号、lexer 标记的单字符候选 → CONST_CHAR
# 用 is_char 标记而非 strlen(val),因为 '\0' 转义后是 NUL 字节strlen 会返回 0
if is_dquote == 0 and is_triple == 0 and is_char != 0:
# 单字符 → CONST_CHARint_val 存储字符 ASCII 值
# val[0] 即使是 NUL 也是合法值 0
ch_val: t.CInt64T = val[0]
return Constant(pool, CONST_CHAR, ch_val, 0.0, val, lineno, col)
# 其他情况 → CONST_STR
return Constant(pool, CONST_STR, 0, 0.0, val, lineno, col)
@@ -751,10 +774,13 @@ def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr:
if ttype == TokenType.String:
sval: str = _cur_str(ps)
is_fstr: t.CInt = ps.cur.kw_subtype & 4
is_triple: t.CInt = ps.cur.kw_subtype & 8
is_dquote: t.CInt = ps.cur.kw_subtype & 16
is_char: t.CInt = ps.cur.kw_subtype & 32
_advance(ps)
if is_fstr:
return _parse_fstring(ps, sval, lineno, col)
return _new_const_str(ps.pool, sval, lineno, col)
return _new_const_str(ps.pool, sval, lineno, col, is_dquote, is_triple, is_char)
if _match_op(ps, TokOp.Ellipsis):
_advance(ps)
@@ -1551,12 +1577,14 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
level += 3
_advance(ps)
module_name: str = None
if _cur_type(ps) == TokenType.Name:
# 关键字(如 import的 token type 也是 Name必须通过 kw_subtype 排除,
# 否则 `from . import` 中的 `import` 会被误认为 module_name
if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword:
module_name = _cur_str(ps)
_advance(ps)
while _match_op(ps, TokOp.Dot):
_advance(ps)
if _cur_type(ps) == TokenType.Name:
if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword:
next_name: str = _cur_str(ps)
mlen: t.CInt = string.strlen(module_name)
nlen: t.CInt = string.strlen(next_name)
@@ -1571,6 +1599,7 @@ def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr:
ps.error_count += 1
return None
_advance(ps)
_skip_nl(ps)
# import *
if _match_op(ps, TokOp.Star):
_advance(ps)
@@ -2058,8 +2087,9 @@ def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr:
# 字符串字面量 pattern
if ttype == TokenType.String:
sval = _cur_str(ps)
is_dquote_m: t.CInt = ps.cur.kw_subtype & 16
_advance(ps)
val = _new_const_str(ps.pool, sval, lineno, col)
val = _new_const_str(ps.pool, sval, lineno, col, is_dquote_m)
node = MatchValue(ps.pool, val)
_set_pos(node, lineno, col, 0, 0)
return node

View File

@@ -847,10 +847,28 @@ def build_ui2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
# ============================================================
# GEP 指令
# ============================================================
def _is_ptr_type(ty: LLVMType | t.CPtr) -> int:
"""检查 ty 是否是 Ptr 类型(独立函数,避免嵌套 match 的编译器 BUG"""
if ty is None:
return 0
match ty:
case LLVMType.Ptr(pointee):
return 1
case _:
return 0
def build_gep(builder: IRBuilder | t.CPtr, elem_ty: LLVMType | t.CPtr,
ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr:
"""%N = getelementptr <elem_ty>, <ptr_ty> <ptr>, <idx_ty> <idx>"""
if builder 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:
stdio.printf("[GEP-ERR] base not pointer, skip GEP\n")
return None
pool: memhub.MemBuddy | t.CPtr = builder.Pool
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
elem_ty_s: t.CChar | t.CPtr = _type_str(builder, elem_ty)
@@ -918,7 +936,6 @@ def build_gep_struct(builder: IRBuilder | t.CPtr, struct_ty: LLVMType | t.CPtr,
line: t.CChar | t.CPtr = pool.alloc(2048)
if line is None:
stdio.printf("[BGS] line alloc None\n")
stdio.fflush(0)
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)
@@ -928,14 +945,12 @@ def build_gep_struct(builder: IRBuilder | t.CPtr, struct_ty: LLVMType | t.CPtr,
result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if result_ty is None:
stdio.printf("[BGS] result_ty alloc None\n")
stdio.fflush(0)
else:
string.memset(result_ty, 0, LLVMType.__sizeof__())
c.DerefAs(result_ty, LLVMType.Ptr(field_ty))
rv: Value | t.CPtr = SSAValue(pool, result_ty, name)
if rv is None:
stdio.printf("[BGS] SSAValue None\n")
stdio.fflush(0)
return rv

View File

@@ -435,7 +435,6 @@ class MemBuddy(MemManager):
ub: t.CSizeT = self.usable_size - fb
stdio.printf("[MEM-FAIL] alloc(%zu) failed: total=%zu used=%zu free=%zu free_blocks=%zu\n",
size, self.usable_size, ub, fb, self.free_count())
stdio.fflush(0)
self._unlock()
return result
@@ -534,7 +533,6 @@ class MemBuddy(MemManager):
label, self.usable_size, ub,
(ub * 100) / self.usable_size if self.usable_size > 0 else 0,
fb, self.free_count())
stdio.fflush(0)
def self_check(self) -> t.CInt:
# 验证伙伴分配器内部一致性,返回 0=OK非 0=损坏

View File

@@ -262,11 +262,30 @@ def atoll(src: str) -> t.CInt64T:
s += 1
elif s[0] == '+':
s += 1
for ch in s:
if ch < '0' or ch > '9': break
d: t.CInt = ch - '0'
digit: t.CInt64T = t.CInt64T(d)
num = num * 10 + digit
# 十六进制前缀 0x / 0X
is_hex: t.CInt = 0
if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'):
is_hex = 1
s += 2
if is_hex:
for ch in s:
d: t.CInt = 0
if ch >= '0' and ch <= '9':
d = ch - '0'
elif ch >= 'a' and ch <= 'f':
d = ch - 'a' + 10
elif ch >= 'A' and ch <= 'F':
d = ch - 'A' + 10
else:
break
digit: t.CInt64T = t.CInt64T(d)
num = num * 16 + digit
else:
for ch in s:
if ch < '0' or ch > '9': break
d: t.CInt = ch - '0'
digit: t.CInt64T = t.CInt64T(d)
num = num * 10 + digit
return num * sign

View File

@@ -20,13 +20,11 @@ def begin(name: str):
SetConsoleOutputCP(CP_UTF8)
SetConsoleCP(CP_UTF8)
stdio.printf("=== %s ===\n\n", name)
stdio.fflush(None)
def section(name: str):
"""打印分节标题"""
stdio.printf("--- %s ---\n", name)
stdio.fflush(None)
def ok(msg: str):
@@ -34,7 +32,6 @@ def ok(msg: str):
global _pass_count
_pass_count += 1
stdio.printf("PASS: %s\n", msg)
stdio.fflush(None)
def fail(msg: str):
@@ -42,7 +39,6 @@ def fail(msg: str):
global _fail_count
_fail_count += 1
stdio.printf("FAIL: %s\n", msg)
stdio.fflush(None)
def check(cond: t.CInt, ok_msg: str, fail_msg: str):
@@ -56,7 +52,6 @@ def check(cond: t.CInt, ok_msg: str, fail_msg: str):
def info(msg: str):
"""打印信息消息(不计入 PASS/FAIL"""
stdio.printf("%s\n", msg)
stdio.fflush(None)
def end() -> t.CInt:
@@ -66,7 +61,6 @@ def end() -> t.CInt:
_total_fail += _fail_count
stdio.printf("\n--- Summary ---\n")
stdio.printf("PASS: %d, FAIL: %d\n", _pass_count, _fail_count)
stdio.fflush(None)
return _fail_count
@@ -74,5 +68,4 @@ def summary() -> t.CInt:
"""打印所有套件的总计汇总,返回总失败数"""
stdio.printf("\n=== Total Summary ===\n")
stdio.printf("Total PASS: %d, Total FAIL: %d\n", _total_pass, _total_fail)
stdio.fflush(None)
return _total_fail

View File

@@ -51,9 +51,6 @@ class File:
self.is_append = False
self._share_mode = share
stdio.printf("[FILE] __init__ filename=%s mode=%d share=%d\n", filename, mode, share)
stdio.fflush(0)
access: ULONG = 0
disposition: ULONG = w32.win32file.OPEN_EXISTING
@@ -100,18 +97,12 @@ class File:
disposition = w32.win32file.OPEN_EXISTING
self.can_read = True
stdio.printf("[FILE] before CreateFileA access=%d disp=%d share=%d\n", access, disposition, self._share_mode)
stdio.fflush(0)
self.handle = w32.win32file.CreateFileA(
filename, access, self._share_mode,
None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None
)
stdio.printf("[FILE] after CreateFileA handle=%p\n", self.handle)
stdio.fflush(0)
if self.handle == w32.win32base.INVALID_HANDLE_VALUE:
stdio.printf("[FILE] FAIL: handle == INVALID_HANDLE_VALUE\n")
stdio.fflush(0)
self.closed = True
return
@@ -202,21 +193,16 @@ class File:
if self.closed: return FRESULT.ERR_CLOSED
if not self.can_read: return FRESULT.ERR_PERM
if max_count < 2: return FRESULT.ERR
# stdio.printf("[DBG read_all] before size()\n")
file_size: LONGLONG = self.size()
# stdio.printf("[DBG read_all] after size(), file_size=%lld\n", file_size)
if file_size < 0: return FRESULT.ERR_IO
to_read: ULONG = 0
if file_size < max_count - 1:
to_read = ULONG(file_size)
else:
to_read = max_count - 1
# stdio.printf("[DBG read_all] to_read=%u, before seek\n", to_read)
self.seek(0, SEEK_SET)
# stdio.printf("[DBG read_all] after seek, before ReadFile\n")
bytes_read: ULONG = 0
result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), None)
# stdio.printf("[DBG read_all] after ReadFile, result=%d, bytes_read=%u\n", result, bytes_read)
if result == 0: return FRESULT.ERR_IO
if bytes_read < max_count:
buf[bytes_read] = 0

View File

@@ -5,7 +5,7 @@ HANDLE: t.CTypedef = VOIDPTR
LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr
LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr
INVALID_HANDLE_VALUE: t.CDefine = 0xFFFFFFFF
INVALID_HANDLE_VALUE: t.CDefine = -1
NULL: t.CDefine = 0
TRUE: t.CDefine = 1
FALSE: t.CDefine = 0