- 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:合并续行
276 lines
11 KiB
Plaintext
276 lines
11 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 - 原生日志系统(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
|