Advertisement
HasteBin0

Python Pretty Expressions Module (V2)

Dec 27th, 2020 (edited)
296
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 18.59 KB | None | 0 0
  1. #!/usr/bin/python3
  2. from collections import deque, namedtuple
  3. from functools import reduce
  4. from math import prod
  5. from typing import *
  6.  
  7. """
  8. Op: + - * / % ** < > <=,≤ >=,≥ <> == !=,≠ !!,¬ &&,∧ ||,∨ << >> ~ & ^,⊕ | =,≔ ?,tn λ (λ)
  9. Source: https://pastebin.com/v2EkGWvr
  10. Normally, a language takes in text (source) and lexes it into bytecode.  That bytecode is then enacted by interpreting, transpiling, or compiling it.
  11. This module is intended for describing and executing calculations.  It's given a sort-of bytecode and it gives back a source text and the calculations' result.
  12. """
  13.  
  14. T_NUM_TYPE = Union[int, float]
  15. T_OP_TYPE = Union[T_NUM_TYPE, 'Op']
  16. T_OPERANDS_EVAL = Tuple[T_NUM_TYPE, ...]
  17. T_OPERANDS_NOT_EVAL = Tuple[T_OP_TYPE, ...]
  18. T_OP_FXN = Union[Callable[[T_OPERANDS_EVAL], T_OP_TYPE], Callable[[T_OPERANDS_NOT_EVAL, bool], T_OP_TYPE]]
  19.  
  20. _T1 = TypeVar('T1')
  21.  
  22.  
  23. def neighbors(x: Iterable[_T1], fill_item: _T1 = ...) -> Iterable[Tuple[_T1, _T1]]:
  24.     values = iter(x)
  25.     for first in values:
  26.         last = first
  27.         for v in values:
  28.             yield last, v
  29.             last = v
  30.         if last is first and fill_item is not Ellipsis:
  31.             yield fill_item, first
  32.             return
  33.  
  34.  
  35. def flat(elements: Iterable[Iterable[_T1]]) -> Iterable[_T1]:
  36.     for e in elements:
  37.         yield from e
  38.  
  39.  
  40. _don: Tuple[Tuple[str, Type['Op']], ...] = ()
  41. op_names: List[Tuple[str, Type['Op']]] = []
  42.  
  43.  
  44. def get_op_names() -> Tuple[Tuple[str, Type['Op']], ...]:
  45.     return tuple(_don)
  46.  
  47.  
  48. def is_op_name(name: str) -> bool:
  49.     return name in _don
  50.  
  51.  
  52. def base_f(v: T_OPERANDS_EVAL) -> 'Op':
  53.     return num(v[0])
  54.  
  55.  
  56. class Op:
  57.     _operands: T_OPERANDS_NOT_EVAL
  58.     _value: Optional[T_OP_TYPE]
  59.     _evaluated: bool = False
  60.     _fxn: T_OP_FXN = base_f
  61.     _fxn_name: str = 'f'
  62.     _repr_fxn: bool = False
  63.     _pre_eval_param: bool = True
  64.     _c_name: str = 'Op'
  65.  
  66.     def __init__(self, *operands: T_OP_TYPE, fxn: T_OP_FXN = ..., fxn_name: str = ..., repr_fxn: bool = ..., pep: bool = ...):
  67.         self._operands = operands
  68.         self._value = None
  69.         if fxn is not Ellipsis:
  70.             self._fxn = fxn
  71.         if fxn_name is not Ellipsis:
  72.             self._fxn_name = fxn_name
  73.         if repr_fxn is not Ellipsis:
  74.             self._repr_fxn = repr_fxn
  75.         elif self._c_name == 'Op':
  76.             self._repr_fxn = True
  77.         if pep is not Ellipsis:
  78.             self._pre_eval_param = pep
  79.  
  80.     def evaluate(self, redo: bool = False) -> T_OP_TYPE:
  81.         if not self._evaluated or redo:
  82.             fxn, operands = self._fxn, self._operands
  83.             self._value = (fxn(evaluate_operands(operands, redo, True)) if self._pre_eval_param else fxn(operands, redo))
  84.             self._evaluated = True
  85.         return self._value
  86.  
  87.     def to_num(self, redo: bool = False) -> T_NUM_TYPE:
  88.         return self.evaluate(redo).to_num(redo)
  89.  
  90.     def to_var(self, redo: bool = False) -> Optional['Variable']:  # Use with caution:  the variable returned might not mirror self.evaluate()
  91.         return self.evaluate(redo).to_var(redo)
  92.  
  93.     def _s_ops(self) -> Iterable[str]:
  94.         return (x.__str__() for x in self._operands)
  95.  
  96.     def __str__(self) -> str:
  97.         return '({})'.format(' '.join((self._fxn_name, *self._s_ops())))
  98.  
  99.     @property
  100.     def source(self) -> str:
  101.         return self.__str__()
  102.  
  103.     def _r_ops(self) -> Iterable[str]:
  104.         return (x.__repr__() for x in self._operands)
  105.  
  106.     def __repr__(self) -> str:
  107.         params = deque(map(repr, self._operands))
  108.         op = self.__class__  # works for derivative classes
  109.  
  110.         def new(attr_name: str, p_name: str):
  111.             if getattr(op, attr_name) != (p_value := getattr(self, attr_name)):
  112.                 params.append(f'{p_name} = {repr(p_value)}')
  113.  
  114.         if self._repr_fxn:
  115.             new('_fxn', 'fxn')
  116.             new('_fxn_name', 'fxn_name')
  117.         new('_repr_fxn', 'repr_fxn')
  118.         new('_pre_eval_param', 'pep')
  119.         return '{}({})'.format(self._c_name, ', '.join(params))
  120.  
  121.     @property
  122.     def py_source(self) -> str:
  123.         return self.__repr__()
  124.  
  125.     @property
  126.     def evaluated(self):
  127.         return self._evaluated
  128.  
  129.     @property
  130.     def value(self) -> Optional[T_OP_TYPE]:
  131.         return self._value
  132.  
  133.     @property
  134.     def fxn(self) -> T_OP_FXN:
  135.         return self._fxn
  136.  
  137.     @property
  138.     def c_name(self) -> str:
  139.         return self._c_name
  140.  
  141.     @classmethod
  142.     def add_to_names(cls):
  143.         op_names.append((cls._c_name, cls))
  144.  
  145.  
  146. Op.add_to_names()
  147.  
  148.  
  149. def evaluate_operands(operands: Iterable[Op], redo: bool, make_tuple: bool) -> Union[Tuple[T_NUM_TYPE, ...], Iterable[T_NUM_TYPE]]:
  150.     g = (x.to_num(redo) for x in operands)
  151.     return tuple(g) if make_tuple else g
  152.  
  153.  
  154. class Base(Op):  # no-op/number
  155.     _evaluated = True
  156.     _c_name = 'num'
  157.  
  158.     def __init__(self, value: T_NUM_TYPE):
  159.         Op.__init__(self)
  160.         self._value = value
  161.  
  162.     def evaluate(self, _ = ...) -> T_NUM_TYPE:
  163.         return self._value
  164.  
  165.     def to_num(self, _ = ...) -> T_NUM_TYPE:
  166.         return self._value
  167.  
  168.     def to_var(self, _: bool = ...) -> Optional['Variable']:
  169.         return None
  170.  
  171.     def __str__(self) -> str:
  172.         return str(self._value)
  173.  
  174.     def __repr__(self) -> str:
  175.         return '{}({})'.format(self._c_name, repr(self._value))
  176.  
  177.  
  178. def number_else0(x: Op = ...) -> Op:
  179.     return num(0) if x is Ellipsis else x
  180.  
  181.  
  182. NoOp = num = Base
  183. num.add_to_names()
  184.  
  185.  
  186. class DOp(Op):
  187.     def __init__(self, *operands: Op):
  188.         Op.__init__(self, *operands)
  189.  
  190.  
  191. def add_f(v: T_OPERANDS_EVAL) -> Op:
  192.     return num(sum(v))
  193.  
  194.  
  195. class Add(DOp):
  196.     _fxn = add_f
  197.     _fxn_name = '+'
  198.     _c_name = 'add'
  199.  
  200.  
  201. add = Add
  202. add.add_to_names()
  203.  
  204.  
  205. def sub_f(v: T_OPERANDS_EVAL) -> Op:
  206.     return num(next((vs := iter(v)), 0) - sum(vs))
  207.  
  208.  
  209. class Sub(DOp):
  210.     _fxn = sub_f
  211.     _fxn_name = '-'
  212.     _c_name = 'sub'
  213.  
  214.  
  215. sub = Sub
  216. sub.add_to_names()
  217.  
  218.  
  219. def neg_f(v: T_OPERANDS_EVAL) -> Op:
  220.     return num(-(v[0]))
  221.  
  222.  
  223. class Neg(DOp):
  224.     _fxn = neg_f
  225.     _fxn_name = '-'
  226.     _c_name = 'neg'
  227.  
  228.     def __str__(self) -> str:
  229.         return '-' + str(self._operands[0])
  230.  
  231.  
  232. neg = Neg
  233. neg.add_to_names()
  234.  
  235.  
  236. def mul_f(v: T_OPERANDS_EVAL) -> Op:
  237.     return num(prod(v))
  238.  
  239.  
  240. class Mul(DOp):
  241.     _fxn = mul_f
  242.     _fxn_name = '*'
  243.     _c_name = 'mul'
  244.  
  245.  
  246. mul = Mul
  247. mul.add_to_names()
  248.  
  249.  
  250. def div0_safe(fxn: T_OP_FXN) -> T_OP_FXN:
  251.     def safe_fxn(v: T_OPERANDS_EVAL) -> Op:
  252.         try:
  253.             return fxn(v)
  254.         except ZeroDivisionError:
  255.             return num(0.00)  # The C language returns 0.0f for 0.0f / 0.0f.
  256.  
  257.     return safe_fxn
  258.  
  259.  
  260. @div0_safe
  261. def div_f(v: T_OPERANDS_EVAL) -> Op:
  262.     return num(next(vs := iter(v), 0) / prod(vs))
  263.  
  264.  
  265. class Div(DOp):
  266.     _fxn = div_f
  267.     _fxn_name = '/'
  268.     _c_name = 'div'
  269.  
  270.  
  271. div = Div
  272. div.add_to_names()
  273.  
  274.  
  275. def fdiv2(a, b):
  276.     return a // b
  277.  
  278.  
  279. @div0_safe
  280. def fdiv_f(v: T_OPERANDS_EVAL) -> Op:
  281.     return num(reduce(fdiv2, v))
  282.  
  283.  
  284. class Fdiv(DOp):
  285.     _fxn = fdiv_f
  286.     _fxn_name = '//'
  287.     _c_name = 'fdiv'
  288.  
  289.  
  290. fdiv = Fdiv
  291. fdiv.add_to_names()
  292.  
  293.  
  294. def mod2(a, b):
  295.     return a % b
  296.  
  297.  
  298. @div0_safe
  299. def mod_f(v: T_OPERANDS_EVAL) -> Op:
  300.     return num(reduce(mod2, v))
  301.  
  302.  
  303. class Mod(DOp):
  304.     _fxn = mod_f
  305.     _fxn_name = '%'
  306.     _c_name = 'mod'
  307.  
  308.  
  309. mod = Mod
  310. mod.add_to_names()
  311.  
  312.  
  313. def pow2(a, b):
  314.     return a ** b
  315.  
  316.  
  317. @div0_safe
  318. def power_f(v: T_OPERANDS_EVAL) -> Op:
  319.     return num(reduce(pow2, v))  # left to right, yes.
  320.  
  321.  
  322. class Pow(DOp):
  323.     _fxn = power_f
  324.     _fxn_name = '**'
  325.     _c_name = 'xpow'
  326.  
  327.  
  328. xpow = Pow
  329. xpow.add_to_names()
  330.  
  331.  
  332. @div0_safe
  333. def bpm_f(v: T_OPERANDS_EVAL) -> Op:
  334.     return num(pow(v[0], v[1], v[2]))
  335.  
  336.  
  337. class BPM(Op):
  338.     _fxn = bpm_f
  339.     _fxn_name = '**%'
  340.     _c_name = 'bpm'
  341.  
  342.     def __init__(self, base: Op, power: Op, modulus: Op):
  343.         Op.__init__(self, base, power, modulus)
  344.  
  345.  
  346. bpm = BPM
  347. bpm.add_to_names()
  348.  
  349.  
  350. def les_f(v: T_OPERANDS_EVAL) -> Op:
  351.     return num(1 * all(a < b for (a, b) in neighbors(v)))
  352.  
  353.  
  354. class Les(DOp):
  355.     _fxn = les_f
  356.     _fxn_name = '<'
  357.     _c_name = 'les'
  358.  
  359.  
  360. les = Les
  361. les.add_to_names()
  362.  
  363.  
  364. def gtr_f(v: T_OPERANDS_EVAL) -> Op:
  365.     return num(1 * all(a > b for (a, b) in neighbors(v)))
  366.  
  367.  
  368. class Gtr(DOp):
  369.     _fxn = gtr_f
  370.     _fxn_name = '>'
  371.     _c_name = 'gtr'
  372.  
  373.  
  374. gtr = Gtr
  375. gtr.add_to_names()
  376.  
  377.  
  378. def leq_f(v: T_OPERANDS_EVAL) -> Op:
  379.     return num(1 * all(a <= b for (a, b) in neighbors(v)))
  380.  
  381.  
  382. class Leq(DOp):
  383.     _fxn = leq_f
  384.     _fxn_name = '<='
  385.     _c_name = 'leq'
  386.  
  387.  
  388. leq = Leq
  389. leq.add_to_names()
  390.  
  391.  
  392. def geq_f(v: T_OPERANDS_EVAL) -> Op:
  393.     return num(1 * all(a >= b for (a, b) in neighbors(v)))
  394.  
  395.  
  396. class Geq(DOp):
  397.     _fxn = geq_f
  398.     _fxn_name = '>='
  399.     _c_name = 'geq'
  400.  
  401.  
  402. geq = Geq
  403. geq.add_to_names()
  404.  
  405.  
  406. def cmp2(a, b) -> int:
  407.     return 0 if a < b else (1 if a == b else 2)
  408.  
  409.  
  410. def cmp_f(v: T_OPERANDS_EVAL) -> Op:
  411.     r = set(cmp2(a, b) for (a, b) in neighbors(v))
  412.     return num(r.pop() if len(r) == 1 else 3)
  413.  
  414.  
  415. class Cmp(DOp):
  416.     _fxn = cmp_f
  417.     _fxn_name = '<>'
  418.     _c_name = 'cmp'
  419.  
  420.  
  421. cmp = Cmp
  422. cmp.add_to_names()
  423.  
  424.  
  425. def equ_f(v: T_OPERANDS_EVAL) -> Op:
  426.     return num(1 * all(a == b for (a, b) in neighbors(v)))
  427.  
  428.  
  429. class Equ(DOp):
  430.     _fxn = equ_f
  431.     _fxn_name = '=='
  432.     _c_name = 'equ'
  433.  
  434.  
  435. equ = Equ
  436. equ.add_to_names()
  437.  
  438.  
  439. def neq_f(v: T_OPERANDS_EVAL) -> Op:
  440.     return num(1 * all(a != b for (a, b) in neighbors(v)))
  441.  
  442.  
  443. class Neq(DOp):
  444.     _fxn = neq_f
  445.     _fxn_name = '!='
  446.     _c_name = 'neq'
  447.  
  448.  
  449. neq = Neq
  450. neq.add_to_names()
  451.  
  452.  
  453. def xnot_f(v: T_OPERANDS_EVAL) -> Op:
  454.     return num(1 * (not v[0]))
  455.  
  456.  
  457. class Xnot(DOp):
  458.     _fxn = xnot_f
  459.     _fxn_name = '!'
  460.     _c_name = 'xnot'
  461.  
  462.     def __str__(self) -> str:
  463.         return self._fxn_name + str(self._operands[0])
  464.  
  465.  
  466. xnot = Xnot
  467. xnot.add_to_names()
  468.  
  469.  
  470. def xand_f(v: T_OPERANDS_EVAL) -> Op:  # unit product
  471.     return num(1 * all(v))
  472.  
  473.  
  474. class Xand(DOp):
  475.     _fxn = xand_f
  476.     _fxn_name = '&&'
  477.     _c_name = 'xand'
  478.  
  479.  
  480. xand = Xand
  481. xand.add_to_names()
  482.  
  483.  
  484. def yor_f(v: T_OPERANDS_EVAL) -> Op:
  485.     return num(1 * any(v))
  486.  
  487.  
  488. class Yor(DOp):
  489.     _fxn = yor_f
  490.     _fxn_name = '||'
  491.     _c_name = 'yor'
  492.  
  493.  
  494. yor = Yor
  495. yor.add_to_names()
  496.  
  497.  
  498. def shift_left_f(v: T_OPERANDS_EVAL) -> Op:
  499.     return num(next((vs := iter(v)), 0) << sum(vs))
  500.  
  501.  
  502. class ShiftLeft(DOp):
  503.     _fxn = shift_left_f
  504.     _fxn_name = '<<'
  505.     _c_name = 'shift_left'
  506.  
  507.  
  508. shift_left = ShiftLeft
  509. shift_left.add_to_names()
  510.  
  511.  
  512. def shift_right_f(v: T_OPERANDS_EVAL) -> Op:
  513.     return num(next((vs := iter(v)), 0) >> sum(vs))
  514.  
  515.  
  516. class ShiftRight(DOp):
  517.     _fxn = shift_right_f
  518.     _fxn_name = '>>'
  519.     _c_name = 'shift_right'
  520.  
  521.  
  522. shift_right = ShiftRight
  523. shift_right.add_to_names()
  524.  
  525.  
  526. def bnot_f(v: T_OPERANDS_EVAL) -> Op:
  527.     return num(~(v[0]))
  528.  
  529.  
  530. class Bnot(DOp):
  531.     _fxn = bnot_f
  532.     _fxn_name = '~'
  533.     _c_name = 'bnot'
  534.  
  535.  
  536. bnot = Bnot
  537. bnot.add_to_names()
  538.  
  539.  
  540. def band2(a, b):
  541.     return a & b
  542.  
  543.  
  544. def band_f(v: T_OPERANDS_EVAL) -> Op:
  545.     return num(reduce(band2, v))
  546.  
  547.  
  548. class Band(DOp):
  549.     _fxn = band_f
  550.     _fxn_name = '&'
  551.     _c_name = 'band'
  552.  
  553.  
  554. band = Band
  555. band.add_to_names()
  556.  
  557.  
  558. def xor2(a, b):
  559.     return a ^ b
  560.  
  561.  
  562. def xor_f(v: T_OPERANDS_EVAL) -> Op:
  563.     return num(reduce(xor2, v))
  564.  
  565.  
  566. class Xor(DOp):
  567.     _fxn = xor_f
  568.     _fxn_name = '^'
  569.     _c_name = 'xor'
  570.  
  571.  
  572. xor = Xor
  573. xor.add_to_names()
  574.  
  575.  
  576. def bor2(a, b):
  577.     return a | b
  578.  
  579.  
  580. def bor_f(v: T_OPERANDS_EVAL) -> Op:
  581.     return num(reduce(bor2, v))
  582.  
  583.  
  584. class Bor(DOp):
  585.     _fxn = bor_f
  586.     _fxn_name = '|'
  587.     _c_name = 'bor'
  588.  
  589.  
  590. bor = Bor
  591. bor.add_to_names()
  592.  
  593.  
  594. def show_f(v: T_OPERANDS_EVAL) -> Op:
  595.     return num(v[0])
  596.  
  597.  
  598. class Show(DOp):
  599.     _fxn = show_f
  600.     _fxn_name = '='
  601.     _c_name = 'show'
  602.  
  603.     def __str__(self) -> str:
  604.         return '({})'.format(' '.join((self._fxn_name, *('[{} {}]'.format(str(operand), operand.to_num()) for operand in self._operands))))
  605.  
  606.  
  607. show = Show
  608. show.add_to_names()
  609.  
  610.  
  611. class Namespace:
  612.     _SYMBOL_STACK: Deque[Dict[str, Op]] = deque()
  613.     _names: Dict[str, Op]
  614.  
  615.     def __init__(self):
  616.         self._names = {}
  617.  
  618.     def __del__(self):
  619.         self._names.clear()  # Protect variables.
  620.  
  621.     def __enter__(self):  # Please don't enter the same ns twice.
  622.         self._SYMBOL_STACK.append(self._names)
  623.         self._names = {}
  624.  
  625.     def __exit__(self, *_):
  626.         self._names = self._SYMBOL_STACK.pop()
  627.  
  628.     def set(self, name: str, value: Op):
  629.         self._names[name] = value
  630.  
  631.     def get(self, name: str, default: Op = ...) -> Op:
  632.         for nss in reversed(self._SYMBOL_STACK):
  633.             try:
  634.                 return nss[name]
  635.             except KeyError:
  636.                 pass
  637.         return number_else0(default)
  638.  
  639.     def has(self, name: str) -> bool:
  640.         return any(name in nss for nss in reversed(self._SYMBOL_STACK))
  641.  
  642.  
  643. def new_ns() -> Namespace:
  644.     return Namespace()
  645.  
  646.  
  647. gns = new_ns()  # general namespace
  648.  
  649.  
  650. class Variable(Op):
  651.     _c_name = 'var'
  652.     _name: str
  653.  
  654.     def __init__(self, name: str):
  655.         Op.__init__(self, self)
  656.         self._name = name
  657.  
  658.     def evaluate(self, redo: bool = False) -> T_OP_TYPE:
  659.         if not self._evaluated or redo:
  660.             self._value = self.get()
  661.             self._evaluated = True
  662.         return self._value
  663.  
  664.     def to_var(self, _: bool = ...) -> Optional['Variable']:
  665.         return self
  666.  
  667.     def __str__(self) -> str:
  668.         return self._name
  669.  
  670.     def __repr__(self) -> str:
  671.         return "{}({})".format(self._c_name, repr(self._name))
  672.  
  673.     @property
  674.     def v_name(self) -> str:
  675.         return self._name
  676.  
  677.     def get(self, default: Op = ..., ns: Namespace = gns) -> Op:
  678.         return ns.get(self._name, default)
  679.  
  680.     def set(self, x: Op, ns: Namespace = gns):
  681.         ns.set(self._name, x)
  682.  
  683.  
  684. var = Variable
  685. var.add_to_names()
  686.  
  687. T_SET_PAIR = Tuple[Variable, Op]
  688. TT_SET_PAIR = Tuple[T_SET_PAIR, ...]
  689.  
  690.  
  691. def xset_f(v: TT_SET_PAIR, redo: bool) -> Op:
  692.     for v_named, new_value in v:
  693.         v_named.to_var(redo).set(num(new_value.to_num(redo)))
  694.     return num(v[0][1].to_num())  # already (re)calculated
  695.  
  696.  
  697. class Xset(Op):
  698.     _operands: TT_SET_PAIR
  699.     _fxn_name = ':='
  700.     _pre_eval_param = False
  701.     _c_name = 'xset'
  702.  
  703.     def __init__(self, *operands: T_SET_PAIR):
  704.         Op.__init__(self, *operands)
  705.  
  706.     def __str__(self) -> str:
  707.         return '({})'.format(' '.join((self._fxn_name, *(f'[{str(n)} {str(v)}]' for (n, v) in self._operands))))
  708.  
  709.     def __repr__(self) -> str:
  710.         return '{}({})'.format(self._c_name, ', '.join((f'({repr(n)}, {repr(v)})' for (n, v) in self._operands)))
  711.  
  712.  
  713. xset = Xset
  714. xset.add_to_names()
  715.  
  716. T_TN_OPERAND = Tuple[Op, Op]
  717. TT_TN_OPERAND = Tuple[TT_SET_PAIR, ...]
  718.  
  719. tnf_type = namedtuple('tnf_type', ('case', 'r_value'))
  720.  
  721.  
  722. def tn_f(sw: Op, v: TT_TN_OPERAND, default: Op, redo: bool) -> Op:
  723.     switch = sw.to_num(redo)
  724.     for x in v:
  725.         clause = tnf_type(*x)
  726.         if switch == clause.case.to_num(redo):
  727.             return num(clause.r_value.to_num(redo))
  728.     return num(default.to_num(redo))
  729.  
  730.  
  731. class Tn(Op):
  732.     _operands: TT_TN_OPERAND
  733.     _fxn_name = '?'
  734.     _pre_eval_param = False
  735.     _c_name = 'tn'
  736.     _switch: Op
  737.     _default: Op
  738.  
  739.     def __init__(self, value: Op, *operands: T_TN_OPERAND, otherwise: Op = ...):
  740.         Op.__init__(self, *operands)
  741.         self._switch = value
  742.         self._default = number_else0(otherwise)
  743.  
  744.     def evaluate(self, redo: bool = False) -> T_OP_TYPE:
  745.         if not self._evaluated or redo:
  746.             self._value = tn_f(self._switch, self._operands, self._default, redo)
  747.             self._evaluated = True
  748.         return self._value
  749.  
  750.     def __str__(self) -> str:
  751.         return '({})'.format(' '.join((self._fxn_name, str(self._switch), *(f'[{str(n)} {str(v)}]' for (n, v) in self._operands), f'[{str(self._default)}]')))
  752.  
  753.     def __repr__(self) -> str:
  754.         return '{}({})'.format(self._c_name, ', '.join((repr(self._switch), *(f'({repr(n)}, {repr(v)})' for (n, v) in self._operands), *((f'otherwise = {repr(df)}',) if (df := self._default).to_num() != 0 else ()))))
  755.  
  756.  
  757. tn = Tn
  758. tn.add_to_names()
  759.  
  760.  
  761. class Lambda(Op):
  762.     _operands: Tuple[Variable, ...]
  763.     _fxn_name = 'λ'
  764.     _c_name = 'lam'
  765.     _var: Variable
  766.     _expr: Op
  767.  
  768.     def __init__(self, name: str, *parameters: Variable, expression: Op):
  769.         Op.__init__(self, *parameters)
  770.         self._var = Variable(name)
  771.         self._expr = expression
  772.  
  773.     def evaluate(self, redo: bool = False) -> T_OP_TYPE:
  774.         if not self._evaluated or redo:
  775.             self._var.set(self)
  776.             self._value = self
  777.             self._evaluated = True
  778.         return self._value
  779.  
  780.     def to_num(self, redo: bool = False) -> T_NUM_TYPE:
  781.         return Call(self).to_num(redo)
  782.  
  783.     def to_var(self, _: bool = ...) -> Optional['Variable']:
  784.         return self._var
  785.  
  786.     def __str__(self) -> str:
  787.         return '({})'.format(' '.join((self._fxn_name, self.v_name, '({})'.format(' '.join(p.v_name for p in self._operands)), str(self._expr))))
  788.  
  789.     def __repr__(self) -> str:
  790.         return '{}({})'.format(self._c_name, ', '.join((repr(self.v_name), *((repr(p.v_name) for p in self._operands)), f'expression = {repr(self._expr)}')))
  791.  
  792.     @property
  793.     def v_name(self):
  794.         return self._var.v_name
  795.  
  796.     def invoke(self) -> Op:
  797.         return self._expr.evaluate(True)  # return bit_shr may be variable.
  798.  
  799.  
  800. lam = Lambda
  801. lam.add_to_names()
  802.  
  803.  
  804. class Call(Op):
  805.     _fxn_name = '(λ{})'
  806.     _c_name = 'call'
  807.     _l_fxn: Lambda
  808.  
  809.     def __init__(self, fxn: Lambda, *operands: Op):
  810.         Op.__init__(self, *operands, fxn_name = Call._fxn_name.format(fxn.v_name))
  811.         self._l_fxn = fxn
  812.  
  813.     def evaluate(self, redo: bool = False) -> T_OP_TYPE:
  814.         if not self._evaluated or redo:
  815.             with new_ns():
  816.                 fxn = self._l_fxn
  817.                 n: Variable
  818.                 # noinspection PyProtectedMember
  819.                 for n, v in zip(fxn._operands, self._operands):
  820.                     n.to_var(redo).set(v.evaluate(redo))  # lazy
  821.                 self._value = fxn.invoke()
  822.             self._evaluated = True
  823.         return self._value
  824.  
  825.     def to_var(self, _: bool = ...) -> Optional['Variable']:
  826.         return None
  827.  
  828.     def __str__(self) -> str:
  829.         return '({})'.format(' '.join((self._fxn_name, '({})'.format(' '.join(self._s_ops())))))
  830.  
  831.     def __repr__(self) -> str:
  832.         return '{}({})'.format(self._c_name, ', '.join((repr(self.v_name), '({})'.format(', '.join(self._r_ops())),)))
  833.  
  834.     @property
  835.     def v_name(self):
  836.         return self._l_fxn.v_name
  837.  
  838.  
  839. call = Call
  840. call.add_to_names()
  841.  
  842. _don = tuple(op_names)
  843. op_names: Tuple[Tuple[str, Type['Op']], ...] = tuple(op_names)
  844.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement