chronaxis.core.expression_integer_v4
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""将版本4整数编码、位选取和显式数值类型转换编译为冻结节点。23mod及位操作在单位为1的64位整数域工作,位号在编译时校验并固化。4显式cast先确定输入的物理尺度,再选择结果dtype。编译只访问声明与纯常量,5逐点的溢出、域错误和精度失败交给各自的参考/数组内核处理。6"""78from dataclasses import replace9from . import unit_registry as units10from .expression import _node, ExprNode, contains_host_call11from .expression_math_v4 import check_integer_leaves12from .numeric import INTEGER_BOUNDS13from .types import SignalDType as D141516CAST_TYPES = {'to_int64': D.INT64, 'to_uint64': D.UINT64, 'to_float64': D.FLOAT64}17INTEGER_KERNELS = frozenset(('mod', 'bit_test', 'bit_extract', 'to_int64', 'to_uint64'))18INTEGER_FUNCTIONS = INTEGER_KERNELS | {'to_float64'} # 浮点目标复用现有精确to_float核。192021def _require_word(compiler, child, call):22 """核对64位整数及数值尺度1,可接受等价的无量纲单位表达式。2324 参数: compiler为本次编译器,child为数值节点,call定位错误。25 返回: None。异常: ValueError为非整数、未知单位、带物理单位或非1倍率。26 """27 unit = units.resolve_unit(child.unit)28 one = units.resolve_unit('1')29 if (child.dtype not in INTEGER_BOUNDS or unit is None or unit.kind != one.kind30 or unit.scale != one.scale or unit.offset != one.offset):31 compiler._error(call, 'mod与位操作只接受单位1的int64或uint64;请显式转换数值和类型')323334def _bit_parameter(compiler, child, call):35 """读取可在编译期确定的无量纲整数,位置与宽度边界由调用处统一判定。3637 参数: compiler为本次编译器,child为位号或宽度节点,call定位错误。38 返回: 原生int。异常: ValueError为依赖运行数据或静态数值本身无效。39 """40 _require_word(compiler, child, call)41 if child.aliases or contains_host_call(child):42 compiler._error(call, '位号、起点与宽度必须是编译期整数')43 # 配置字面量及无依赖表达式按同一数值协议检查,不执行任意Python。44 from .expression_reference import _evaluate45 value = _evaluate(child, {}, {}).value46 if not value.valid:47 compiler._error(call, '位参数没有有效的编译期整数值')48 return value.value495051def compile_integer(compiler, call):52 """编译mod、位操作或精确cast,冻结整数策略与编译期位参数。5354 参数: compiler为v4编译器,call为已登记名称的裸调用AST。55 返回: ExprNode;cast结果按所选尺度保持目标dtype,位索引不构造运行列。56 异常: ValueError为签名、输入类型/单位、位参数、常量越界或隐式混合定宽。57 """58 name = call.func.id59 arity = 1 if name in CAST_TYPES else 3 if name == 'bit_extract' else 260 if name not in INTEGER_FUNCTIONS or len(call.args) != arity or call.keywords:61 compiler._error(call, f'{name}需要{arity}个位置参数')62 args = tuple(compiler.visit(arg) for arg in call.args)63 check_integer_leaves(compiler, args, call)64 child = args[0]65 if name in CAST_TYPES:66 if child.dtype not in (*INTEGER_BOUNDS, D.FLOAT64):67 compiler._error(call, '显式数值类型转换只接受数值,枚举需先用enum_code')68 # 1500mV的信号默认对应1.5V,转int不能截断;先显式to_unit(x,"mV")69 # 时输入尺度是mV,转int得到1500mV。外层不能再把它当作裸字面量重写。70 if not child.unit_explicit:71 child = compiler._canonical(child, call)72 op = 'to_float' if name == 'to_float64' else name73 result = _node(op, CAST_TYPES[name], child.unit, (child,), unit_explicit=child.unit_explicit)74 return compiler._known_node(replace(result, constant=False, typed_constant=False, conversion_promoted=False))75 _require_word(compiler, child, call)76 if name == 'mod':77 right = args[1]78 _require_word(compiler, right, call)79 # 两个纯整数字面量无信号锚点,按能容纳正大数的共同定宽适配;80 # 两个不同定宽的信号不能自动升为float,用户须先明确目标类型。81 if all(arg.constant or arg.typed_constant for arg in args):82 dtype = D.UINT64 if any(arg.dtype is D.UINT64 for arg in args) else D.INT6483 anchor = ExprNode('const', dtype, '1', 'verified', value=0, constant=True)84 child, right = (compiler._context(arg, anchor, call, arithmetic=True) for arg in args)85 else:86 child = compiler._context(child, right, call, arithmetic=True)87 right = compiler._context(right, child, call, arithmetic=True)88 if child.dtype is not right.dtype:89 compiler._error(call, 'mod的int64/uint64输入须先显式转换到同一整数类型')90 return compiler._known_node(_node('mod', child.dtype, '1', (child, right)))91 # 位0是最低位。start=0,width=64允许取得完整补码;任何移位的起点最多63。92 start = _bit_parameter(compiler, args[1], call)93 width = 1 if name == 'bit_test' else _bit_parameter(compiler, args[2], call)94 if not (0 <= start < 64 and 1 <= width <= 64 - start):95 compiler._error(call, '位号须在0到63之间,宽度须为正且起点加宽度不超过64')96 result = _node(name, D.BOOL if name == 'bit_test' else D.UINT64, '1', (child,), value=(start, width))97 return compiler._known_node(replace(result, constant=False, typed_constant=False, conversion_promoted=False))98