"""内置符文集合。 对齐酒馆核心子集(``char`` / ``user`` / ``original`` / ``random`` / ``roll`` / ``getvar``)+ 魂镜扩展(辰正时态宏,复用 ``time_sense.TemporalSnapshot``)。 全部为纯函数解析器,不做 IO 或代码执行。 注:酒馆的 ``pick``(不重复随机)与 ``setvar``(写变量)需要跨调用状态, 不在无状态渲染层实现;如需,由调用方在 ``MacroContext.variables`` 维护后注入。 """ from __future__ import annotations import random import re from app.modules.macros.engine import MacroRegistry, MacroResolver from app.modules.macros.types import MacroContext def _char(_args: list[str], ctx: MacroContext) -> str: return ctx.char_name or "" def _user(_args: list[str], ctx: MacroContext) -> str: return ctx.user_name or "" def _original(_args: list[str], ctx: MacroContext) -> str: return ctx.original or "" def _random(args: list[str], _ctx: MacroContext) -> str: if not args: return "" return random.choice(args) def _roll(args: list[str], _ctx: MacroContext) -> str: """``{{roll:NdM}}`` 或 ``{{roll:dM}}`` → N 个 M 面骰求和。非法规格原样返回。""" spec = (args[0] if args else "1d6").strip().casefold() match = re.fullmatch(r"(?P\d*)d(?P\d+)", spec) if match is None: return spec count = int(match.group("n") or 1) sides = int(match.group("sides")) if count < 1 or sides < 1: return spec return str(sum(random.randint(1, sides) for _ in range(count))) def _getvar(args: list[str], ctx: MacroContext) -> str: return ctx.variables.get(args[0], "") if args else "" def _snapshot_field(field: str) -> MacroResolver: """从辰正快照取字段;快照未注入时返回空串。""" def _resolve(_args: list[str], ctx: MacroContext) -> str: snap = ctx.snapshot if snap is None: return "" value = getattr(snap, field, None) return "" if value is None else str(value) return _resolve # 辰正时态宏名 → TemporalSnapshot 字段(魂镜扩展) _TIME_MACROS: tuple[tuple[str, str], ...] = ( ("date", "solar_date"), ("time", "local_time"), ("day_period", "day_period"), ("shichen", "shichen"), ("season", "season"), ("solar_term", "solar_term"), ("weekday", "weekday"), ) def build_default_registry() -> MacroRegistry: """构造默认符文注册表。""" reg = MacroRegistry() reg.register("char", _char) reg.register("bot", _char) # 酒馆别名 reg.register("user", _user) reg.register("original", _original) reg.register("random", _random) reg.register("roll", _roll) reg.register("getvar", _getvar) for name, field in _TIME_MACROS: reg.register(name, _snapshot_field(field)) return reg