306 lines
15 KiB
Python
306 lines
15 KiB
Python
from __future__ import annotations
|
||
|
||
import ast
|
||
from typing import TYPE_CHECKING
|
||
import llvmlite.ir as ir
|
||
|
||
from lib.core.ConstEvaluator import ConstEvaluator
|
||
|
||
if TYPE_CHECKING:
|
||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||
|
||
|
||
class ConstEvalMixin:
|
||
"""常量表达式求值 Mixin
|
||
|
||
提供数组初始化常量构建与常量表达式求值能力。
|
||
"""
|
||
|
||
@staticmethod
|
||
def _bswap_constant_value(val: int, width: int) -> int:
|
||
"""编译期字节序交换"""
|
||
if width == 16:
|
||
return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF)
|
||
elif width == 32:
|
||
return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF)
|
||
elif width == 64:
|
||
return ((val & 0xFF) << 56) | ((val & 0xFF00) << 40) | ((val & 0xFF0000) << 24) | ((val & 0xFF000000) << 8) | ((val >> 8) & 0xFF000000) | ((val >> 24) & 0xFF0000) | ((val >> 40) & 0xFF00) | ((val >> 56) & 0xFF)
|
||
return val
|
||
|
||
def _BuildArrayInitConstants(self, value_node: ast.AST, ElemType: ir.Type, elem_type_node: ast.AST, ArrayCount: int, Gen: LlvmCodeGenerator, byte_order: str = '') -> list[ir.Constant] | None:
|
||
_zv: ir.Constant | None = Gen._zero_value_for_type(ElemType)
|
||
_fallback: ir.Constant = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined)
|
||
if not isinstance(value_node, (ast.List, ast.Set)):
|
||
return None
|
||
if isinstance(ElemType, ir.ArrayType):
|
||
constants: list[ir.Constant] = []
|
||
for elt in value_node.elts:
|
||
if isinstance(elt, (ast.List, ast.Set)):
|
||
inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen)
|
||
if inner_consts:
|
||
try:
|
||
constants.append(ir.Constant(ElemType, inner_consts))
|
||
except Exception: # fallback to _fallback on constant construction failure
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
while len(constants) < ArrayCount:
|
||
constants.append(_fallback)
|
||
return constants[:ArrayCount]
|
||
StructName: str | None = None
|
||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||
StructName = elem_type_node.id
|
||
constants = []
|
||
for elt in value_node.elts:
|
||
if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName:
|
||
const: ir.Constant | None = self.ClassHandler._BuildStructConstant(elt, StructName, Gen)
|
||
if const:
|
||
constants.append(const)
|
||
else:
|
||
constants.append(_fallback)
|
||
elif isinstance(elt, ast.Constant):
|
||
# 字符串常量:根据引号类型决定 i8 或 i8*
|
||
if isinstance(elt.value, str):
|
||
const: ir.Constant | None = self._BuildStringLiteralConstant(elt, ElemType, Gen)
|
||
if const:
|
||
constants.append(const)
|
||
else:
|
||
constants.append(_fallback)
|
||
else:
|
||
const = self._BuildScalarConstantUnified(elt, ElemType, Gen)
|
||
if const:
|
||
constants.append(const)
|
||
else:
|
||
constants.append(_fallback)
|
||
elif isinstance(elt, ast.UnaryOp):
|
||
const = self._BuildScalarConstantUnified(elt, ElemType, Gen)
|
||
if const:
|
||
constants.append(const)
|
||
else:
|
||
constants.append(_fallback)
|
||
elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr':
|
||
if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int):
|
||
try:
|
||
constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF))
|
||
except Exception: # fallback to _fallback on constant construction failure
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord':
|
||
if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1:
|
||
try:
|
||
constants.append(ir.Constant(ElemType, ord(elt.args[0].value)))
|
||
except Exception: # fallback to _fallback on constant construction failure
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
else:
|
||
const_val: int | float | str | None = self._try_eval_const_call(elt, Gen)
|
||
if const_val is not None:
|
||
try:
|
||
constants.append(ir.Constant(ElemType, const_val))
|
||
except Exception: # fallback to _fallback on constant construction failure
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
while len(constants) < ArrayCount:
|
||
constants.append(_fallback)
|
||
if byte_order == 'big' and isinstance(ElemType, ir.IntType) and ElemType.width in (16, 32, 64):
|
||
swapped: list[ir.Constant] = []
|
||
for c in constants:
|
||
if isinstance(c, ir.Constant) and isinstance(c.type, ir.IntType) and isinstance(c.constant, int):
|
||
swapped_val: int = self._bswap_constant_value(int(c.constant), ElemType.width)
|
||
swapped.append(ir.Constant(ElemType, swapped_val))
|
||
else:
|
||
swapped.append(c)
|
||
constants = swapped
|
||
return constants[:ArrayCount]
|
||
|
||
def _BuildStringLiteralConstant(self, node: ast.Constant, target_type: ir.Type, Gen: LlvmCodeGenerator) -> ir.Constant | None:
|
||
"""根据引号类型决定字符串常量的类型:
|
||
|
||
- 单引号单字符 → i8 (char 值)
|
||
- 双引号/单引号多字符/三重引号 → i8* (C 字符串指针)
|
||
- 空字符串 → 0 (None),传入 ptr 目标自动隐式转换
|
||
"""
|
||
if not isinstance(node.value, str):
|
||
return None
|
||
s: str = node.value
|
||
# 空字符串 → 0 (None)
|
||
if len(s) == 0:
|
||
try:
|
||
return ir.Constant(target_type, 0)
|
||
except Exception:
|
||
return None
|
||
# 获取源代码以判断引号类型
|
||
quote_char: str | None = None
|
||
is_triple: bool = False
|
||
col_offset: int = getattr(node, 'col_offset', 0)
|
||
node_lineno: int = getattr(node, 'lineno', 0)
|
||
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
|
||
# 因此在 lineno 和 lineno-1 两行中查找引号
|
||
for try_lineno in (node_lineno, node_lineno - 1):
|
||
source_line: str | None = Gen._get_source_line(try_lineno)
|
||
if source_line and col_offset < len(source_line):
|
||
ch: str = source_line[col_offset]
|
||
if ch in ("'", '"'):
|
||
quote_char = ch
|
||
if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'):
|
||
is_triple = True
|
||
break
|
||
# 判断是否为 char (i8):单引号、非三重、单字符
|
||
is_char: bool = (not is_triple) and (quote_char == "'") and (len(s) == 1)
|
||
if is_char:
|
||
# 单引号单字符 → i8
|
||
if isinstance(target_type, ir.IntType):
|
||
try:
|
||
return ir.Constant(target_type, ord(s))
|
||
except Exception:
|
||
return None
|
||
# 目标类型不是整数 → 类型不匹配
|
||
return None
|
||
else:
|
||
# 双引号/多字符/三重 → i8* (C 字符串)
|
||
if isinstance(target_type, ir.PointerType):
|
||
str_val: str = s + '\x00'
|
||
str_bytes: bytes = str_val.encode('utf-8')
|
||
arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes))
|
||
gv_name: str = f"str_const_{id(node)}"
|
||
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, arr_type, name=gv_name)
|
||
gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
|
||
gv.linkage = 'internal'
|
||
return ir.Constant(target_type, gv.get_reference())
|
||
# 目标类型不是指针 → 类型不匹配
|
||
return None
|
||
|
||
def _BuildScalarConstantUnified(self, node: ast.AST, target_type: ir.Type, Gen: LlvmCodeGenerator) -> ir.Constant | None:
|
||
"""统一的标量常量构建方法。
|
||
|
||
合并原 HandlesClassDef._BuildScalarConstant 与 HandlesImports._BuildScalarConstant 的特性:
|
||
- 支持 bool/int/float/str/ast.UnaryOp(USub)/ast.Name(True/False)
|
||
- 字符串处理委托给 _BuildStringLiteralConstant
|
||
- 显式拒绝 BaseStructType
|
||
- 全部 try/except 保护
|
||
"""
|
||
# 显式拒绝结构体类型
|
||
if isinstance(target_type, ir.BaseStructType):
|
||
return None
|
||
# 处理常量节点
|
||
if isinstance(node, ast.Constant):
|
||
# bool 必须在 int 之前判断(bool 是 int 的子类)
|
||
if isinstance(node.value, bool):
|
||
try:
|
||
return ir.Constant(target_type, 1 if node.value else 0)
|
||
except Exception:
|
||
return None
|
||
elif isinstance(node.value, int):
|
||
try:
|
||
return ir.Constant(target_type, node.value)
|
||
except Exception:
|
||
return None
|
||
elif isinstance(node.value, float):
|
||
try:
|
||
return ir.Constant(target_type, node.value)
|
||
except Exception:
|
||
return None
|
||
elif isinstance(node.value, str):
|
||
# 字符串处理委托给 _BuildStringLiteralConstant
|
||
const: ir.Constant | None = self._BuildStringLiteralConstant(node, target_type, Gen)
|
||
if const is not None:
|
||
return const
|
||
# 回退:直接创建字符串全局变量(i8*)
|
||
try:
|
||
return Gen._create_string_global(node.value)
|
||
except Exception:
|
||
return None
|
||
# 处理一元负号
|
||
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
|
||
if isinstance(node.operand, ast.Constant) and isinstance(node.operand.value, int):
|
||
try:
|
||
return ir.Constant(target_type, -node.operand.value)
|
||
except Exception:
|
||
return None
|
||
# 处理 True/False 名称节点
|
||
elif isinstance(node, ast.Name):
|
||
if node.id == 'True':
|
||
try:
|
||
return ir.Constant(target_type, 1)
|
||
except Exception:
|
||
return None
|
||
elif node.id == 'False':
|
||
try:
|
||
if isinstance(target_type, ir.PointerType):
|
||
return ir.Constant(target_type, None)
|
||
return ir.Constant(target_type, 0)
|
||
except Exception:
|
||
return None
|
||
return None
|
||
|
||
def _try_eval_const_call(self, node: ast.AST, Gen: LlvmCodeGenerator) -> int | None:
|
||
if isinstance(node, ast.Call):
|
||
func_name: str | None = None
|
||
if isinstance(node.func, ast.Name):
|
||
func_name = node.func.id
|
||
elif isinstance(node.func, ast.Attribute):
|
||
func_name = node.func.attr
|
||
if func_name:
|
||
arg_vals: list[int | float | str | None] = []
|
||
for arg in node.args:
|
||
v: int | float | str | None = self._try_eval_const_expr(arg, Gen)
|
||
if v is None:
|
||
return None
|
||
arg_vals.append(v)
|
||
if func_name == 'COLOR_RGB' and len(arg_vals) == 3:
|
||
r: int | float | str | None
|
||
g: int | float | str | None
|
||
b: int | float | str | None
|
||
r, g, b = arg_vals
|
||
return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r)
|
||
if func_name in Gen._DefineConstants:
|
||
return Gen._DefineConstants[func_name]
|
||
for key in Gen.functions:
|
||
if key.endswith(f'__{func_name}'):
|
||
return None
|
||
return None
|
||
return self._try_eval_const_expr(node, Gen)
|
||
|
||
def _try_eval_const_expr(self, node: ast.AST, Gen: LlvmCodeGenerator) -> int | float | str | None:
|
||
return ConstEvaluator.eval_with_symtab(node, self.SymbolTable)
|
||
|
||
def _BuildMultiDimArrayInitConstants(self, value_node: ast.AST, ArrayType: ir.ArrayType, Gen: LlvmCodeGenerator) -> list[ir.Constant] | None:
|
||
inner_type: ir.Type = ArrayType.element
|
||
count: int = ArrayType.count
|
||
elts: list[ast.AST] = list(value_node.elts) if hasattr(value_node, 'elts') else []
|
||
_zv: ir.Constant | None = Gen._zero_value_for_type(inner_type)
|
||
_fallback: ir.Constant = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined)
|
||
constants: list[ir.Constant] = []
|
||
for elt in elts:
|
||
if isinstance(inner_type, ir.ArrayType):
|
||
if isinstance(elt, (ast.List, ast.Set)):
|
||
inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen)
|
||
if inner_consts:
|
||
constants.append(ir.Constant(inner_type, inner_consts))
|
||
else:
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
elif isinstance(elt, ast.Constant):
|
||
const: ir.Constant | None = self._BuildScalarConstantUnified(elt, inner_type, Gen)
|
||
if const:
|
||
constants.append(const)
|
||
else:
|
||
constants.append(_fallback)
|
||
elif isinstance(elt, ast.UnaryOp):
|
||
const = self._BuildScalarConstantUnified(elt, inner_type, Gen)
|
||
if const:
|
||
constants.append(const)
|
||
else:
|
||
constants.append(_fallback)
|
||
else:
|
||
constants.append(_fallback)
|
||
while len(constants) < count:
|
||
constants.append(_fallback)
|
||
return constants[:count]
|