Files
TransPyV/App/lib/core/Handles/HandlesNonlocal.py
2026-07-19 13:18:46 +08:00

128 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# HandlesNonlocal - nonlocal 变量访问(通过闭包 env
#
# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针)
# 指针指向原始变量(可能是 alloca 或全局变量)
#
# 在提升的嵌套函数中:
# 1. 函数签名: define i32 @__closure_{name}(i8* %env)
# 2. 入口处: %env_alloca = alloca i8*; store i8* %env, i8** %env_alloca
# 3. 访问 nonlocal var:
# a. %env_ptr = load i8*, i8** %env_alloca
# b. %addr = gep i8, i8* %env_ptr, i32 (index * 8)
# c. %ptr_addr = bitcast i8* %addr to i8**
# d. %var_ptr_raw = load i8*, i8** %ptr_addr
# e. %var_ptr = bitcast i8* %var_ptr_raw to i32*
# f. read: %val = load i32, i32* %var_ptr
# write: store i32 %new, i32* %var_ptr
# ============================================================
# ============================================================
# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca
# ============================================================
def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, "_env_ptr")
if env_var is not None:
return env_var
# 创建 alloca 存储 env
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
if alloca is None:
return None
HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca)
return alloca
# ============================================================
# 加载 nonlocal 变量值 → 返回 i32 Value
#
# env 直接存储 i32 值(不是指针),每个 nonlocal 变量占 4 字节
# ============================================================
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量值env 直接存储 i32 值)"""
idx: int = HT.get_nonlocal_index(trans, name)
if idx < 0:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
# 1. 加载 env_ptr
env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans)
if env_alloca is None:
return None
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
if env_ptr is None:
return None
# 2. GEP to offset (idx * 4) — env 直接存储 i32 值
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4)
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
if addr is None:
return None
# 3. Bitcast to i32* and load
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i32_ptr_ty)
if var_ptr is None:
return None
return llvmlite.build_load(builder, i32_ty, var_ptr)
# ============================================================
# 获取 nonlocal 变量指针(用于 store
#
# 返回 env 中 i32 槽位的地址i32*),用于直接 store
# ============================================================
def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""获取 nonlocal 变量在 env 中的地址i32*),用于 store 操作"""
idx: int = HT.get_nonlocal_index(trans, name)
if idx < 0:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
# 1. 加载 env_ptr
env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans)
if env_alloca is None:
return None
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
if env_ptr is None:
return None
# 2. GEP to offset (idx * 4) — env 直接存储 i32 值
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4)
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
if addr is None:
return None
# 3. Bitcast to i32* and return (直接指向 env 中的 i32 槽位)
return llvmlite.build_bitcast(builder, addr, i32_ptr_ty)