Files
ViperC/App/lib/core/VLogger.vp
T
TermiNexus f3c708613f refactor(TransPyV): 统一自举写法(字段默认值/novirtual/define/enum/指针注解)
- CallGenBase:字段声明处直接给默认值,InitCallGen 不再逐字段赋值
- CallGenFd/CallGenDispatch:@t.NoVTable 改 novirtual,清理过时注释
- VLogger:LogLevel 改 enum、t.CDefine 改 define 关键字、Logger|t.CPtr 改 Logger*、longjmp 用 rawptr
- Generator:_g_gen 由 Generator|t.CPtr 改为 Generator*
- CallGenProp:合并续行
2026-09-30 19:09:22 +08:00

276 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 控制台彩色输出)
# 输出格式: ├ LEVEL: message / ├ LEVEL[category]: message(与 TPC lib/core/VLogger.py 对齐)
# ============================================================
# 错误恢复(REPL/JIT 模式):error 打印后 longjmp 跳回 REPL 的 setjmp 点。
# mingw-w64 x86_64:longjmp 原型为 void longjmp(jmp_buf, int);setjmp 宏展开为
# _setjmp(buf, NULL)(jmp_buf 实为 _JBTYPE[16],见 Repl.vp 的 _REPL_JMPBUF_SIZE)。
extern def longjmp(buf: rawptr, val: int)
# REPL 恢复点指针(由 Repl 在会话开始时注册、会话结束时清除)。
# 生命周期 = 整个 REPL 会话:Repl 每轮片段都会重新武装(Repl.run 每轮 _setjmp +
# Repl.ReplExecFragment 入口重注册),故它覆盖整条片段流水线(翻译 → 写 .ll →
# llc → clang++ → LoadLibrary → GetProcAddress → 调用 → 回显),而不只是翻译期。
# 批处理路径从不调用 set_repl_jmpbuf ⇒ 恒为 None ⇒ 所有出口退回 sys.exit(1)。
_repl_jmpbuf: rawptr = None
# ============================================================
# repl_abort - TPV 内"诊断后终止"的唯一出口
#
# 约定:调用方**已打印**诊断(Traceback / VLogger.error / [OOM] 等),本函数只决定
# "跳回 REPL 继续"还是"终止进程":
# * REPL 会话(_repl_jmpbuf 已注册):fflush 后 longjmp 回 Repl.run 的恢复点,
# 进程存活、提示符继续(宽容 Traceback);
# * 批处理 / 未武装:sys.exit(1),与改动前的 fail-fast 行为逐字一致。
# 收敛点:Logger.error、模块级 error、TypeGenErr.fatal_error、
# ImportsGenMixin._report_import_error、CallGenBase/VpiReader 的链表哨兵。
# ============================================================
def repl_abort() -> int:
"""诊断后的统一出口:已注册恢复点则 longjmp 回 REPL,否则终止进程。"""
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:
"""注册 REPL 的 jmp_buf(会话开始;每片段入口可幂等重注册)。"""
global _repl_jmpbuf
_repl_jmpbuf = buf
return 0
def clear_repl_jmpbuf() -> int:
"""清除已注册的 jmp_buf(REPL 会话结束时调用;中途不清)。"""
global _repl_jmpbuf
_repl_jmpbuf = None
return 0
# 日志级别
enum LogLevel:
DEBUG, INFO, WARNING, ERROR, SUCCESS, CRITICAL
# Win32 控制台前景色属性
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 控制台背景色属性
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 - 核心日志输出(分段着色:前缀符号 ├ / LEVEL 标签 / 消息内容)
# 格式: ├ LEVEL: msg 或 ├ 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:
# 前缀符号着色
self._set_color(sym_color)
stdio.printf("%s ", prefix_sym)
# LEVEL 标签着色
self._set_color(level_color)
stdio.printf("%s", level_str)
self._reset_color()
# 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 模式:诊断已打印,经统一出口跳回 REPL 循环(未武装时该出口仍终止进程)
if self.jit_flag:
repl_abort()
return ret
# 批处理模式:错误立即终止进程(行为与改动前逐字一致)
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 set_jit_flag(self, v: bool) -> int:
"""设置 JIT/REPL 模式标志:True 时 error 改为 longjmp 回 REPL 循环。"""
self.jit_flag = v
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.MemBuddy*
# 全局 logger 指针
logger: Logger*
log: Logger*
def init_logger():
"""初始化全局 logger 实例。"""
global logger, log
raw: t.CPtr = _mbuddy.alloc(Logger.__sizeof__())
# if raw is None: return None 存疑,如何去管理内存?
logger = raw
logger.__before_init__()
logger.__init__(LogLevel.INFO)
log = logger
# if fmtbuffer is None: return None
# ============================================================
# --nowarn-register 开关:抑制 Phase A 依赖类 WARN 输出(仅抑制输出,不影响内部逻辑)
# ============================================================
_nowarn_register: int = 0
# ============================================================
# 模块级便捷函数(与 TPC 的 lib.core.VLogger 对齐,无需先 get_logger())
# ============================================================
def info(msg: str, category: str = "") -> int:
"""输出 INFO 级别日志。"""
if log is not None: return log.info(msg, category)
return 0
def warning(msg: str, category: str = "") -> int:
"""输出 WARN 级别日志。"""
if log is not None: return log.warning(msg, category)
return 0
def error(msg: str, category: str = "") -> int:
"""输出 ERROR 级别日志:批处理模式终止进程;JIT/REPL 模式 longjmp 回 REPL。"""
if log is not None: return log.error(msg, category)
# logger 不可用时也走统一出口(REPL 已注册恢复点时仍可恢复)
repl_abort()
return 0
def success(msg: str, category: str = "") -> int:
"""输出 SUCCESS 级别日志。"""
if log is not None: return log.success(msg, category)
return 0
def critical(msg: str, category: str = "") -> int:
"""输出 CRITICAL 级别日志(致命错误,红底白字)。"""
if log is not None: return log.critical(msg, category)
return 0
def debug(msg: str, category: str = "") -> int:
"""输出 DEBUG 级别日志。"""
if log is not None: return log.debug(msg, category)
return 0