Files
ViperC/App/lib/core/Gen/VarGenMixin.vp
T
TermiNexus c2d7480f3d fix(transpyv): 槽视图统一 cast 到声明类型(47 处,含 codegen 自身)
同 includes 的同类修正:把一级指针 i8* 隐式塞进二级注解(i8** / str*)。
TransPyV 侧 coerce(ExprGenBase._ptr_cast_reason)没有 TPC 那样的「值侧是显式
指针 cast ⇒ 按 bitcast 重解释」豁免,故一旦用新构建的 TransPyV 编到这些文件
必然 fail-fast(回归测试首爆点在 includes/llvmlite 侧,本仓同形态站点随后必然
同样触发)。

涉及的两种形态:
  · `slot: str | t.CPtr = (t.CPtr)(addr)`   —— cast 目标是一级 t.CPtr
  · `nm_slot: str* = (t.CPtr)(addr)`        —— 注解 str* 即 i8**
统一改为 cast 到声明类型:`(str | t.CPtr)(addr)` / `str*(addr)`(后者与
includes/sys.vp `argv_arr: str* = str*(...)` 同一写法)。

本仓 47 处 / 6 文件:
  App/lib/core/Gen/VarGenMixin.vp 3
  App/lib/core/Gen/TranslatorGenMixin.vp 8
  App/lib/core/Gen/Func/FuncGenMixin.vp 13
  App/lib/core/Gen/AsyncGenMixin.vp 15
  App/lib/core/Gen/DebugInfoGen.vp 6
  App/lib/Stub/StubGen/Converter.vp 2
Converter.vp:107 的 `_g_pyi_cdef_names: str | t.CPtr = None` 保持原样
(None 即空指针,任何指针类型均可,不属本类问题)。

只提交本 6 个文件;本仓其余未提交改动(CallGenBase/CallGenDispatch/CallGenFd/
CallGenProp/Generator/Translator/VLogger)与本迁移无关,保持不动。
2026-09-29 15:10:33 +08:00

1627 lines
83 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 lib.core.Gen.GenTypes as GenTypes
import lib.core.Gen.Generator as Generator
import lib.core.Gen.Type.TypeSpec as TSpec
from MatchGenMixin import SCOPE_MATCH
import lib.core.Gen.Translator as HT
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdlib
# ============================================================
# VarGenMixin - 变量/作用域符号表 Mixin
# ============================================================
# ============================================================
# 常量(作用域类型;容量常量经 HT. 引用,见下)
# ============================================================
# 作用域类型常量
define SCOPE_MODULE = 0
define SCOPE_FUNCTION = 1
define SCOPE_BLOCK = 2
# 每个作用域最大变量数:唯一真源在 Translator.vp,本文件一律写 HT.MAX_VARS
# ============================================================
# VarGenMixin - 变量/作用域符号表 Mixin
# ============================================================
novirtual class VarGenMixin:
"""变量/作用域 Mixin"""
# ============================================================
# init_vars — 分配并清零 VarEntry 数组
# ============================================================
Gen: Generator.Generator*
def init_vars(self, pool: memhub.MemBuddy*) -> GenTypes.VarEntry*:
"""分配并清零变量表数组"""
size: sizet = HT.MAX_VARS * GenTypes.VarEntry.__sizeof__()
vars_ptr: GenTypes.VarEntry* = pool.alloc(size)
if vars_ptr is not None: string.memset(vars_ptr, 0, size)
return vars_ptr
# ============================================================
# find_var — 在变量表中按名称查找
# ============================================================
def find_var(self, vars_ptr: GenTypes.VarEntry*,
var_count: int,
name: str) -> llvmlite.Value*:
"""在变量表中按名称查找"""
if name is None or vars_ptr is None:
return None
entry_size: sizet = GenTypes.VarEntry.__sizeof__()
for i in range(var_count):
entry_addr: uint64 = uint64(vars_ptr) + i * entry_size
entry: GenTypes.VarEntry* = GenTypes.VarEntry*(entry_addr)
if entry.Name is not None and entry.Used != 0:
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
return entry.Alloca
return None
# ============================================================
# find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy)
# ============================================================
def find_var_entry(self, vars_ptr: GenTypes.VarEntry*,
var_count: int,
name: str) -> GenTypes.VarEntry*:
"""在变量表中按名称查找,返回 VarEntry 或 None"""
if name is None or vars_ptr is None:
return None
entry_size: sizet = GenTypes.VarEntry.__sizeof__()
for i in range(var_count):
entry_addr: uint64 = uint64(vars_ptr) + i * entry_size
entry: GenTypes.VarEntry* = GenTypes.VarEntry*(entry_addr)
if entry.Name is not None and entry.Used != 0:
if string.strcmp(entry.Name, name) == 0:
return entry
return None
# ============================================================
# lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry
# ============================================================
def lookup_var_entry(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> GenTypes.VarEntry*:
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None"""
if symtab is None or name is None:
return None
scope: rawptr[GenTypes.Scope] = symtab.Current
while scope is not None:
result: GenTypes.VarEntry* = self.find_var_entry(scope.Vars, scope.VarCount, name)
if result is not None:
return result
scope = scope.Parent
return None
# ============================================================
# set_var_annot_class_name — 设置变量的原始类型注解类名
#
# 在函数参数定义后调用,存储原始类型注解的类名(Spec.SourceName)。
# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化),
# 通过 Spec.SourceName 查找实际结构体类型。
# ============================================================
def set_var_annot_class_name(self, symtab: rawptr[GenTypes.SymbolTable],
name: str,
class_name: str) -> int:
"""设置变量的原始类型注解类名(写入 Spec.SourceName),返回 0=成功 / 1=失败
[S4] 原 VarEntry.AnnotClassName 字段已删除,注解名统一承载在 Spec.SourceName:
- 整数符号性:SpecFromLLVMType 反推恒 TS_INT(LLVM iN 不分符号),
注解名携带真实无符号性(uint32/CUInt32T 等)→ 切 TS_INT→TS_UINT;
- 来源名:`X | t.CPtr` 简化为 Ptr(i8) 后 Spec 里没有类名,附上供
属性访问/方法分派恢复(消费点经 var_annot_class_name 读取)。
类型信息缺失(SpecFromLLVMType 不适用致 Spec 为 None)时建 TS_UNKNOWN
承载注解名 —— TS_UNKNOWN 不表态任何具体类型,等价于原来的"Spec 缺失"。
"""
if symtab is None or name is None:
return 1
entry: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
if class_name is None:
# 无注解名:不写入(VarEntry 槽位不复用,原值恒为 None,与清空等价)。
return 0
arena_sn: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
if arena_sn is None:
return 1
if entry.Spec is None:
entry.Spec = TSpec.NewTypeSpec(arena_sn, TSpec.TS_UNKNOWN, 0,
TSpec.TS_SIGN_UNKNOWN)
if entry.Spec is None:
return 1
sign: int = self.Gen.TypeGenCType.spec_sign_of_annot(class_name)
if sign != TSpec.TS_SIGN_UNKNOWN:
entry.Spec = TSpec.SpecWithSign(arena_sn, entry.Spec, sign)
entry.Spec = TSpec.SpecWithSource(entry.Spec, class_name)
return 0
# ============================================================
# var_annot_class_name - 变量条目注解类名的统一读取入口(S4 切读·类名块)
#
# 注解侧由 set_var_annot_class_name 经 SpecWithSource 写入 Spec.SourceName。
# 变量侧类名恢复读取点统一走此入口。
# ============================================================
def var_annot_class_name(self, entry: GenTypes.VarEntry*) -> str:
"""变量条目注解类名(Spec.SourceName);未设置返回 None"""
if entry is None:
return None
return TSpec.SpecSourceName(entry.Spec)
# set_var_ptr_element — 标记变量为「指针元素(ptr-element)」语义
# 注解为 bytes|t.CPtr / str|t.CPtr / T|t.CPtr / 64位标量|t.CPtr 的变量,其
# LLVM 类型退化为 i8*(Ptr(Int8)),但下标访问应按 8 字节槽步长(i8** 语义),
# 而非 1 字节步长(i8* 语义)。
# 该语义由 Spec.ElemBits 承载:上述四类在 LLVM 层都是 Ptr(Int8)(ElemBits=8,
# 无法区分),故注解侧把元素槽宽覆盖为 8 字节,消费点经 var_is_ptr_element 读取。
# 由 AnnAssign 按注解形式(_is_ptr_element_annotation)调用。
def set_var_ptr_element(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> int:
"""标记变量为 ptr-element(Spec.ElemBits=64),返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
# ptr-element 变量的 alloca 是 Ptr(Ptr(Int8)),其值类型 Ptr(Int8) ⇒ Spec 必为
# PtrLevel>=1。不满足即上游异常(类型缺失/退化),fail-fast 暴露 ——
# 若静默放过,读点 var_is_ptr_element 返回 0 → 下标按 1 字节误算(数据损坏)。
if entry.Spec is None or entry.Spec.PtrLevel < 1:
self.Gen.TypeGenErr.fatal_error(None, f"变量 '{name}' 标记为 ptr-element,但其 Spec 不可承载指针语义", "InternalCompilerError")
return 1
entry.Spec = TSpec.SpecWithElemBits(entry.Spec, 64)
return 0
# var_is_ptr_element - 变量是否「指针元素」语义(Spec.ElemBits 承载)
# 判据:PtrLevel>=1 且元素位宽为 8(LLVM 层退化后的 i8*)且 ElemBits==64
# (注解侧覆盖的 8 字节槽)。后两个条件缺一不可:真实 i64* 变量 ElemBits 也为 64
# 但 Elem.Bits=64,不命中;纯 str/bytes/char|t.CPtr 变量 ElemBits=8,同样不命中。
def var_is_ptr_element(self, entry: GenTypes.VarEntry*) -> int:
"""变量是否为 ptr-element 语义(1=是 / 0=否)"""
if entry is None or entry.Spec is None:
return 0
sp: TSpec.TypeSpec* = entry.Spec
if sp.PtrLevel < 1 or sp.Elem is None:
return 0
if sp.Elem.Bits != 8:
return 0
if sp.ElemBits == 64:
return 1
return 0
# set_var_volatile — 标记变量为 volatile(注解联合含 t.CVolatile)
# 语义对齐 C 的 volatile 限定:该变量的每次 load/store 都带 LLVM volatile,
# 禁止优化器把忙等循环中的重复 load 提升/消除。由注解侧
# (模块级已注册后 / 局部声明时)调用。
def set_var_volatile(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> int:
"""标记变量为 volatile(VarEntry.IsVolatile=1),返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.IsVolatile = 1
return 0
# var_is_volatile — 变量是否 volatile(读路径/写路径统一入口)
def var_is_volatile(self, entry: GenTypes.VarEntry*) -> int:
"""变量条目是否 volatile(1=是 / 0=否;entry 为 None 时 0)"""
if entry is None:
return 0
return entry.IsVolatile
# set_var_pointee_volatile — 标记"指针所指物"为 volatile
# (变量注解为 rawptr[t.CVolatile | T],等价 C 的 volatile T*)。
# 语义对齐 C 的 volatile 限定(作用于 pointee 而非指针自身):解引用
# (p[i] / p.field / c.Deref(p))的每次 load/store 都带 LLVM volatile,
# 禁止优化器重排序/消除对所指对象的访问。由注解侧在登记变量时调用。
def set_var_pointee_volatile(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> int:
"""标记变量所指物为 volatile(VarEntry.PointeeVolatile=1),返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.PointeeVolatile = 1
return 0
# var_pointee_is_volatile — 变量所指物是否 volatile(解引用读写统一入口)
def var_pointee_is_volatile(self, entry: GenTypes.VarEntry*) -> int:
"""变量条目所指物是否 volatile(1=是 / 0=否;entry 为 None 时 0)"""
if entry is None:
return 0
return entry.PointeeVolatile
# set_var_const — 标记变量为 const 对象(注解含 t.CConst 且类型非指针)
# 语义:与 TPC 的 Gen.var_const_flags / global_const_flags 同判据、同报文
# (见 Debugger/type-descriptors.md「两侧语义对照表」)。整个作用域内禁止对
# 该变量名赋值 / 增量赋值 / 元素赋值;由注解侧(模块级已注册后 / 局部声明时 /
# 形参声明时)调用。
def set_var_const(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> int:
"""标记变量为 const 对象(VarEntry.IsConst=1),返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.IsConst = 1
return 0
# var_is_const — 变量是否 const 对象(赋值/增量赋值/元素赋值拦截面统一入口)
def var_is_const(self, entry: GenTypes.VarEntry*) -> int:
"""变量条目是否 const 对象(1=是 / 0=否;entry 为 None 时 0)"""
if entry is None:
return 0
return entry.IsConst
# ============================================================
# add_var — 添加变量到变量表
# ============================================================
def add_var(self, vars_ptr: GenTypes.VarEntry*,
var_count: int,
name: str,
alloca: llvmlite.Value*) -> int:
"""添加变量到变量表"""
if name is None or alloca is None or vars_ptr is None:
return 1
if var_count >= HT.MAX_VARS:
return 1
entry_size: sizet = GenTypes.VarEntry.__sizeof__()
entry_addr: uint64 = uint64(vars_ptr) + var_count * entry_size
entry: GenTypes.VarEntry* = GenTypes.VarEntry*(entry_addr)
# 变量名必须深拷贝到 stdlib(跨 pool reset 存活):entry.Name 直接存 AST
# 节点 Name.id 指针时,该段内存被后续分配覆盖会使 find_var 的 strcmp 静默
# 失配 → Handle 阶段找不到 PreScan 已建的同名 alloca → 另建类型退化的
# alloca(随后 .get 等按错误元素类型分派)。深拷贝后符号表条目不再依赖
# AST tree 生命周期。
name_len: sizet = string.strlen(name)
name_copy: bytes = stdlib.malloc(name_len + 1)
if name_copy is None:
return 1
string.strcpy(name_copy, name)
entry.Name = name_copy
entry.Alloca = alloca
entry.Used = 1
# const 标记显式置 0(不依赖条目内存的零初值约定):由注解侧
# set_var_const 在确认为 const 对象时才置 1,显式清零杜绝误报。
entry.IsConst = 0
# [S3 条目双写] 值类型 Spec(alloca.Ty 是 Ptr(值类型) ⇒ 取其 pointee)
entry.Spec = self._spec_of_var_alloca(alloca)
return 0
# ============================================================
# _spec_of_var_alloca - 由 alloca 的值类型构造 TypeSpec(S3 条目双写)
#
# alloca.Ty 为 Ptr(var_ty)(见 _alloca_at_entry / 全局变量 SSAValue 路径),
# 故取 pointee 才是变量的**值类型**。失败或类型不适用(Label/Metadata 等
# SpecFromLLVMType 不支持者)返回 None —— 后者是设计内的「不适用」,非兜底。
# 分配一律 PermPool 驻留 ⇒ 跨文件/跨 1b reset 安全。
# ============================================================
def _spec_of_var_alloca(self, alloca: llvmlite.Value*) -> TSpec.TypeSpec*:
"""由 alloca 的值类型构造 TypeSpec,不适用/失败返回 None"""
if alloca is None or alloca.Ty is None:
return None
ty: llvmlite.LLVMType* = alloca.Ty
if self.Gen.ExprGenBase.is_ptr_type(ty) != 0:
ty = ty.Pointee
arena: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
if arena is None:
return None
return TSpec.SpecFromLLVMType(arena, ty)
# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性)
# LLVM IR 要求指令支配所有使用点,故所有 alloca 须在函数入口块生成。
# 实现:临时切换 builder.CurBlock 到入口块,生成 alloca 后恢复。
def _alloca_at_entry(self, builder: llvmlite.IRBuilder*,
ty: llvmlite.LLVMType*) -> llvmlite.Value*:
"""在函数入口块生成 alloca,返回 alloca 值
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca,
确保所有 alloca 在入口块,避免支配性违规。
"""
if builder is None or ty is None:
return None
return llvmlite.build_alloca_at_entry(builder, ty)
# get_or_create_var — 查找或创建变量 alloca(旧版兼容)
def get_or_create_var(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
vars_ptr: GenTypes.VarEntry*,
var_count: int,
name: str,
ty: llvmlite.LLVMType*) -> llvmlite.Value*:
"""查找或创建变量 alloca"""
existing: llvmlite.Value* = self.find_var(vars_ptr, var_count, name)
if existing is not None:
return existing
alloca: llvmlite.Value* = self._alloca_at_entry(builder, ty)
if alloca is None:
return None
if self.add_var(vars_ptr, var_count, name, alloca) != 0:
return None
return alloca
# ============================================================
# _create_scope — 创建新作用域节点(内部辅助函数)
# ============================================================
def _create_scope(self, pool: memhub.MemBuddy*,
parent: rawptr[GenTypes.Scope],
kind: int) -> rawptr[GenTypes.Scope]:
"""创建并初始化作用域节点"""
scope: rawptr[GenTypes.Scope] = pool.alloc(GenTypes.Scope.__sizeof__())
if scope is None:
return None
string.memset(scope, 0, GenTypes.Scope.__sizeof__())
scope.Parent = parent
scope.Vars = self.init_vars(pool)
scope.VarCount = 0
scope.Kind = kind
if scope.Vars is None:
return None
return scope
# ============================================================
# init_symbol_table — 创建符号表(含模块级根作用域)
# ============================================================
def init_symbol_table(self, pool: memhub.MemBuddy*) -> rawptr[GenTypes.SymbolTable]:
"""创建并初始化符号表,包含模块级根作用域"""
if pool is None:
return None
symtab: rawptr[GenTypes.SymbolTable] = pool.alloc(GenTypes.SymbolTable.__sizeof__())
if symtab is None:
return None
string.memset(symtab, 0, GenTypes.SymbolTable.__sizeof__())
symtab.Pool = pool
# 创建根作用域(模块级)
root: rawptr[GenTypes.Scope] = self._create_scope(pool, None, SCOPE_MODULE)
if root is None:
return None
symtab.Root = root
symtab.Current = root
return symtab
# ============================================================
# enter_scope — 进入新作用域
# ============================================================
def enter_scope(self, symtab: rawptr[GenTypes.SymbolTable],
kind: int) -> rawptr[GenTypes.Scope]:
"""进入新作用域,返回新创建的作用域"""
if symtab is None:
return None
pool: memhub.MemBuddy* = symtab.Pool
scope: rawptr[GenTypes.Scope] = self._create_scope(pool, symtab.Current, kind)
if scope is None:
return None
symtab.Current = scope
return scope
# ============================================================
# exit_scope — 退出当前作用域
# ============================================================
def exit_scope(self, symtab: rawptr[GenTypes.SymbolTable]):
"""退出当前作用域,恢复到父作用域"""
if symtab is not None and symtab.Current is not None:
symtab.Current = symtab.Current.Parent
# ============================================================
# define_var — 在当前作用域定义变量
# ============================================================
def define_var(self, symtab: rawptr[GenTypes.SymbolTable],
name: str,
alloca: llvmlite.Value*) -> int:
"""在当前作用域定义变量,返回 0 成功"""
if symtab is None or name is None or alloca is None:
return 1
scope: rawptr[GenTypes.Scope] = symtab.Current
if scope is None:
return 1
ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca)
if ret == 0:
scope.VarCount = scope.VarCount + 1
return ret
# ============================================================
# define_module_var — 在模块作用域定义变量
# ============================================================
def define_module_var(self, symtab: rawptr[GenTypes.SymbolTable],
name: str,
alloca: llvmlite.Value*) -> int:
"""在模块作用域定义变量,返回 0 成功"""
if symtab is None or name is None or alloca is None:
return 1
scope: rawptr[GenTypes.Scope] = symtab.Root
if scope is None:
return 1
ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca)
if ret == 0:
scope.VarCount = scope.VarCount + 1
return ret
# ============================================================
# lookup_var — 从当前作用域逐级向上查找变量
# ============================================================
def lookup_var(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> llvmlite.Value*:
"""从当前作用域逐级向上查找变量,返回 alloca 或 None"""
if symtab is None or name is None:
return None
scope: rawptr[GenTypes.Scope] = symtab.Current
while scope is not None:
result: llvmlite.Value* = self.find_var(scope.Vars, scope.VarCount, name)
if result is not None:
return result
scope = scope.Parent
return None
# ============================================================
# lookup_current — 仅在当前作用域查找变量
# ============================================================
def lookup_current(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> llvmlite.Value*:
"""仅在当前作用域查找变量"""
if symtab is None or name is None:
return None
scope: rawptr[GenTypes.Scope] = symtab.Current
if scope is None:
return None
return self.find_var(scope.Vars, scope.VarCount, name)
# ============================================================
# lookup_module_var — 在模块作用域查找变量
# ============================================================
def lookup_module_var(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> llvmlite.Value*:
"""在模块作用域查找变量"""
if symtab is None or name is None:
return None
scope: rawptr[GenTypes.Scope] = symtab.Root
if scope is None:
return None
return self.find_var(scope.Vars, scope.VarCount, name)
# ============================================================
# is_module_scope - 判断当前是否在模块级作用域
#
# 用于区分模块级代码和函数内代码:
# - 模块级代码:AnnAssign 应修改模块级变量(Python 语义)
# - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义)
# ============================================================
def is_module_scope(self, symtab: rawptr[GenTypes.SymbolTable]) -> int:
"""判断当前作用域是否为模块级作用域(Current == Root)
Returns: 1=模块级作用域, 0=函数内作用域
"""
if symtab is None:
return 0
if symtab.Root is None or symtab.Current is None:
return 0
# 比较指针:Current 与 Root 相同则为模块级
if uint64(symtab.Current) == uint64(symtab.Root):
return 1
return 0
# _lookup_through_match_scope — 穿越 match case 作用域查找变量
def _lookup_through_match_scope(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> llvmlite.Value*:
"""从当前作用域向上,仅穿越 SCOPE_MATCH 作用域查找变量 alloca"""
if symtab is None or name is None:
return None
scope: rawptr[GenTypes.Scope] = symtab.Current
while scope is not None:
result: llvmlite.Value* = self.find_var(scope.Vars, scope.VarCount, name)
if result is not None:
return result
if scope.Kind == SCOPE_MATCH:
scope = scope.Parent
continue
return None
return None
# ============================================================
# get_or_create_sym — 查找或创建变量(在当前作用域)
# ============================================================
def get_or_create_sym(self, symtab: rawptr[GenTypes.SymbolTable],
pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
name: str,
ty: llvmlite.LLVMType*) -> llvmlite.Value*:
"""查找或创建变量 alloca(在当前作用域)"""
existing: llvmlite.Value* = self.lookup_current(symtab, name)
if existing is not None:
return existing
# SCOPE_MATCH 隔离作用域对"赋值"必须透明:
existing = self._lookup_through_match_scope(symtab, name)
if existing is not None:
return existing
alloca: llvmlite.Value* = self._alloca_at_entry(builder, ty)
if alloca is None:
return None
if self.define_var(symtab, name, alloca) != 0:
self.Gen.TypeGenErr.fatal_error(None, f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)", "InternalCompilerError")
return alloca
# ============================================================
# REPL 模式(M2)—— 会话变量槽位读写
#
# 前置:trans.ReplCtx != None(仅 Repl.vp 翻译片段前置位、翻译后清空)。
# 下面所有函数都只被带该守卫的调用点进入 ⇒ 普通编译路径不经过任何一行。
#
# ctx 布局(详见 GenTypes 顶部注释):片段函数首形参是 ctx(i8*,注解 bytes),
# 会话变量 x 的槽位于 ctx + x.Offset(= REPL_SLOT_BASE + i*REPL_SLOT_SIZE)。
# 槽内存放的是**值本身**(标量/指针/≤16B 结构体值内联)⇒ 宿主不需要知道类型,
# 且槽地址即值地址(c.Addr 的地址同一性)。
# ============================================================
# ---- repl_find_entry — 会话表按名查找 ----
def repl_find_entry(self, ctx: rawptr[GenTypes.ReplCtx], name: str) -> rawptr[GenTypes.ReplVarEntry]:
"""在会话表中按名查找条目;ctx 无效或未登记返回 None"""
if ctx is None or name is None:
return None
# 魔数校验:防止把非 ReplCtx 的指针当上下文用(宁可不拦截也不乱拦截)
if ctx.Marker != GenTypes.REPL_CTX_MARKER:
return None
if ctx.Table is None or ctx.Count <= 0:
return None
entry_size: sizet = GenTypes.ReplVarEntry.__sizeof__()
for i in range(ctx.Count):
entry_addr: uint64 = uint64(ctx.Table) + i * entry_size
entry: rawptr[GenTypes.ReplVarEntry] = rawptr[GenTypes.ReplVarEntry](entry_addr)
if entry.Name is not None and string.strcmp(entry.Name, name) == 0:
return entry
return None
# ---- repl_in_frag_scope — 当前最近函数作用域是否就是片段函数本体 ----
def repl_in_frag_scope(self, symtab: rawptr[GenTypes.SymbolTable]) -> int:
"""1=当前最近函数作用域即片段函数本体(其父为模块根);0=其他
拦截只在片段函数本体生效:片段自己声明的局部名/参数、片段内嵌套函数体
(其函数作用域的父不是模块根)一律走原路径。if/while 分支不建新作用域,
故分支内的赋值同样命中(整行片段语义)。
"""
if symtab is None or symtab.Current is None or symtab.Root is None:
return 0
scope: rawptr[GenTypes.Scope] = symtab.Current
while scope is not None:
if scope.Kind == SCOPE_FUNCTION:
if scope.Parent is not None and uint64(scope.Parent) == uint64(symtab.Root):
return 1
return 0
scope = scope.Parent
return 0
# ---- repl_ctx_ptr — 取片段函数 ctx 形参的值(i8*) ----
def repl_ctx_ptr(self, trans: HT.Translator*,
ctx: rawptr[GenTypes.ReplCtx],
node: ast.AST*) -> llvmlite.Value*:
"""load 片段函数 ctx 形参(形参 alloca 由 FuncGenDef 建);失败 fail-fast"""
if trans is None or ctx is None or ctx.CtxParam is None:
return None
symtab: rawptr[GenTypes.SymbolTable] = trans.SymTab
param_alloca: llvmlite.Value* = self.lookup_var(symtab, ctx.CtxParam)
if param_alloca is None or param_alloca.Ty is None or param_alloca.Ty.Pointee == 0:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 片段函数缺少 ctx 形参 '{ctx.CtxParam}'(包裹模板与 M2 调用约定不一致)", "InternalCompilerError")
return None
return llvmlite.build_load(trans._cur_builder, param_alloca.Ty.Pointee, param_alloca)
# ---- repl_in_frag_entry_scope — 当前最近函数作用域是否就是**片段入口**函数 ----
#
# 与 repl_in_frag_scope 的差别(M3 引入):被提升的会话函数(片段里顶层 def 提升
# 到模块级的 export def)在作用域上同样是"父为模块根的函数作用域",故
# repl_in_frag_scope 对其返回 1;但它**不是**片段入口函数。
# - 读路径(会话变量取值/取址/会话函数调用):两者都允许 ⇒ 用 repl_in_frag_scope
# (会话函数体里能读到会话变量,这是 M3 的核心能力);
# - 写路径(会话槽位分配/赋值/增强赋值/注解赋值):只允许片段入口函数 ⇒ 用本
# 谓词。理由(正确性,不是风格):
# ① 会话函数体里的 `y = 1` 应是**局部**变量(Python 语义),若走会话槽
# 会把局部名泄漏成全局、并使递归/重入共享同一槽;
# ② 形参同名遮蔽最危险:`x = 1` 建立会话变量 x 后,`def f(x: int): x = x + 1`
# 若走会话槽会把实参写进**会话变量 x**(静默数据串味);
# ③ 片段入口函数是唯一"用户一整行/一整块"的语义载体 ⇒ 与 M2 行为一致。
# 判定:片段入口函数名由宿主生成,恒以 GenTypes.REPL_ENTRY_PREFIX 开头
# (Repl.vp 的 "__repl_frag_%d")。非 REPL 路径 _cur_func 无该前缀 ⇒ 恒 0。
def repl_in_frag_entry_scope(self, trans: HT.Translator*) -> int:
"""1=当前正在翻译片段入口函数本体;0=其他(含被提升的会话函数本体)"""
if trans is None or trans._cur_func is None:
return 0
if self.repl_in_frag_scope(trans.SymTab) == 0:
return 0
cur_nm: str = llvmlite.function_get_name(trans._cur_func)
if cur_nm is None:
return 0
pfx: str = GenTypes.REPL_ENTRY_PREFIX
pl: sizet = string.strlen(pfx)
if string.strncmp(cur_nm, pfx, pl) != 0:
return 0
return 1
# ---- repl_find_func_entry — 会话函数表按名查找(M3) ----
def repl_find_func_entry(self, ctx: rawptr[GenTypes.ReplCtx],
name: str) -> rawptr[GenTypes.ReplFuncEntry]:
"""在会话函数表中按名查找;ctx 无效/未登记返回 None(只读,不改表)"""
if ctx is None or name is None:
return None
if ctx.Marker != GenTypes.REPL_CTX_MARKER:
return None
if ctx.FuncTable is None or ctx.FuncCount <= 0:
return None
entry_size: sizet = GenTypes.ReplFuncEntry.__sizeof__()
for i in range(ctx.FuncCount):
entry_addr: uint64 = uint64(ctx.FuncTable) + i * entry_size
entry: rawptr[GenTypes.ReplFuncEntry] = rawptr[GenTypes.ReplFuncEntry](entry_addr)
if entry.Name is not None and string.strcmp(entry.Name, name) == 0:
return entry
return None
# ---- repl_func_ty — 签名 token → LLVM 类型(M3) ----
#
# token 由宿主在注册期从定义片段的 IR define 行解析而来(唯一 ABI 真相),
# 只允许可往返重建的集合:iN(N=1/8/16/32/64) / float / double / i8*。
# 其余 token(含 REPL_TY_PTR / REPL_TY_STRUCT)返回 None ⇒ 调用点明确报错。
def repl_func_ty(self, pool: memhub.MemBuddy*,
tag: int, bits: int) -> llvmlite.LLVMType*:
"""签名 token → LLVM 类型;不支持的 token 返回 None"""
if pool is None:
return None
if tag == GenTypes.REPL_TY_INT:
return self.repl_scalar_ty(pool, bits, 0)
if tag == GenTypes.REPL_TY_FLOAT:
return self.repl_scalar_ty(pool, bits, 1)
if tag == GenTypes.REPL_TY_STR:
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
return None
# ---- repl_func_sig_label — 签名 token → 人类可读类型名(错误消息用) ----
def repl_func_sig_label(self, tag: int, bits: int) -> str:
"""签名 token → 显示名;未识别返回 "?"(VOID 显示为 void)"""
if tag == GenTypes.REPL_TY_VOID:
return "void"
return self.repl_tag_label(tag, bits)
# ---- repl_try_session_func_call — 会话函数间接调用(M3 核心) ----
#
# 命中(名字在会话函数表且当前在片段函数作用域内)时:
# ① 从 ctx 的函数指针槽(ctx + SlotOff,i8**)load 出函数地址(i8*);
# ② 首实参恒为本片段的 ctx(i8*)——被提升的会话函数首形参即 ctx,
# 其体内经该指针读写会话变量槽(与片段入口函数同一套寻址);
# ③ 其余实参与定义端签名逐个对齐(translate_value 带 target_ty + coerce_to_type);
# ④ 按表内签名(ret + (i8*, P1..Pn))bitcast 后 build_call_indirect。
# 语义要点:函数**代码**只在定义片段的 DLL 里存在一份,调用点不复制/不重编译;
# 表内签名即定义端 ABI(宿主从 define 行解析)⇒ 调用点签名与定义端恒一致。
#
# hit 是宿主调用方提供的 int 盒子(stdlib.malloc(4) 风格,与 translate_call 里
# h1_hit 同款):命中后(含命中但报错)置 1,使调用方"已处理"而不是继续走
# "裸名调用未定义且未导入"的 fail-fast 或搭上别的解析路径。
# 守卫:调用方只在 trans.ReplCtx is not None 时调用;非 REPL 恒不进入。
def repl_try_session_func_call(self, trans: HT.Translator*,
pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
func_name: str,
cargs: list[ast.AST*]*,
can: int,
kw_count: int,
node: ast.AST*,
hit: t.CPtr) -> llvmlite.Value*:
"""会话函数调用:命中返回 call 结果(void 函数返回 None 但 hit 已置 1)"""
if trans is None or trans.ReplCtx is None or pool is None or builder is None:
return None
if func_name is None or hit is None:
return None
ctx: rawptr[GenTypes.ReplCtx] = trans.ReplCtx
entry: rawptr[GenTypes.ReplFuncEntry] = self.repl_find_func_entry(ctx, func_name)
if entry is None:
return None
# 本判定与 M2 的读路径同口径:片段入口函数**或被提升的会话函数**体内允许
# 调用别的会话函数;片段内的嵌套闭包体(无 ctx 形参)不允许 ⇒ 返回未命中,
# 由既有路径给出明确报错(不生成非法 IR)。
if self.repl_in_frag_scope(trans.SymTab) == 0:
return None
hit[0] = 1
if kw_count != 0:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 不支持关键字实参(M3 仅支持位置实参)", "TypeError")
return None
if can != entry.ParamCount:
self.Gen.TypeGenErr.fatal_error( node, f"REPL: 会话函数 '{func_name}' 期待 {entry.ParamCount} 个位置实参,调用处给了 {can} 个(M3 不支持默认参数/缺省补全)", "TypeError")
return None
ctx_val: llvmlite.Value* = self.repl_ctx_ptr(trans, ctx, node)
if ctx_val is None:
return None
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
# ① 槽内取函数地址:槽地址是 i8**(Ptr(i8*)),load 得 i8*
slot: llvmlite.Value* = self.repl_slot_ptr(pool, builder, ctx_val, entry.SlotOff, i8_ptr_ty)
if slot is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话函数指针槽地址生成失败", "InternalCompilerError")
return None
fn_i8: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, slot)
if fn_i8 is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的地址读取失败", "InternalCompilerError")
return None
# ② 签名构造前先取形参类型(token → LLVM 类型;不支持 ⇒ 明确报错)
ptypes: t.CPtr = pool.alloc(8 * GenTypes.REPL_FUNC_PARAM_MAX)
if ptypes is None:
return None
string.memset(ptypes, 0, 8 * GenTypes.REPL_FUNC_PARAM_MAX)
ai_chk: int
for ai_chk in range(entry.ParamCount):
pty_chk: llvmlite.LLVMType* = self.repl_func_ty(pool, int(entry.ParamTags[ai_chk]), int(entry.ParamBits[ai_chk]))
if pty_chk is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 第 {ai_chk + 1} 个形参的类型 token 不受支持(M3 支持 iN/float/double/i8*)", "TypeError")
return None
pty_slot: str | t.CPtr = (str | t.CPtr)(uint64(ptypes) + ai_chk * 8)
pty_slot[0] = pty_chk
# ③ 实参:首实参 = 本片段 ctx,其后按签名类型逐个翻译并 coerce
head: llvmlite.Value* = ctx_val
head.Next = None
tail: llvmlite.Value* = head
arg_count: int = 1
ai: int
for ai in range(entry.ParamCount):
arg: ast.AST* = cargs.get(ai)
if arg is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参缺失", "SyntaxError")
return None
pty_slot2: str | t.CPtr = (str | t.CPtr)(uint64(ptypes) + ai * 8)
pty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(pty_slot2[0])
arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, pty)
if arg_val is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参翻译失败", "TypeError")
return None
coerced: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pty, arg, trans)
if coerced is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参与签名类型不兼容", "TypeError")
return None
coerced.Next = None
tail.Next = coerced
tail = coerced
arg_count += 1
# ④ 函数类型:ret + (i8*, P1..Pn)(ret=void 时用 llvmlite.Void,
# build_call_indirect 返回 None ⇒ 宿主调用方按"void 调用"处理)
ret_ty: llvmlite.LLVMType* = llvmlite.Void(pool)
if entry.RetTag != GenTypes.REPL_TY_VOID:
ret_ty = self.repl_func_ty(pool, entry.RetTag, entry.RetBits)
if ret_ty is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的返回类型 token 不受支持(M3 支持 void/iN/float/double/i8*)", "TypeError")
return None
# 形参链表节点是 llvmlite.ParamNode(new_param_node 返回 rawptr[ParamNode]、
# paramnode_set_next / Func 形参同为 rawptr[ParamNode])——原先误注解为 Function*。
fp_first: llvmlite.ParamNode* = None
fp_prev: llvmlite.ParamNode* = None
pi: int
for pi in range(arg_count):
cur_ty: llvmlite.LLVMType* = i8_ptr_ty
if pi > 0:
pty_slot3: str | t.CPtr = (str | t.CPtr)(uint64(ptypes) + (pi - 1) * 8)
cur_ty = (llvmlite.LLVMType*)(pty_slot3[0])
pn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, cur_ty)
if pn is not None:
if fp_first is None:
fp_first = pn
if fp_prev is not None:
llvmlite.paramnode_set_next(fp_prev, pn)
fp_prev = pn
func_ty: llvmlite.LLVMType* = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
if func_ty is None:
return None
func_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, func_ty)
fn_typed: llvmlite.Value* = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty)
if fn_typed is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的地址转换失败", "InternalCompilerError")
return None
return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty)
# ---- repl_slot_ptr — 槽地址(ctx + off 的字节 GEP 后 bitcast 成 Ptr(val_ty)) ----
def repl_slot_ptr(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
ctx_val: llvmlite.Value*,
off: int,
val_ty: llvmlite.LLVMType*) -> llvmlite.Value*:
"""返回槽指针(Ptr(val_ty));参数不完整返回 None
用 i8 步长 GEP 做纯字节偏移(同 list_getitem_inline 的既有做法),
再 bitcast 到目标类型指针——槽步长与负载类型解耦。
"""
if pool is None or builder is None or ctx_val is None or val_ty is None:
return None
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
target_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, val_ty)
off_val: llvmlite.Value* = llvmlite.const_int64(pool, t.CInt64T(off))
if off_val is None:
return None
base: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, ctx_val, off_val)
if base is None:
return None
# 同型时不发 bitcast:llvmlite 类型非 canonical(同类型不同实例地址不同),
# 而 LLVM 拒绝 `bitcast i8* %x to i8*`(同型 cast 非法)——val_ty 为 i8
# (char 会话变量)时目标恰是 i8*,必须直接返回 GEP 结果。
if base.Ty is not None and self.Gen.AssignGen._stg_ty_equal(pool, base.Ty, target_ptr_ty) != 0:
return base
return llvmlite.build_bitcast(builder, base, target_ptr_ty)
# ---- repl_scalar_ty — 位宽 → LLVM 标量类型 ----
def repl_scalar_ty(self, pool: memhub.MemBuddy*,
bits: int, is_float: int) -> llvmlite.LLVMType*:
"""按位宽还原 LLVM 标量类型;不支持的位宽返回 None"""
if is_float != 0:
if bits == 32:
return llvmlite.Float(pool)
if bits == 64:
return llvmlite.Double(pool)
return None
if bits == 1:
return llvmlite.Int1(pool)
if bits == 8:
return llvmlite.Int8(pool)
if bits == 16:
return llvmlite.Int16(pool)
if bits == 32:
return llvmlite.Int32(pool)
if bits == 64:
return llvmlite.Int64(pool)
return None
# ---- repl_llvm_ty — 条目 → LLVM 值类型(结构体按名重解析) ----
def repl_llvm_ty(self, pool: memhub.MemBuddy*,
entry: rawptr[GenTypes.ReplVarEntry]) -> llvmlite.LLVMType*:
"""条目反推 LLVM 值类型;未定型/结构体类型不可解析返回 None
TyTag=STRUCT 时返回结构体**值**类型(内联存槽,槽类型即它本身)。
结构体按 TyName 在当前片段重解析(类型对象不跨片段缓存——片段 pool 行末
即回收,缓存指针会悬垂);当前片段不可见该结构体时返回 None 由调用点
给明确消息(跨片段类型可见性属 M4)。
"""
if entry is None or pool is None:
return None
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
return None
if entry.TyTag == GenTypes.REPL_TY_INT:
return self.repl_scalar_ty(pool, entry.Bits, 0)
if entry.TyTag == GenTypes.REPL_TY_FLOAT:
return self.repl_scalar_ty(pool, entry.Bits, 1)
if entry.TyTag == GenTypes.REPL_TY_STR:
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if entry.TyTag == GenTypes.REPL_TY_PTR:
if entry.TyName is not None:
st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(entry.TyName)
if st is None:
return None
return llvmlite.Ptr(pool, st)
ptee: llvmlite.LLVMType* = self.repl_scalar_ty(pool, entry.Bits, 0)
if ptee is None:
ptee = llvmlite.Int8(pool)
return llvmlite.Ptr(pool, ptee)
if entry.TyTag == GenTypes.REPL_TY_STRUCT:
if entry.TyName is None:
return None
return self.Gen.StructGen.get_struct_type(entry.TyName)
return None
# ---- repl_slot_ty — 槽内存放的值类型 ----
def repl_slot_ty(self, pool: memhub.MemBuddy*,
entry: rawptr[GenTypes.ReplVarEntry]) -> llvmlite.LLVMType*:
"""槽内存放的值类型 = 条目的值类型本身(标量/指针/结构体值都内联在槽里)
结构体值另有体积约束:尺寸 > REPL_SLOT_SIZE 或对齐 > REPL_SLOT_SIZE 时
不可放入槽 → 返回 None(定型期 repl_seal 已先给明确报错,此处为防御)。
"""
if entry is None or pool is None:
return None
vt: llvmlite.LLVMType* = self.repl_llvm_ty(pool, entry)
if vt is None:
return None
if entry.TyTag == GenTypes.REPL_TY_STRUCT:
sz: int = self.repl_type_size(vt)
al: int = self.repl_type_align(vt)
if sz <= 0 or al <= 0 or sz > GenTypes.REPL_SLOT_SIZE \
or al > GenTypes.REPL_SLOT_SIZE:
return None
return vt
# ---- repl_type_align / repl_type_size — 结构体值的尺寸/对齐(LLVM 标准布局) ----
def repl_type_align(self, ty: llvmlite.LLVMType*, depth: int = 0) -> int:
"""类型自然对齐字节;未知类型返回 0(deep=守卫递归深度)"""
if ty is None or depth > 64:
return 0
ib: int = self.Gen.ExprGenBase.get_llvm_type_bits(ty)
if ib != 0:
if ib <= 8:
return 1
if ib <= 16:
return 2
if ib <= 32:
return 4
return 8
fb: int = self.Gen.ExprGenBase.get_llvm_float_bits(ty)
if fb != 0:
if fb <= 16:
return 2
if fb <= 32:
return 4
return 8
if self.Gen.ExprGenBase.is_ptr_type(ty) != 0:
return 8
elem_ty: llvmlite.LLVMType* = None
match ty:
case llvmlite.LLVMType.Array(elem_a, _cnt_a):
elem_ty = elem_a
case _:
pass
if elem_ty is not None:
return self.repl_type_align(elem_ty, depth + 1)
fields: rawptr[llvmlite.ParamNode] = llvmlite.get_struct_fields(ty)
if fields is None:
return 0
cur: rawptr[llvmlite.ParamNode] = fields
best: int = 1
while cur is not None:
fty: llvmlite.LLVMType* = llvmlite.paramnode_get_ty(cur)
fa: int = self.repl_type_align(fty, depth + 1)
if fa <= 0:
return 0
if fa > best:
best = fa
cur = llvmlite.paramnode_get_next(cur)
return best
def repl_type_size(self, ty: llvmlite.LLVMType*, depth: int = 0) -> int:
"""类型字节尺寸(LLVM 标准布局:字段按自然对齐排布 + 尾填充);未知返回 0
用于结构体值的"能否放入槽"判定(标量/指针见 repl_scalar_ty)。
"""
if ty is None or depth > 64:
return 0
ib: int = self.Gen.ExprGenBase.get_llvm_type_bits(ty)
if ib != 0:
return (ib + 7) // 8
fb: int = self.Gen.ExprGenBase.get_llvm_float_bits(ty)
if fb != 0:
return fb // 8
if self.Gen.ExprGenBase.is_ptr_type(ty) != 0:
return 8
elem_ty: llvmlite.LLVMType* = None
cnt: int = 0
match ty:
case llvmlite.LLVMType.Array(elem_s, cnt_s):
elem_ty = elem_s
cnt = cnt_s
case _:
pass
if elem_ty is not None:
es: int = self.repl_type_size(elem_ty, depth + 1)
if es <= 0 or cnt <= 0:
return 0
return es * cnt
fields: rawptr[llvmlite.ParamNode] = llvmlite.get_struct_fields(ty)
if fields is None:
return 0
align_struct: int = self.repl_type_align(ty, depth + 1)
if align_struct <= 0:
return 0
cur: rawptr[llvmlite.ParamNode] = fields
off: int = 0
counted: int = 0
while cur is not None:
fty2: llvmlite.LLVMType* = llvmlite.paramnode_get_ty(cur)
fsz: int = self.repl_type_size(fty2, depth + 1)
fa2: int = self.repl_type_align(fty2, depth + 1)
if fsz <= 0 or fa2 <= 0:
return 0
rem: int = off % fa2
if rem != 0:
off += fa2 - rem
off += fsz
counted += 1
cur = llvmlite.paramnode_get_next(cur)
if counted <= 0:
return 0
rem2: int = off % align_struct
if rem2 != 0:
off += align_struct - rem2
return off
# ---- repl_seal — 首次定型(已定型则校验类型标签一致) ----
def repl_seal(self, trans: HT.Translator*,
entry: rawptr[GenTypes.ReplVarEntry],
val_ty: llvmlite.LLVMType*,
node: ast.AST*) -> int:
"""按 val_ty 给条目定型;返回 0=成功(含幂等命中)/ 1=不支持或冲突(已 fail-fast)
规则:
- 首次(Kind=UNTYPED)写入 Kind/TyTag/Bits/TyName;
- 已定型:TyTag 必须一致(int↔float↔指针不隐式换型,避免槽语义漂移),
Bits 差异允许(由 coerce_to_type 做位宽对齐,常量溢出仍有既有 fail-fast)。
"""
if trans is None or entry is None or val_ty is None:
return 1
perm: memhub.MemBuddy* = self.repl_perm_pool(trans)
if perm is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话永久池不可用(宿主未注入)", "InternalCompilerError")
return 1
tag: int = 0
bits: int = 0
kind: int = GenTypes.REPL_KIND_SCALAR
tname: str = None
ib: int = self.Gen.ExprGenBase.get_llvm_type_bits(val_ty)
fb: int = self.Gen.ExprGenBase.get_llvm_float_bits(val_ty)
if ib != 0:
tag = GenTypes.REPL_TY_INT
bits = ib
elif fb != 0:
tag = GenTypes.REPL_TY_FLOAT
bits = fb
elif self.Gen.ExprGenBase.is_ptr_type(val_ty) != 0:
ptee: llvmlite.LLVMType* = val_ty.Pointee
pname: str = None
if ptee is not None:
pname = llvmlite.get_struct_name(ptee)
if pname is not None:
tag = GenTypes.REPL_TY_PTR
bits = 64
tname = pname
else:
pb: int = 0
pf: int = 0
if ptee is not None:
pb = self.Gen.ExprGenBase.get_llvm_type_bits(ptee)
pf = self.Gen.ExprGenBase.get_llvm_float_bits(ptee)
if pb == 8:
tag = GenTypes.REPL_TY_STR
bits = 8
else:
tag = GenTypes.REPL_TY_PTR
if pb != 0:
bits = pb
elif pf != 0:
bits = pf
else:
bits = 0
else:
sname: str = llvmlite.get_struct_name(val_ty)
if sname is not None:
# 结构体**值**:按声明类型内联在槽里(不做装箱)。
# 槽容量/对齐上限 = REPL_SLOT_SIZE(16 字节):结构体尺寸或对齐
# 超出即明确报错(不静默截断、不换用堆盒子)。
sz: int = self.repl_type_size(val_ty)
al: int = self.repl_type_align(val_ty)
if sz <= 0 or al <= 0:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{entry.Name}' 的结构体值 '{sname}' 尺寸/对齐未知"
f"(无法判定能否放入 {GenTypes.REPL_SLOT_SIZE} 字节槽)",
"TypeError")
return 1
if sz > GenTypes.REPL_SLOT_SIZE or al > GenTypes.REPL_SLOT_SIZE:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{entry.Name}' 的结构体值 '{sname}' 体积 {sz} 字节、"
f"对齐 {al} 字节,无法放入 {GenTypes.REPL_SLOT_SIZE} 字节槽"
f"(M2 结构体值须内联进槽;大对象请改用对象指针/堆分配)",
"TypeError")
return 1
tag = GenTypes.REPL_TY_STRUCT
bits = sz * 8
kind = GenTypes.REPL_KIND_SCALAR
tname = sname
else:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{entry.Name}' 的类型暂不支持"
f"(M2 支持 int/bool/浮点/str/bytes/指针/结构体值)",
"TypeError")
return 1
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
entry.Kind = kind
entry.TyTag = tag
entry.Bits = bits
entry.TyName = None
if tname is not None:
entry.TyName = self.repl_perm_strdup(perm, tname)
return 0
if entry.Kind != kind or entry.TyTag != tag:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{entry.Name}' 已定型为 {self.repl_tag_label(entry.TyTag, entry.Bits)},"
f"不能再赋成 {self.repl_tag_label(tag, bits)}(如需换型请重启会话)",
"TypeError")
return 1
if tname is not None and entry.TyName is None:
entry.TyName = self.repl_perm_strdup(perm, tname)
return 0
# ---- repl_perm_strdup — 深拷贝到 PermPool(跨片段存活) ----
def repl_perm_strdup(self, pool: memhub.MemBuddy*,
s: str) -> str:
"""把 s 深拷贝进 pool(调用方传 PermPool)供会话表长期持有;失败返回 None"""
if s is None or pool is None:
return None
n: sizet = string.strlen(s)
buf: str = pool.alloc(n + 1)
if buf is None:
return None
string.strcpy(buf, s)
return buf
# ---- repl_tag_label — 类型标签 → 显示名(宿主回显同口径) ----
def repl_tag_label(self, tag: int, bits: int) -> str:
"""TyTag/Bits → 人类可读类型名(仅用于错误消息)"""
if tag == GenTypes.REPL_TY_INT:
if bits == 1:
return "bool"
if bits == 8:
return "char"
if bits == 16:
return "int16"
if bits == 32:
return "int"
if bits == 64:
return "int64"
return "int?"
if tag == GenTypes.REPL_TY_FLOAT:
if bits == 32:
return "float"
if bits == 64:
return "double"
return "float?"
if tag == GenTypes.REPL_TY_STR:
return "str"
if tag == GenTypes.REPL_TY_PTR:
return "ptr"
if tag == GenTypes.REPL_TY_STRUCT:
return "struct"
return "?"
# ---- repl_ensure_entry — 首次遇到未定型的会话变量名时申请槽位 ----
#
# 分配时机:片段翻译期(translate_assign / translate_annassign 的 Name 目标
# 在局部表未命中时)。表满 ⇒ 明确报错(fail-fast,经 M0 setjmp 恢复点继续
# 下一行),不静默丢弃。
def repl_ensure_entry(self, trans: HT.Translator*,
name: str,
node: ast.AST*) -> rawptr[GenTypes.ReplVarEntry]:
"""按名取条目,未登记则分配槽位并登记;失败返回 None(已 fail-fast)"""
if trans is None or name is None:
return None
ctx: rawptr[GenTypes.ReplCtx] = trans.ReplCtx
if ctx is None or ctx.Marker != GenTypes.REPL_CTX_MARKER:
return None
hit: rawptr[GenTypes.ReplVarEntry] = self.repl_find_entry(ctx, name)
if hit is not None:
return hit
if ctx.Table is None or ctx.Cap <= 0:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话变量表未初始化(宿主未建 ctx)", "InternalCompilerError")
return None
if ctx.Count >= ctx.Cap:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量已达上限 {ctx.Cap} 个(ctx 槽位用尽),"
f"无法为 '{name}' 再分配槽位;请重启会话",
"ResourceError")
return None
perm: memhub.MemBuddy* = self.repl_perm_pool(trans)
if perm is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话永久池不可用(宿主未注入)", "InternalCompilerError")
return None
name_copy: str = self.repl_perm_strdup(perm, name)
if name_copy is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的名字深拷贝失败", "InternalCompilerError")
return None
entry_size: sizet = GenTypes.ReplVarEntry.__sizeof__()
entry: rawptr[GenTypes.ReplVarEntry] = rawptr[GenTypes.ReplVarEntry](uint64(ctx.Table) + uint64(ctx.Count) * uint64(entry_size))
if entry is None:
return None
entry.Name = name_copy
entry.TyName = None
entry.Offset = GenTypes.REPL_SLOT_BASE + ctx.Count * GenTypes.REPL_SLOT_SIZE
entry.Kind = GenTypes.REPL_KIND_UNTYPED
entry.TyTag = 0
entry.Bits = 0
ctx.Count = ctx.Count + 1
return entry
# ---- repl_perm_pool — 会话数据的永久池(跨片段存活) ----
def repl_perm_pool(self, trans: HT.Translator*) -> memhub.MemBuddy*:
"""宿主注入的 PermPool(ctx.Perm);无 ctx/未注入返回 None"""
if trans is None or trans.ReplCtx is None:
return None
return trans.ReplCtx.Perm
# ---- repl_emit_result — 把本片段结果写入 ctx 结果区 ----
def repl_emit_result(self, trans: HT.Translator*,
ctx_val: llvmlite.Value*,
val: llvmlite.Value*,
tag: int, bits: int,
node: ast.AST* = None) -> int:
"""按 tag 把 val 写入 ctx 结果区(见 GenTypes 的 result_kind 表);0=成功
tag: REPL_TY_INT/FLOAT/STR/PTR/STRUCT。
INT → kind=1,result_a = 值(sext 到 i64,按位模式;bits 仅用于诊断)
FLOAT → kind=2,result_a = double 位模式(f32 先 fpext)
STR → kind=3,result_a = 指针,result_b = 0(NUL 结尾,长度未知)
PTR → kind=4,result_a = 地址
STRUCT→ kind=4,result_a = 0(结构体值内联在槽里,本身没有地址)
宿主只按 (kind, result_a, result_b) 读,不需要知道槽内类型。
"""
if trans is None or ctx_val is None or val is None:
return 1
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
if pool is None or builder is None:
return 1
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
zero64: llvmlite.Value* = llvmlite.const_int64(pool, 0)
if tag == GenTypes.REPL_TY_INT:
iv: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, val, i64_ty, node, trans)
if iv is None:
return 1
if self._repl_store_res_i32(trans, ctx_val, GenTypes.REPL_RES_KIND_OFF,
GenTypes.REPL_RES_INT) != 0:
return 1
if self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_A_OFF, iv) != 0:
return 1
return self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_B_OFF, zero64)
if tag == GenTypes.REPL_TY_FLOAT:
dv: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, val, llvmlite.Double(pool), node, trans)
if dv is None:
return 1
# double → i64 位模式(bitcast,不做数值转换):宿主按位重解释回 double
dbits: llvmlite.Value* = llvmlite.build_bitcast(builder, dv, i64_ty)
if dbits is None:
return 1
if self._repl_store_res_i32(trans, ctx_val, GenTypes.REPL_RES_KIND_OFF,
GenTypes.REPL_RES_FLOAT) != 0:
return 1
if self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_A_OFF, dbits) != 0:
return 1
return self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_B_OFF, zero64)
if tag == GenTypes.REPL_TY_STR or tag == GenTypes.REPL_TY_PTR:
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
pv: llvmlite.Value* = val
if val.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0 \
and self.Gen.AssignGen._stg_ty_equal(pool, val.Ty, i8_ptr_ty) == 0:
# 已是指向 i8 的指针(str/bytes/t.CPtr)时跳过——LLVM 拒绝同型 bitcast
pv = llvmlite.build_bitcast(builder, val, i8_ptr_ty)
if pv is None:
return 1
# 指针 → i64(ptrtoint):宿主按整数读回后再 inttoptr 成地址
pbits: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, pv, i64_ty, node, trans)
if pbits is None:
return 1
kind: int = GenTypes.REPL_RES_OBJ
if tag == GenTypes.REPL_TY_STR:
kind = GenTypes.REPL_RES_STR
if self._repl_store_res_i32(trans, ctx_val, GenTypes.REPL_RES_KIND_OFF,
kind) != 0:
return 1
if self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_A_OFF, pbits) != 0:
return 1
return self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_B_OFF, zero64)
if tag == GenTypes.REPL_TY_STRUCT:
# 结构体值:内联在会话槽里,值本身没有地址 ⇒ 结果区只报"类别"
# (kind=4 且 result_a=0;宿主据此打印 <struct 值>)
if self._repl_store_res_i32(trans, ctx_val, GenTypes.REPL_RES_KIND_OFF,
GenTypes.REPL_RES_OBJ) != 0:
return 1
if self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_A_OFF, zero64) != 0:
return 1
return self._repl_store_res_i64(trans, ctx_val, GenTypes.REPL_RES_B_OFF, zero64)
return 1
# ---- _repl_store_res_i64 / _repl_store_res_i32 — 结果区某偏移写定宽常量/值 ----
def _repl_store_res_i64(self, trans: HT.Translator*,
ctx_val: llvmlite.Value*,
off: int,
val: llvmlite.Value*) -> int:
"""把 i64 值写到 ctx 结果区的 off 偏移(0=成功)"""
if trans is None or ctx_val is None or val is None:
return 1
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
slot: llvmlite.Value* = self.repl_slot_ptr(pool, builder, ctx_val, off, llvmlite.Int64(pool))
if slot is None:
return 1
llvmlite.build_store(builder, val, slot)
return 0
def _repl_store_res_i32(self, trans: HT.Translator*,
ctx_val: llvmlite.Value*,
off: int,
val: int) -> int:
"""把 i32 常量写到 ctx 结果区的 off 偏移(kind / var_count 等,0=成功)"""
if trans is None or ctx_val is None:
return 1
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
if pool is None or builder is None:
return 1
slot: llvmlite.Value* = self.repl_slot_ptr(pool, builder, ctx_val, off, llvmlite.Int32(pool))
if slot is None:
return 1
cv: llvmlite.Value* = llvmlite.const_int32(pool, val)
if cv is None:
return 1
llvmlite.build_store(builder, cv, slot)
return 0
# ---- repl_try_read — 会话变量读取(命中返回 load 值,未命中返回 None) ----
def repl_try_read(self, trans: HT.Translator*,
name: str,
node: ast.AST*) -> llvmlite.Value*:
"""REPL 会话变量读:命中返回槽内值(结构体返回盒子地址);否则 None
返回 None 表示"不是会话变量",调用方继续原有查找/报错路径。
"""
if trans is None or trans.ReplCtx is None or name is None:
return None
entry: rawptr[GenTypes.ReplVarEntry] = self.repl_find_entry(trans.ReplCtx, name)
if entry is None:
return None
if self.repl_in_frag_scope(trans.SymTab) == 0:
return None
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{name}' 尚未赋值(未定型,先执行一条 'x = ...' 或 'x: int = ...')",
"NameError")
return None
pool: memhub.MemBuddy* = trans.Pool
slot_ty: llvmlite.LLVMType* = self.repl_slot_ty(pool, entry)
if slot_ty is None:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{name}' 的类型 "
f"{self.repl_tag_label(entry.TyTag, entry.Bits)} 在当前片段不可用"
f"(跨片段类型可见性属 M4)",
"NameError")
return None
ctx_val: llvmlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
if ctx_val is None:
return None
slot: llvmlite.Value* = self.repl_slot_ptr(pool, trans._cur_builder, ctx_val, entry.Offset, slot_ty)
if slot is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽地址生成失败", "InternalCompilerError")
return None
return llvmlite.build_load(trans._cur_builder, slot_ty, slot)
# ---- repl_try_addr — 会话变量取址(c.Addr(x) → ctx 槽地址) ----
def repl_try_addr(self, trans: HT.Translator*,
name: str,
node: ast.AST*) -> llvmlite.Value*:
"""会话变量取址:返回槽地址(Ptr(值类型))
值只存一份(宿主持有的 ctx arena)且内联在槽里,故 c.Addr(x) 得到的
就是该槽的地址:后续经该指针的读写直接作用于会话变量(地址同一性)。
未登记/未定型/不在片段函数本体返回 None,由调用方继续原有查找与报错路径。
"""
if trans is None or trans.ReplCtx is None or name is None:
return None
entry: rawptr[GenTypes.ReplVarEntry] = self.repl_find_entry(trans.ReplCtx, name)
if entry is None:
return None
if self.repl_in_frag_scope(trans.SymTab) == 0:
return None
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{name}' 尚未赋值(未定型),无法取址(c.Addr)",
"NameError")
return None
pool: memhub.MemBuddy* = trans.Pool
slot_ty: llvmlite.LLVMType* = self.repl_slot_ty(pool, entry)
if slot_ty is None:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{name}' 的类型在当前片段不可用(跨片段类型可见性属 M4)",
"NameError")
return None
ctx_val: llvmlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
if ctx_val is None:
return None
slot: llvmlite.Value* = self.repl_slot_ptr(pool, trans._cur_builder, ctx_val, entry.Offset, slot_ty)
if slot is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽地址生成失败", "InternalCompilerError")
return None
# 值内联在槽里(无装箱间接层)⇒ 槽地址即值地址
return slot
# ---- repl_store_slot — 定型后的值写槽(并把该值写入结果区) ----
def repl_store_slot(self, trans: HT.Translator*,
entry: rawptr[GenTypes.ReplVarEntry],
ctx_val: llvmlite.Value*,
rhs_val: llvmlite.Value*,
node: ast.AST*) -> int:
"""coerce 到槽类型 → 写槽 → 写结果区;0=成功(失败已 fail-fast)
槽内一律"值本身"(标量/指针/≤16B 结构体值内联),无装箱间接层 ⇒
槽地址即值地址(c.Addr 的地址同一性由此成立)。
"""
if trans is None or entry is None or ctx_val is None or rhs_val is None:
return 1
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
slot_ty: llvmlite.LLVMType* = self.repl_slot_ty(pool, entry)
if slot_ty is None:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{entry.Name}' 的槽类型不可用"
f"(类型在当前片段不可解析,或结构体值体积超出槽容量)",
"TypeError")
return 1
store_val: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, slot_ty, node, trans)
if store_val is None:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{entry.Name}' 无法把右侧值转换为"
f" {self.repl_tag_label(entry.TyTag, entry.Bits)}",
"CastError")
return 1
if self.Gen.ExprGenBase.is_ptr_type(slot_ty) != 0 \
and store_val.Ty is not None \
and self.Gen.ExprGenBase.is_ptr_type(store_val.Ty) != 0 \
and self.Gen.AssignGen._stg_ty_equal(pool, store_val.Ty, slot_ty) == 0:
# 指针同型化(槽类型与右侧指针可能不是同一类型实例;位宽相同)。
# 同型(含两侧都是 i8*)时跳过——LLVM 拒绝同型 bitcast。
store_val = llvmlite.build_bitcast(builder, store_val, slot_ty)
if store_val is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽指针同型化失败", "CastError")
return 1
slot: llvmlite.Value* = self.repl_slot_ptr(pool, builder, ctx_val, entry.Offset, slot_ty)
if slot is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽写入失败", "InternalCompilerError")
return 1
llvmlite.build_store(builder, store_val, slot)
self.repl_emit_result(trans, ctx_val, store_val, entry.TyTag, entry.Bits, node)
return 0
# ---- repl_try_assign — 会话变量赋值(命中返回 1) ----
def repl_try_assign(self, trans: HT.Translator*,
name: str,
rhs_val: llvmlite.Value*,
rhs_node: ast.AST*,
node: ast.AST*) -> int:
"""REPL 会话变量赋值:命中(已登记 + 在**片段入口函数**本体)返回 1,否则 0
命中路径:定型 → coerce 到条目类型 → 写槽 → 写结果区。
返回 1 时调用方必须 continue(不得再走局部 alloca 路径)。
作用域判据用 repl_in_frag_entry_scope(M3):被提升的会话函数体内不做
会话槽写入(那里 `y = 1` 是局部变量、形参同名遮蔽也走局部)——详见该谓词注释。
"""
if trans is None or trans.ReplCtx is None or name is None or rhs_val is None:
return 0
entry: rawptr[GenTypes.ReplVarEntry] = self.repl_find_entry(trans.ReplCtx, name)
if entry is None:
return 0
if self.repl_in_frag_entry_scope(trans) == 0:
return 0
if rhs_val.Ty is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的赋值右侧类型未知", "TypeError")
return 1
if self.repl_seal(trans, entry, rhs_val.Ty, rhs_node) != 0:
return 1
ctx_val: llvmlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
if ctx_val is None:
return 1
self.repl_store_slot(trans, entry, ctx_val, rhs_val, node)
return 1
# ---- repl_try_annassign — 会话变量带注解声明/赋值(命中返回 1) ----
def repl_try_annassign(self, trans: HT.Translator*,
name: str,
annot_node: ast.AST*,
value_node: ast.AST*,
node: ast.AST*) -> int:
"""REPL 会话变量注解路径:x: int = 1 / x: int(仅定型)
注解先解析并定型条目,再用定型后的类型作为 RHS 的 target_ty(与普通
AnnAssign 的 P1-A 位宽传播同口径:`x: int64 = 12345` 直接物化 i64)。
作用域判据用 repl_in_frag_entry_scope(M3):被提升的会话函数体内
`x: int = 1` 是局部声明(Python 语义),不占会话槽。
"""
if trans is None or trans.ReplCtx is None or name is None:
return 0
entry: rawptr[GenTypes.ReplVarEntry] = self.repl_find_entry(trans.ReplCtx, name)
if entry is None:
return 0
if self.repl_in_frag_entry_scope(trans) == 0:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
if annot_node is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的注解缺失", "SyntaxError")
return 1
# 与普通 AnnAssign 同口径:先注册泛型特化,避免 list[X] 退化为裸基类
# (裸 list* 会让后续 .get() 误分派并截断指针)
self.Gen.AssignGen._prespecialize_generic_annotation(trans, pool, annot_node)
annot_ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, annot_node, trans._imported_modules, trans._from_imports, trans, 0)
if annot_ty is None:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{name}' 的类型注解解析失败"
f"(片段无 import;仅内建名 int/str/bytes/bool/float/double/char 等可解析)",
"NameError")
return 1
if self.repl_seal(trans, entry, annot_ty, node) != 0:
return 1
if value_node is None:
# 仅定型(x: int):不产生值;结果区本行由宿主清零 ⇒ 无结果
return 1
slot_ty: llvmlite.LLVMType* = self.repl_slot_ty(pool, entry)
# 与普通 AnnAssign 四处同口径:翻译 RHS 前设置上下文(裸名泛型构造推断用)
trans.CurAssignAnnot = annot_node
trans.CurAssignNode = value_node
rhs_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, value_node, None, 0, trans, slot_ty)
trans.CurAssignAnnot = None
trans.CurAssignNode = None
if rhs_val is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的初值翻译失败", "TypeError")
return 1
ctx_val: llvmlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
if ctx_val is None:
return 1
self.repl_store_slot(trans, entry, ctx_val, rhs_val, node)
return 1
# ---- repl_try_augassign — 会话变量增强赋值(命中返回 1) ----
def repl_try_augassign(self, trans: HT.Translator*,
name: str,
op: int,
rhs_node: ast.AST*,
node: ast.AST*) -> int:
"""REPL 会话变量 x += v:读槽 → 二元运算 → 写槽 → 写结果(命中返回 1)
作用域判据用 repl_in_frag_entry_scope(M3):被提升的会话函数体内
`x += 1` 按 Python 局部语义处理(不写会话槽)。
"""
if trans is None or trans.ReplCtx is None or name is None:
return 0
entry: rawptr[GenTypes.ReplVarEntry] = self.repl_find_entry(trans.ReplCtx, name)
if entry is None:
return 0
if self.repl_in_frag_entry_scope(trans) == 0:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
if entry.TyTag == GenTypes.REPL_TY_STRUCT:
self.Gen.TypeGenErr.fatal_error(node,
f"REPL: 会话变量 '{name}' 是结构体值,不支持增强赋值",
"TypeError")
return 1
cur_val: llvmlite.Value* = self.repl_try_read(trans, name, node)
if cur_val is None:
return 1
rhs_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, rhs_node, None, 0, trans)
if rhs_val is None:
self.Gen.TypeGenErr.fatal_error(node, "REPL: 增强赋值右侧翻译失败", "TypeError")
return 1
result: llvmlite.Value* = self.Gen.AssignGen._apply_aug_op(pool, builder, op, cur_val, rhs_val, node, trans, node)
if result is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的增强赋值运算失败 op={op}", "TypeError")
return 1
# 写回槽(复用赋值路径:定型已存在 ⇒ 只做转换与存储)
return self.repl_try_assign(trans, name, result, node, node)
# ---- repl_expr_result — 片段内裸表达式语句的结果回传 ----
def repl_expr_result(self, trans: HT.Translator*,
value_node: ast.AST*) -> int:
"""REPL 模式下把裸表达式语句(如 x + 1)求值并写入结果区;0=成功
非 REPL 模式不调用本函数(translate_expr_stmt 只在 REPL 分支调用),
故"表达式语句除调用外一律忽略"的原行为不变。
"""
if trans is None or trans.ReplCtx is None or value_node is None:
return 1
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, value_node, None, 0, trans)
if val is None or val.Ty is None:
self.Gen.TypeGenErr.fatal_error(value_node, "REPL: 表达式片段求值失败", "TypeError")
return 1
ctx_val: llvmlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, value_node)
if ctx_val is None:
return 1
# 类型分类用宿主的影子条目(不占会话槽、不进表):每次先复位为未定型
sh: rawptr[GenTypes.ReplVarEntry] = trans.ReplCtx.Scratch
if sh is None:
self.Gen.TypeGenErr.fatal_error(value_node, "REPL: 会话缺少影子条目(宿主未初始化)", "InternalCompilerError")
return 1
sh.Kind = GenTypes.REPL_KIND_UNTYPED
sh.TyTag = 0
sh.Bits = 0
sh.TyName = None
if self.repl_seal(trans, sh, val.Ty, value_node) != 0:
return 1
return self.repl_emit_result(trans, ctx_val, val, sh.TyTag, sh.Bits, value_node)