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 - 原生日志系统(Windows 控制台彩色输出) # # 输出格式与 TPC (lib/core/VLogger.py) 对齐: # ├ INFO: message # ├ INFO[category]: message # ├ WARN: message # ├ ERROR: message # ├ SUCCESS: message # ├ DEBUG: message # ╠ CRITICAL: message (红底白字,致命错误) # ╠ CRITICAL[category]: message # # 分段着色:前缀符号(├/╠) 用级别色,LEVEL 标签用亮色,消息用默认色 # CRITICAL 级别使用 ╠ 前缀和红底白字标签,与 TPC critical 对齐 # ============================================================ # 日志级别 class LogLevel(t.CEnum): DEBUG = 0 INFO = 1 WARNING = 2 ERROR = 3 SUCCESS = 4 CRITICAL = 5 # Win32 控制台前景色属性 FOREGROUND_BLUE: t.CDefine = 0x0001 FOREGROUND_GREEN: t.CDefine = 0x0002 FOREGROUND_RED: t.CDefine = 0x0004 FOREGROUND_INTENSITY: t.CDefine = 0x0008 FOREGROUND_WHITE: t.CDefine = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE FOREGROUND_CYAN: t.CDefine = FOREGROUND_BLUE | FOREGROUND_GREEN FOREGROUND_YELLOW: t.CDefine = FOREGROUND_RED | FOREGROUND_GREEN FOREGROUND_MAGENTA: t.CDefine = FOREGROUND_RED | FOREGROUND_BLUE # Win32 控制台背景色属性 BACKGROUND_RED: t.CDefine = 0x0040 BACKGROUND_GREEN: t.CDefine = 0x0020 BACKGROUND_BLUE: t.CDefine = 0x0010 BACKGROUND_INTENSITY: t.CDefine = 0x0080 BACKGROUND_WHITE: t.CDefine = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE class Logger: _level: int _console_handle: w32base.HANDLE _use_color: int __mbuddy__: memhub.MemManager | t.CPtr def __init__(self, level: int = 1): self._level = level self._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE) self._use_color = 1 self.__mbuddy__ = _mbuddy def _set_color(self, attr: WORD) -> int: if self._use_color: return w32cmd.SetConsoleTextAttribute(self._console_handle, attr) return 0 def _reset_color(self) -> int: if self._use_color: return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE) return 0 # ============================================================ # _log - 核心日志输出(分段着色) # # 格式: ├ LEVEL: msg 或 ├ LEVEL[category]: msg # 分三段着色: # 1. 前缀符号 ├ (sym_color) # 2. LEVEL 标签 (level_color) # 3. 消息内容 (默认白色) # ============================================================ def _log(self, level: int, prefix_sym: str, level_str: str, msg: str, sym_color: WORD, level_color: WORD, category: str = "") -> int: if level < self._level: return 0 # 前缀符号(如 ├) self._set_color(sym_color) stdio.printf("%s ", prefix_sym) # LEVEL 标签(亮色) self._set_color(level_color) if category is not None: if category[0] != 0: stdio.printf("%s[%s]: ", level_str, category) else: stdio.printf("%s: ", level_str) else: stdio.printf("%s: ", level_str) # 消息内容(默认色) self._reset_color() 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: return self._log(LogLevel.INFO, "├", "INFO", msg, FOREGROUND_GREEN, FOREGROUND_GREEN | FOREGROUND_INTENSITY, category) 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) # 错误立即终止进程(避免错误后继续执行导致连锁崩溃) 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 使用 ╠ 前缀(红底白字标签,对齐 TPC critical 风格) 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 banner(self, msg: str) -> int: """输出分节标题(蓝色高亮,与 TPC 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: """格式化编译错误输出(红底白字标题 + 位置 + 错误信息)。""" 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: """格式化编译警告输出(黄底黑字标题 + 位置 + 警告信息)。""" 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 # 全局 mbuddy 指针(由 lib.InitLib 注入) _mbuddy: memhub.MemManager | t.CPtr # 全局 logger 指针 _g_logger: Logger | t.CPtr # 全局格式化缓冲区(用于带变量的日志消息,1024 字节) _fmt_buf: t.CChar | t.CPtr def fmt_buf() -> t.CChar | t.CPtr: """获取全局格式化缓冲区(1024 字节)。 用法: buf: t.CChar | t.CPtr = VLogger.fmt_buf() if buf is not None: viperlib.snprintf(buf, 1024, "翻译: %s (sha1=%s)", rp, sha1) log.info(buf, "Phase1") """ global _fmt_buf if _fmt_buf is None: _fmt_buf = stdlib.malloc(1024) return _fmt_buf def get_logger() -> Logger | t.CPtr: """获取全局 logger 实例。若不存在则通过 _mbuddy 分配并初始化。""" global _g_logger if _g_logger is None: if _mbuddy is None: return None raw: t.CVoid | t.CPtr = _mbuddy.alloc(Logger.__sizeof__()) if raw is None: return None _g_logger = raw _g_logger._level = LogLevel.INFO _g_logger._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE) _g_logger._use_color = 1 _g_logger.__mbuddy__ = _mbuddy return _g_logger def set_logger(logger: Logger | t.CPtr) -> int: """设置全局 logger 实例。""" global _g_logger _g_logger = logger return 0 # ============================================================ # 模块级便捷函数(与 TPC 的 lib.core.VLogger 对齐) # # 调用方式: VLogger.info("msg", "category") # 无需先 get_logger(),方便各模块直接使用 # ============================================================ def info(msg: str, category: str = "") -> int: """输出 INFO 级别日志。""" log: Logger | t.CPtr = get_logger() if log is not None: return log.info(msg, category) return 0 def warning(msg: str, category: str = "") -> int: """输出 WARN 级别日志。""" log: Logger | t.CPtr = get_logger() if log is not None: return log.warning(msg, category) return 0 def error(msg: str, category: str = "") -> int: """输出 ERROR 级别日志并立即终止进程。""" log: Logger | t.CPtr = get_logger() if log is not None: return log.error(msg, category) # logger 不可用时也直接退出 sys.exit(1) return 0 def success(msg: str, category: str = "") -> int: """输出 SUCCESS 级别日志。""" log: Logger | t.CPtr = get_logger() if log is not None: return log.success(msg, category) return 0 def critical(msg: str, category: str = "") -> int: """输出 CRITICAL 级别日志(致命错误,红底白字)。""" log: Logger | t.CPtr = get_logger() if log is not None: return log.critical(msg, category) return 0 def debug(msg: str, category: str = "") -> int: """输出 DEBUG 级别日志。""" log: Logger | t.CPtr = get_logger() if log is not None: return log.debug(msg, category) return 0