507 lines
25 KiB
Plaintext
507 lines
25 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||
import t, c
|
||
from stdint import *
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
|
||
|
||
# ============================================================
|
||
# VarGenMixin - 变量/作用域符号表 Mixin
|
||
#
|
||
# 职责:变量注册/查找、作用域进出(模块/函数/match)与 alloca 创建。
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesVar 保持一致)
|
||
# ============================================================
|
||
# 作用域类型常量
|
||
SCOPE_MODULE: t.CDefine = 0
|
||
SCOPE_FUNCTION: t.CDefine = 1
|
||
SCOPE_BLOCK: t.CDefine = 2
|
||
# match case 作用域(对齐 MatchGenMixin.SCOPE_MATCH;本地定义避免循环依赖)。
|
||
# 该作用域仅用于"变体字段绑定隔离",普通赋值语义上属于外层函数作用域,
|
||
# get_or_create_sym/_lookup_through_match_scope 会"看穿"它写回外层变量。
|
||
SCOPE_MATCH: t.CDefine = 6
|
||
|
||
# 每个作用域最大变量数
|
||
# 256 太小:NewAstTest main() 有 289 个局部变量(几十个测试用例),
|
||
# add_var 超限静默失败导致变量未注册,后续使用报"未定义名称"(NameError)。
|
||
MAX_VARS: t.CDefine = 1024
|
||
|
||
|
||
# ============================================================
|
||
# VarGenMixin - 变量/作用域符号表 Mixin
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class VarGenMixin:
|
||
"""变量/作用域 Mixin(P6 方法化)"""
|
||
# 迁移自 HandlesVar 的模块级函数
|
||
|
||
# ============================================================
|
||
# init_vars — 分配并清零 VarEntry 数组
|
||
# ============================================================
|
||
Gen: rawptr[Generator.Generator]
|
||
def init_vars(self, pool: rawptr[memhub.MemBuddy]) -> GenTypes.VarEntry | t.CPtr:
|
||
"""分配并清零变量表数组"""
|
||
size: sizet = MAX_VARS * GenTypes.VarEntry.__sizeof__()
|
||
vars_ptr: GenTypes.VarEntry | t.CPtr = 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 | t.CPtr,
|
||
var_count: int,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""在变量表中按名称查找"""
|
||
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 | t.CPtr = (GenTypes.VarEntry | t.CPtr)(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 | t.CPtr,
|
||
var_count: int,
|
||
name: str) -> GenTypes.VarEntry | t.CPtr:
|
||
"""在变量表中按名称查找,返回 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 | t.CPtr = (GenTypes.VarEntry | t.CPtr)(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: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> GenTypes.VarEntry | t.CPtr:
|
||
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: GenTypes.Scope | t.CPtr = symtab.Current
|
||
while scope is not None:
|
||
result: GenTypes.VarEntry | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr) -> 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: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> int:
|
||
"""标记变量为 ptr-element(Spec.ElemBits=64),返回 0=成功 / 1=失败"""
|
||
if symtab is None or name is None:
|
||
return 1
|
||
entry: GenTypes.VarEntry | t.CPtr = 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 | t.CPtr) -> int:
|
||
"""变量是否为 ptr-element 语义(1=是 / 0=否)"""
|
||
if entry is None or entry.Spec is None:
|
||
return 0
|
||
sp: TSpec.TypeSpec | t.CPtr = 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
|
||
|
||
# ============================================================
|
||
# add_var — 添加变量到变量表
|
||
# ============================================================
|
||
def add_var(self, vars_ptr: GenTypes.VarEntry | t.CPtr,
|
||
var_count: int,
|
||
name: str,
|
||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""添加变量到变量表"""
|
||
if name is None or alloca is None or vars_ptr is None:
|
||
return 1
|
||
if var_count >= MAX_VARS:
|
||
return 1
|
||
entry_size: sizet = GenTypes.VarEntry.__sizeof__()
|
||
entry_addr: uint64 = uint64(vars_ptr) + var_count * entry_size
|
||
entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(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
|
||
# [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 | t.CPtr) -> TSpec.TypeSpec | t.CPtr:
|
||
"""由 alloca 的值类型构造 TypeSpec,不适用/失败返回 None"""
|
||
if alloca is None or alloca.Ty is None:
|
||
return None
|
||
ty: llvmlite.LLVMType | t.CPtr = alloca.Ty
|
||
if self.Gen.ExprGenBase.is_ptr_type(ty) != 0:
|
||
ty = ty.Pointee
|
||
arena: TSpec.TypeSpecArena | t.CPtr = 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 | t.CPtr,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""在函数入口块生成 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: rawptr[memhub.MemBuddy],
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
vars_ptr: GenTypes.VarEntry | t.CPtr,
|
||
var_count: int,
|
||
name: str,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""查找或创建变量 alloca"""
|
||
existing: llvmlite.Value | t.CPtr = self.find_var(vars_ptr, var_count, name)
|
||
if existing is not None:
|
||
return existing
|
||
alloca: llvmlite.Value | t.CPtr = 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: rawptr[memhub.MemBuddy],
|
||
parent: GenTypes.Scope | t.CPtr,
|
||
kind: int) -> GenTypes.Scope | t.CPtr:
|
||
"""创建并初始化作用域节点"""
|
||
scope: GenTypes.Scope | t.CPtr = 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: rawptr[memhub.MemBuddy]) -> GenTypes.SymbolTable | t.CPtr:
|
||
"""创建并初始化符号表,包含模块级根作用域"""
|
||
if pool is None:
|
||
return None
|
||
symtab: GenTypes.SymbolTable | t.CPtr = pool.alloc(GenTypes.SymbolTable.__sizeof__())
|
||
if symtab is None:
|
||
return None
|
||
string.memset(symtab, 0, GenTypes.SymbolTable.__sizeof__())
|
||
symtab.Pool = pool
|
||
|
||
# 创建根作用域(模块级)
|
||
root: GenTypes.Scope | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
kind: int) -> GenTypes.Scope | t.CPtr:
|
||
"""进入新作用域,返回新创建的作用域"""
|
||
if symtab is None:
|
||
return None
|
||
pool: rawptr[memhub.MemBuddy] = symtab.Pool
|
||
scope: GenTypes.Scope | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr):
|
||
"""退出当前作用域,恢复到父作用域"""
|
||
if symtab is not None and symtab.Current is not None:
|
||
symtab.Current = symtab.Current.Parent
|
||
|
||
# ============================================================
|
||
# define_var — 在当前作用域定义变量
|
||
# ============================================================
|
||
def define_var(self, symtab: GenTypes.SymbolTable | t.CPtr,
|
||
name: str,
|
||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""在当前作用域定义变量,返回 0 成功"""
|
||
if symtab is None or name is None or alloca is None:
|
||
return 1
|
||
scope: GenTypes.Scope | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
name: str,
|
||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""在模块作用域定义变量,返回 0 成功"""
|
||
if symtab is None or name is None or alloca is None:
|
||
return 1
|
||
scope: GenTypes.Scope | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从当前作用域逐级向上查找变量,返回 alloca 或 None"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: GenTypes.Scope | t.CPtr = symtab.Current
|
||
while scope is not None:
|
||
result: llvmlite.Value | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""仅在当前作用域查找变量"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: GenTypes.Scope | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""在模块作用域查找变量"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: GenTypes.Scope | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr) -> 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 作用域查找变量
|
||
# match case 作用域(SCOPE_MATCH)仅用于"变体字段绑定隔离"(case 绑定的模式
|
||
# 变量互不泄漏);case 体内对"外层普通变量"的赋值语义上应写回外层 alloca,
|
||
# 而非新建 case 局部槽——否则外层变量恒为初始值。
|
||
# 遍历规则:逐级向上查找;SCOPE_MATCH 边界可穿越(可命中外层 case 声明的变量),
|
||
# 遇到第一个非 match 作用域(函数/模块)后停止——不跨函数边界(闭包 nonlocal
|
||
# 语义由 is_nonlocal_name 单独处理)。
|
||
def _lookup_through_match_scope(self, symtab: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从当前作用域向上,仅穿越 SCOPE_MATCH 作用域查找变量 alloca"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: GenTypes.Scope | t.CPtr = symtab.Current
|
||
while scope is not None:
|
||
result: llvmlite.Value | t.CPtr = 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: GenTypes.SymbolTable | t.CPtr,
|
||
pool: rawptr[memhub.MemBuddy],
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
name: str,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""查找或创建变量 alloca(在当前作用域)"""
|
||
existing: llvmlite.Value | t.CPtr = self.lookup_current(symtab, name)
|
||
if existing is not None:
|
||
return existing
|
||
# SCOPE_MATCH 隔离作用域对"赋值"必须透明(详见 _lookup_through_match_scope):
|
||
# case 体内对外层变量的赋值要写回外层 alloca。仅穿越 match 边界,
|
||
# 不跨函数/模块作用域(global/nonlocal 在 AssignGenMixin 提前拦截)。
|
||
existing = self._lookup_through_match_scope(symtab, name)
|
||
if existing is not None:
|
||
return existing
|
||
alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty)
|
||
if alloca is None:
|
||
return None
|
||
if self.define_var(symtab, name, alloca) != 0:
|
||
# fail-fast: 变量注册失败(如超过 MAX_VARS)必须立即终止。
|
||
# 静默忽略返回值会使 alloca 已建但未入符号表,后续读取报"未定义名称"。
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
None,
|
||
f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)",
|
||
"InternalCompilerError")
|
||
return alloca
|