from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator import ast import llvmlite.ir as ir class ExprUtils: def __init__(self, translator: "Translator"): self.Trans = translator def GetOpSymbol(self, Op): OpMap = { ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', ast.MatMult: '@', } return OpMap.get(type(Op), None) def GetUnaryOpSymbol(self, Op): OpMap = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} return OpMap.get(type(Op), None) def GetComparatorSymbol(self, Op): OpMap = { ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', ast.In: 'in', ast.NotIn: 'not in', } return OpMap.get(type(Op), None) def _get_var_class(self, node, Gen): if isinstance(node, ast.Name): VarName = node.id return Gen.var_struct_class.get(VarName) if isinstance(node, ast.Attribute): AttrName = node.attr return Gen.var_struct_class.get(AttrName) return None def _try_operator_overLoad(self, ClassName, op_name, obj_val, Gen, other_val=None): FullMethodName = f'{ClassName}.{op_name}' if not Gen._has_function(FullMethodName): FullMethodName = f'{ClassName}.{op_name}__' if Gen._has_function(FullMethodName): func = Gen._get_function(FullMethodName) call_args = [obj_val] if other_val is not None: call_args.append(other_val) if len(func.ftype.args) == len(call_args): for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): if expected_type != actual_val.type: if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") result = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") return result return None def _llvm_type_to_detailed_string(self, llvm_type, var_name=""): info = { 'name': "unknown", 'size': 0, 'signed': False, 'ptr': False } if isinstance(llvm_type, ir.IntType): info['size'] = llvm_type.width // 8 info['signed'] = True if llvm_type.width == 8: info['name'] = "char" elif llvm_type.width == 16: info['name'] = "short" elif llvm_type.width == 32: info['name'] = "int" elif llvm_type.width == 64: info['name'] = "long long" else: info['name'] = f"int{llvm_type.width}" elif isinstance(llvm_type, ir.DoubleType): info['size'] = 8 info['signed'] = True info['name'] = "double" elif isinstance(llvm_type, ir.FloatType): info['size'] = 4 info['signed'] = True info['name'] = "float" elif isinstance(llvm_type, ir.PointerType): info['size'] = 8 info['signed'] = False info['ptr'] = True pointee_info = self._llvm_type_to_detailed_string(llvm_type.pointee) info['name'] = f"{pointee_info['name']}*" elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): size = 0 for elem in llvm_type.elements: elem_info = self._llvm_type_to_detailed_string(elem) size += elem_info['size'] info['size'] = size info['signed'] = False if isinstance(llvm_type, ir.IdentifiedStructType): info['name'] = llvm_type.name else: info['name'] = "struct" elif isinstance(llvm_type, ir.ArrayType): elem_info = self._llvm_type_to_detailed_string(llvm_type.element) info['size'] = elem_info['size'] * llvm_type.count info['signed'] = elem_info['signed'] info['name'] = f"{elem_info['name']}[]" elif isinstance(llvm_type, ir.VoidType): info['size'] = 0 info['signed'] = False info['name'] = "void" else: info['size'] = 0 info['signed'] = False info['name'] = str(llvm_type) return info def _infer_expr_llvm_type_full(self, node): Gen = self.Trans.LlvmGen if isinstance(node, ast.Constant): if isinstance(node.value, bool): return ir.IntType(32) elif isinstance(node.value, int): return ir.IntType(32) elif isinstance(node.value, float): return ir.DoubleType() elif isinstance(node.value, str): if getattr(node, 'kind', None) == 'u': return ir.PointerType(ir.IntType(16)) return ir.PointerType(ir.IntType(8)) return ir.IntType(32) elif isinstance(node, ast.Name): if node.id in Gen.variables: var_ptr = Gen.variables[node.id] if isinstance(var_ptr.type, ir.PointerType): return var_ptr.type.pointee return var_ptr.type if node.id in Gen._reg_values: return Gen._reg_values[node.id].type return ir.IntType(32) elif isinstance(node, ast.Attribute): attr_name = node.attr if attr_name in self.Trans.SymbolTable: AttrInfo = self.Trans.SymbolTable[attr_name] if getattr(AttrInfo, 'IsEnumMember', None): return ir.IntType(32) return ir.IntType(32) elif isinstance(node, ast.BinOp): left_type = self._infer_expr_llvm_type_full(node.left) right_type = self._infer_expr_llvm_type_full(node.right) if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): return ir.DoubleType() if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): return ir.PointerType(ir.IntType(8)) return ir.IntType(32) elif isinstance(node, ast.UnaryOp): return self._infer_expr_llvm_type_full(node.operand) elif isinstance(node, ast.Subscript): val_type = self._infer_expr_llvm_type_full(node.value) if isinstance(val_type, ir.PointerType): if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: return ir.IntType(8) if isinstance(val_type.pointee, ir.ArrayType): return ir.PointerType(val_type.pointee.element) return val_type.pointee if isinstance(val_type, ir.ArrayType): return val_type.element if isinstance(val_type, ir.IntType): return ir.IntType(8) return ir.IntType(32) elif isinstance(node, ast.Call): if isinstance(node.func, ast.Name): func_name = node.func.id if Gen._has_function(func_name): fn = Gen._get_function(func_name) return fn.function_type.return_type if func_name == 'len': return ir.IntType(32) if func_name == 'sizeof': return ir.IntType(32) if func_name == 'ord': return ir.IntType(32) if func_name == 'chr': return ir.IntType(8) if func_name == 'int': return ir.IntType(32) if func_name == 'float' or func_name == 'double': return ir.DoubleType() elif isinstance(node.func, ast.Attribute): if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': if node.func.attr == 'Deref': return ir.IntType(64) if isinstance(node.func.value, ast.Name) and node.func.value.id == 't': if node.func.attr == 'CChar': return ir.PointerType(ir.IntType(8)) return ir.IntType(32) elif isinstance(node, ast.Compare): return ir.IntType(1) elif isinstance(node, ast.BoolOp): return ir.IntType(1) elif isinstance(node, ast.IfExp): return self._infer_expr_llvm_type_full(node.body) elif isinstance(node, ast.Attribute): return ir.PointerType(ir.IntType(8)) return ir.IntType(32) def _collect_names(self, node, bound, free=None): """收集 AST 节点中的绑定变量和自由变量 Args: node: AST 节点 bound: 集合,收集绑定变量(ast.Store 上下文) free: 集合,收集自由变量(ast.Load 上下文),可为 None """ if free is None: free = set() if isinstance(node, ast.Name): if isinstance(node.ctx, ast.Store): bound.add(node.id) elif isinstance(node.ctx, ast.Load): free.add(node.id) elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): # 这些节点有自己的作用域,不递归进入 # 但需要收集参数名作为 bound if hasattr(node, 'args') and node.args: for arg in node.args.args: bound.add(arg.arg) elif getattr(node, '_fields', None): for field in node._fields: value = getattr(node, field, None) if isinstance(value, list): for item in value: if isinstance(item, (ast.stmt, ast.expr)): self._collect_names(item, bound, free) elif isinstance(value, (ast.stmt, ast.expr)): self._collect_names(value, bound, free)