按 wiki/新规范:注释只讲作用、不掺杂历史原因、避免超长、尽可能英文(含三引号 __doc__)。全文 79 个 .vp:# 注释 16269 行(中文 13808)与 docstring(中文 1381 处)全部改英文;超 2 行的注释块(2093)与 docstring(397)全部压到 2 行。运行时可见文本未动(fatal_error/VLogger 的中文报错文案、stdio.printf 的横幅格式串)。校验:屏蔽注释与三引号后逐行比对各文件代码骨架,0 漂移。验证:自举重建 153.48s 通过(跨模块内联完成);TPV 顺序回归 77/77 全通过。
245 lines
9.1 KiB
Plaintext
245 lines
9.1 KiB
Plaintext
import t, c
|
|
from stdint import *
|
|
import stdio
|
|
import stdlib
|
|
import memhub
|
|
import sys
|
|
import w32.win32console as w32cmd
|
|
import w32.win32file as w32file
|
|
import w32.win32base as win32base
|
|
|
|
|
|
# VLogger - native logger with colored Windows console output.
|
|
# Format: ├ LEVEL: message or ├ LEVEL[category]: message (aligned with TPC lib/core/VLogger.py).
|
|
|
|
# Error recovery (REPL/JIT): after error, longjmp back to the REPL setjmp point.
|
|
# mingw-w64 x86_64: longjmp is void longjmp(jmp_buf, int); setjmp expands to _setjmp(buf, NULL).
|
|
extern def longjmp(buf: rawptr, val: int)
|
|
|
|
|
|
# REPL recovery-point pointer: registered at session start, cleared at session end.
|
|
# Covers the whole fragment pipeline; batch mode never sets it, so it stays None and exits via sys.exit(1).
|
|
_repl_jmpbuf: rawptr = None
|
|
|
|
|
|
# repl_abort - the single "terminate after diagnosis" exit in TPV.
|
|
# Caller already printed the diagnostic; returns to REPL via longjmp if a recovery point is set, else sys.exit(1).
|
|
def repl_abort() -> int:
|
|
"""Unified exit after diagnosis: longjmp to the REPL if a recovery point is set, else exit."""
|
|
if _repl_jmpbuf is not None:
|
|
stdio.fflush(None)
|
|
longjmp(_repl_jmpbuf, 1)
|
|
sys.exit(1)
|
|
return 0
|
|
|
|
|
|
def set_repl_jmpbuf(buf: t.CPtr) -> int:
|
|
"""Register the REPL jmp_buf; idempotent at each fragment entry."""
|
|
global _repl_jmpbuf
|
|
_repl_jmpbuf = buf
|
|
return 0
|
|
|
|
|
|
def clear_repl_jmpbuf() -> int:
|
|
"""Clear the registered jmp_buf at REPL session end."""
|
|
global _repl_jmpbuf
|
|
_repl_jmpbuf = None
|
|
return 0
|
|
|
|
# Log levels
|
|
enum LogLevel:
|
|
DEBUG, INFO, WARNING, ERROR, SUCCESS, CRITICAL
|
|
|
|
|
|
# Win32 console foreground color attributes
|
|
define FOREGROUND_BLUE = 0x0001
|
|
define FOREGROUND_GREEN = 0x0002
|
|
define FOREGROUND_RED = 0x0004
|
|
define FOREGROUND_INTENSITY = 0x0008
|
|
define FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
|
define FOREGROUND_CYAN = FOREGROUND_BLUE | FOREGROUND_GREEN
|
|
define FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN
|
|
define FOREGROUND_MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE
|
|
|
|
# Win32 console background color attributes
|
|
define BACKGROUND_RED = 0x0040
|
|
define BACKGROUND_GREEN = 0x0020
|
|
define BACKGROUND_BLUE = 0x0010
|
|
define BACKGROUND_INTENSITY = 0x0080
|
|
define BACKGROUND_WHITE = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
|
|
|
|
|
novirtual class Logger:
|
|
_level: int
|
|
_console_handle: win32base.HANDLE
|
|
_use_color: int
|
|
jit_flag: bool
|
|
__mbuddy__: memhub.MemBuddy*
|
|
|
|
def __init__(self, level: int = 1):
|
|
self._level = level
|
|
self._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE)
|
|
self._use_color = 1
|
|
self.jit_flag = False
|
|
self.__mbuddy__ = _mbuddy
|
|
|
|
def _set_color(self, attr: WORD) -> int:
|
|
uc: int = self._use_color
|
|
if uc:
|
|
ch: win32base.HANDLE = self._console_handle
|
|
ret: int = w32cmd.SetConsoleTextAttribute(ch, attr)
|
|
return ret
|
|
return 0
|
|
|
|
def _reset_color(self) -> int:
|
|
if self._use_color: return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE)
|
|
return 0
|
|
|
|
# _log - core log output with segmented coloring (prefix symbol / level tag / message).
|
|
# Format: ├ LEVEL: msg or ├ LEVEL[category]: msg.
|
|
def _log(self, level: int, prefix_sym: str, level_str: str, msg: str, sym_color: WORD, level_color: WORD, category: str = "") -> int:
|
|
# Color the prefix symbol
|
|
self._set_color(sym_color)
|
|
stdio.printf("%s ", prefix_sym)
|
|
# Color the level tag
|
|
self._set_color(level_color)
|
|
stdio.printf("%s", level_str)
|
|
self._reset_color()
|
|
# Optional category
|
|
if category is not None and category[0] != 0: stdio.printf(" [%s]", category)
|
|
stdio.printf(": %s\n", msg)
|
|
return 0
|
|
|
|
def debug(self, msg: str, category: str = "") -> int:
|
|
return self._log(LogLevel.DEBUG, "├", "DEBUG", msg, FOREGROUND_INTENSITY, FOREGROUND_INTENSITY, category)
|
|
|
|
def info(self, msg: str, category: str = "") -> int:
|
|
ret: int = self._log(LogLevel.INFO, "├", "INFO", msg, FOREGROUND_GREEN, FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
|
return ret
|
|
|
|
def warning(self, msg: str, category: str = "") -> int:
|
|
return self._log(LogLevel.WARNING, "├", "WARN", msg, FOREGROUND_YELLOW, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
|
|
|
def error(self, msg: str, category: str = "") -> int:
|
|
ret: int = self._log(LogLevel.ERROR, "├", "ERROR", msg, FOREGROUND_RED, FOREGROUND_RED | FOREGROUND_INTENSITY, category)
|
|
# JIT/REPL: diagnostic already printed; jump back to the REPL loop via the unified exit.
|
|
if self.jit_flag:
|
|
repl_abort()
|
|
return ret
|
|
# Batch mode: terminate immediately on error.
|
|
sys.exit(1)
|
|
return ret
|
|
|
|
def success(self, msg: str, category: str = "") -> int:
|
|
return self._log(LogLevel.SUCCESS, "├", "SUCCESS", msg, FOREGROUND_GREEN, FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
|
|
|
def critical(self, msg: str, category: str = "") -> int:
|
|
# CRITICAL uses the ╠ prefix (red-background white label, aligned with TPC style).
|
|
return self._log(LogLevel.CRITICAL, "╠", "CRITICAL", msg, FOREGROUND_RED, BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY, category)
|
|
|
|
def set_level(self, level: int) -> int:
|
|
self._level = level
|
|
return 0
|
|
|
|
def set_jit_flag(self, v: bool) -> int:
|
|
"""Set the JIT/REPL flag: True makes error longjmp back to the REPL loop."""
|
|
self.jit_flag = v
|
|
return 0
|
|
|
|
# Advanced log methods.
|
|
|
|
def banner(self, msg: str) -> int:
|
|
"""Print a blue-highlighted section banner."""
|
|
self._set_color(FOREGROUND_BLUE | FOREGROUND_INTENSITY)
|
|
stdio.printf("\n=== %s ===\n\n", msg)
|
|
self._reset_color()
|
|
return 0
|
|
|
|
def compile_error(self, msg: str, file: str = "", line: int = 0) -> int:
|
|
"""Format a compile error with a red-background header, location and message."""
|
|
self._set_color(BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY)
|
|
stdio.printf(" 编译错误 ")
|
|
self._set_color(FOREGROUND_RED | FOREGROUND_INTENSITY)
|
|
stdio.printf("\n")
|
|
if file is not None:
|
|
if file[0] != 0 and line > 0: stdio.printf(" 位置: %s:%d\n", file, line)
|
|
elif file[0] != 0: stdio.printf(" 文件: %s\n", file)
|
|
stdio.printf(" 错误: %s\n", msg)
|
|
self._reset_color()
|
|
return 0
|
|
|
|
def compile_warning(self, msg: str, file: str = "", line: int = 0) -> int:
|
|
"""Format a compile warning with a yellow background, location and message."""
|
|
self._set_color(BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_INTENSITY)
|
|
stdio.printf(" 编译警告 ")
|
|
self._set_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY)
|
|
stdio.printf("\n")
|
|
if file is not None:
|
|
if file[0] != 0 and line > 0: stdio.printf(" 位置: %s:%d\n", file, line)
|
|
elif file[0] != 0: stdio.printf(" 文件: %s\n", file)
|
|
stdio.printf(" 警告: %s\n", msg)
|
|
self._reset_color()
|
|
return 0
|
|
|
|
|
|
# Global mbuddy pointer (injected by lib.InitLib).
|
|
_mbuddy: memhub.MemBuddy*
|
|
|
|
# Global logger pointer
|
|
logger: Logger*
|
|
log: Logger*
|
|
|
|
def init_logger():
|
|
"""Initialize the global logger instance."""
|
|
global logger, log
|
|
raw: t.CPtr = _mbuddy.alloc(Logger.__sizeof__())
|
|
# if raw is None: return None (memory management still unclear)
|
|
logger = raw
|
|
logger.__before_init__()
|
|
logger.__init__(LogLevel.INFO)
|
|
log = logger
|
|
# if fmtbuffer is None: return None
|
|
|
|
|
|
# --nowarn-register switch: suppresses Phase A dependency WARN output (output only).
|
|
_nowarn_register: int = 0
|
|
|
|
# Module-level convenience functions (aligned with TPC lib.core.VLogger; no get_logger() needed).
|
|
|
|
def info(msg: str, category: str = "") -> int:
|
|
"""Log at INFO level."""
|
|
if log is not None: return log.info(msg, category)
|
|
return 0
|
|
|
|
|
|
def warning(msg: str, category: str = "") -> int:
|
|
"""Log at WARN level."""
|
|
if log is not None: return log.warning(msg, category)
|
|
return 0
|
|
|
|
|
|
def error(msg: str, category: str = "") -> int:
|
|
"""Log at ERROR level: exit in batch mode, longjmp to REPL under JIT/REPL."""
|
|
if log is not None: return log.error(msg, category)
|
|
# When the logger is unavailable, still use the unified exit (REPL can recover if registered)
|
|
repl_abort()
|
|
return 0
|
|
|
|
|
|
def success(msg: str, category: str = "") -> int:
|
|
"""Log at SUCCESS level."""
|
|
if log is not None: return log.success(msg, category)
|
|
return 0
|
|
|
|
|
|
def critical(msg: str, category: str = "") -> int:
|
|
"""Log at CRITICAL level (fatal, red background)."""
|
|
if log is not None: return log.critical(msg, category)
|
|
return 0
|
|
|
|
|
|
def debug(msg: str, category: str = "") -> int:
|
|
"""Log at DEBUG level."""
|
|
if log is not None: return log.debug(msg, category)
|
|
return 0
|