Files
ViperC/App/lib/core/Handles/HandlesBody.vp
T

309 lines
12 KiB
Plaintext

import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import viperlib
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# HandlesBody - 语句分派(trans 单参模式,全方法调用)
#
# 所有语句类型通过 trans.XxxH.Handle(node) 分派到对应 Handle。
# 对应 TransPyC BodyHandle.HandleBodyLlvm 的 isinstance 分派。
# ============================================================
# ============================================================
# 语句翻译分派
# ============================================================
def translate_stmt(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译单条语句,返回新增的变量数"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Expr:
return translate_expr_stmt(trans, node)
elif k == ast.ASTKind.Assign:
return trans.AssignH.Handle(node)
elif k == ast.ASTKind.AnnAssign:
return trans.AnnAssignH.Handle(node)
elif k == ast.ASTKind.FunctionDef:
# 嵌套函数定义:提升为顶层函数 + 创建闭包
return HandlesFunctions.translate_nested_function_def(trans, node)
elif k == ast.ASTKind.Return:
return trans.ReturnH.Handle(node)
elif k == ast.ASTKind.If:
return trans.IfH.Handle(node)
elif k == ast.ASTKind.While:
return trans.WhileH.Handle(node)
elif k == ast.ASTKind.AugAssign:
return trans.AugAssignH.Handle(node)
elif k == ast.ASTKind.For:
return trans.ForH.Handle(node)
elif k == ast.ASTKind.ClassDef:
return HandlesClassDef.translate_class_def(trans, node)
elif k == ast.ASTKind.Import:
return trans.ImportsH.HandleImport(node)
elif k == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(node)
return trans.ImportsH.HandleImportFromNames(node)
elif k == ast.ASTKind.Global:
return translate_global(trans, node)
elif k == ast.ASTKind.Nonlocal:
return translate_nonlocal(trans, node)
elif k == ast.ASTKind.Pass:
return 0
elif k == ast.ASTKind.Break:
return translate_break(trans)
elif k == ast.ASTKind.Continue:
return translate_continue(trans)
elif k == ast.ASTKind.Match:
return trans.MatchH.Handle(node)
elif k == ast.ASTKind.Delete:
return translate_delete(trans, node)
return 0
# ============================================================
# 翻译 Delete 语句: del obj.attr
#
# 支持 property deleter: 当目标 attr 是 @x.deleter 方法时,
# 生成 call Class.attr$del(obj)。其余目标暂不生成代码。
# ============================================================
def translate_delete(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 del 语句,返回 0"""
if trans is None or node is None:
return 0
dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node)
if dnode is None or dnode.targets is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
if pool is None or mod is None or builder is None:
return 0
tn: t.CSizeT = dnode.targets.__len__()
for ti in range(tn):
tgt: ast.AST | t.CPtr = dnode.targets.get(ti)
if tgt is None:
continue
# del obj.attr → property deleter
if tgt.kind() == ast.ASTKind.Attribute:
del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt)
if del_at is not None:
HandlesExprCall._try_property_deleter(
pool, builder, mod, del_at, trans)
return 0
# ============================================================
# 翻译 Global 语句: global x, y
#
# 将 names 中的变量名加入 _global_names 集合
# ============================================================
def translate_global(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 global 语句:记录 global 变量名"""
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
if gn is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
if names is None:
return 0
n: t.CSizeT = names.__len__()
for i in range(n):
nm_node: ast.AST | t.CPtr = names.get(i)
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm.id is not None:
HT.add_global_name(trans, nm.id)
return 0
# ============================================================
# 翻译 Nonlocal 语句: nonlocal x, y
#
# 将 names 中的变量名加入 _nonlocal_names 集合
# ============================================================
def translate_nonlocal(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
"""
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
if nl is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
if names is None:
return 0
n: t.CSizeT = names.__len__()
for i in range(n):
nm_node: ast.AST | t.CPtr = names.get(i)
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm.id is not None:
# 查找父作用域中的变量 alloca,获取类型信息
var_ty: llvmlite.LLVMType | t.CPtr = None
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nm.id)
if var_alloca is not None and var_alloca.Ty is not None:
var_ty = var_alloca.Ty.Pointee
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
# 设为 None 让 add_nonlocal_name 回退为 i32,避免生成
# "bitcast ... to void*" / "load void, void*" 非法 IR
if var_ty is not None:
match var_ty:
case llvmlite.LLVMType.Void():
var_ty = None
case _:
pass
HT.add_nonlocal_name(trans, nm.id, var_ty)
return 0
# ============================================================
# 翻译表达式语句 Expr(value=Call(...))
# ============================================================
def translate_expr_stmt(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译表达式语句(printf 调用等)"""
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
if ex is None:
return 0
call_node: ast.AST | t.CPtr = ex.value
if call_node is None:
return 0
ck: int = call_node.kind()
if ck != ast.ASTKind.Call:
return 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
func_node: ast.AST | t.CPtr = cl.func
if func_node is None:
return 0
func_name: str = HandlesExpr.get_func_name(func_node)
if func_name is None:
return 0
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
if string.strcmp(func_name, "printf") == 0:
trans.ExprCallH.HandlePrintfCall(cl)
elif string.strcmp(func_name, "print") == 0:
trans.ExprCallH.HandlePrintCall(cl)
else:
# 通用函数调用(返回值丢弃)
trans.ExprCallH.HandleCall(call_node)
return 0
# ============================================================
# 预扫描:为局部变量提前创建 alloca
# ============================================================
def pre_scan_allocas(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描语句中的 AnnAssign,提前创建 alloca
返回新增的变量数
"""
if node is None:
return 0
return trans.AnnAssignH.PreScan(node)
# ============================================================
# 预扫描:Global/Nonlocal 声明(Python 作用域语义)
#
# Python 中 global/nonlocal 声明对整个函数作用域生效,与声明
# 位置无关。必须在翻译任何赋值之前注册 global/nonlocal 名称,
# 否则 global 声明前的赋值会错误创建局部变量遮蔽全局。
# ============================================================
def pre_scan_scope_decls(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Global:
return translate_global(trans, node)
if k == ast.ASTKind.Nonlocal:
return translate_nonlocal(trans, node)
return 0
# ============================================================
# 翻译 break 语句
# ============================================================
def translate_break(trans: HT.Translator | t.CPtr) -> int:
"""翻译 break 语句:跳转到循环 end 块"""
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if builder is None or func is None:
return 0
# 发射 br 到 break 目标
if trans._break_bb is not None:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, trans._break_bb)
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
return 0
# ============================================================
# 翻译 continue 语句
# ============================================================
def translate_continue(trans: HT.Translator | t.CPtr) -> int:
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if builder is None or func is None:
return 0
# 发射 br 到 continue 目标
if trans._continue_bb is not None:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, trans._continue_bb)
# 创建死代码 BB,用于后续语句
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
return 0
# ============================================================
# 获取语句类型名(调试用)
# ============================================================
def get_stmt_kind_name(node: ast.AST | t.CPtr) -> str:
"""获取语句类型名"""
if node is None:
return None
return node.type_name()