309 lines
12 KiB
Plaintext
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()
|