同 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)与本迁移无关,保持不动。
1627 lines
83 KiB
Plaintext
1627 lines
83 KiB
Plaintext
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)
|