- Gen/*.vp 按前缀分组迁入 Call/Class/Expr/Func/Stmt/Type 子目录,import 同步更新(BuildPipeline/Generator/StructGenMixin 等) - CallGenDispatch: REnum.kind() 前置拦截 → bitcast i32* + load(读 __tag),杜绝方法查找兜底误绑 AST.kind(this 偏移语义错误) - 留根:Assign/Async/Base/Imports/Match/Struct/Translator/Var 单文件前缀 + GenApi/GenTypes/Generator/__init__
437 lines
21 KiB
Plaintext
437 lines
21 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import t, c
|
||
from stdint import *
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
|
||
|
||
# ============================================================
|
||
# VarGenMixin - 变量/作用域符号表 Mixin(P6 对象化,wiki/14-oo-refactor.md)
|
||
#
|
||
# 从 HandlesVar.vp 迁移:模块级函数(init_vars/find_var/find_var_entry/
|
||
# lookup_var_entry/set_var_annot_class_name/set_var_ptr_element/add_var/
|
||
# _alloca_at_entry/get_or_create_var/_create_scope/init_symbol_table/
|
||
# enter_scope/exit_scope/define_var/define_module_var/lookup_var/
|
||
# lookup_current/lookup_module_var/is_module_scope/get_or_create_sym)
|
||
# → 本类方法。
|
||
#
|
||
# @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: Generator.Generator | t.CPtr
|
||
def init_vars(self, pool: memhub.MemBuddy | t.CPtr) -> GenTypes.VarEntry | t.CPtr:
|
||
"""分配并清零变量表数组"""
|
||
size: t.CSizeT = 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: t.CSizeT = GenTypes.VarEntry.__sizeof__()
|
||
for i in range(var_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
|
||
entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None and entry.Used != 0:
|
||
if 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: t.CSizeT = GenTypes.VarEntry.__sizeof__()
|
||
for i in range(var_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
|
||
entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
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 — 设置变量的原始类型注解类名
|
||
#
|
||
# 在函数参数定义后调用,存储原始类型注解的类名。
|
||
# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化),
|
||
# 通过 AnnotClassName 查找实际结构体类型。
|
||
# ============================================================
|
||
def set_var_annot_class_name(self, symtab: GenTypes.SymbolTable | t.CPtr,
|
||
name: str,
|
||
class_name: str) -> int:
|
||
"""设置变量的原始类型注解类名,返回 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
|
||
entry.AnnotClassName = class_name
|
||
return 0
|
||
|
||
# ============================================================
|
||
# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型
|
||
#
|
||
# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*,
|
||
# 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。
|
||
# 此标志在 HandlesAnnAssign 中根据注解形式设置。
|
||
# ============================================================
|
||
def set_var_ptr_element(self, symtab: GenTypes.SymbolTable | t.CPtr,
|
||
name: str) -> int:
|
||
"""标记变量为 ptr_element 类型,返回 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
|
||
entry.IsPtrElement = 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: t.CSizeT = GenTypes.VarEntry.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size
|
||
entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
entry.Name = name
|
||
entry.Alloca = alloca
|
||
entry.Used = 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性)
|
||
#
|
||
# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成,
|
||
# 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。
|
||
# 标准做法:所有 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: memhub.MemBuddy | t.CPtr,
|
||
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: memhub.MemBuddy | t.CPtr,
|
||
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: memhub.MemBuddy | t.CPtr) -> 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: memhub.MemBuddy | t.CPtr = 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 t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root):
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _lookup_through_match_scope — 穿越 match case 作用域查找变量
|
||
#
|
||
# match case 作用域(SCOPE_MATCH)仅用于"变体字段绑定隔离"(case 绑定的
|
||
# 模式变量互不泄漏)。case 体内对"外层普通变量"的赋值(如 FuncGenDef
|
||
# 参数 match 的 param_ty2 = Ptr(...),或 translate_subscript 内层 case 的
|
||
# list_struct_name = lsn)语义上应写回外层 alloca,而非新建 case 局部槽
|
||
# ——否则外层变量恒为初始值。自举证据:gen1 编译出的 gen2 其 FuncGenDef
|
||
# 参数 match 把赋值写进 case 局部槽、build_alloca 读初始 i32_ty,导致
|
||
# 指针参数 alloca 退化为 i32 → FuncTest main.vp:32 `p[0] = p[0] + val`
|
||
# 的 translate_subscript 读 i32 非指针返回 None("赋值右侧为 None
|
||
# [kind=11]" 根因)。
|
||
# 遍历规则:逐级向上查找;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: memhub.MemBuddy | t.CPtr,
|
||
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 已创建但未入符号表,后续读取该变量
|
||
# 报"未定义名称"(NewAstTest main() 289 个局部变量 > MAX_VARS=256
|
||
# 的 NameError 根因),误导排查。变量表超限暴露上游规模问题。
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
None,
|
||
f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)",
|
||
"InternalCompilerError")
|
||
return alloca
|