# Copyright (C) 2021 Jasper den Ouden. # # This is free software: you can redistribute it and/or modify # it under the terms of the Affero GNU General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. from type_stack_calc.ib.if_block import IfBlock from type_stack_calc.base.component import BaseComponent from type_stack_calc.tp.bool import BoolType, ConstBool class IfCall: """Code objects have a `.if` are set to this. Produces an IfBlock if needed.""" mac, n, fun_tp = True, 3, 'method' def tp_calc(self, sc, _code, vs, stack, into): assert len(stack) >= 3, \ f"If needs three blocks, the condition, if-true and if false. Got {stack}" then, otherwise, cond = stack[:3] wrongs = [] if not isinstance(cond, list) or cond.tp != '(': wrongs.append(f"wrong condition block: {cond}") if not isinstance(then, list) or then.tp != '{': wrongs.append(f"wrong then-block: {then}") if not isinstance(otherwise, list) or otherwise.tp != '{': wrongs.append(f"wrong otherwise-block: {otherwise}") assert not any(wrongs), "If:\n" + "\n".join(wrongs) tc_cond = [] cond_got = sc.tp_calc(cond, vs, [], tc_cond.append) assert len(cond_got) == 1, \ f"Only one boolean-like value, got: {cond_got}" cond_val = cond_got[0] if isinstance(cond_val, BaseComponent): cond_val = cond_val.val if isinstance(cond_val, ConstBool): # Just one of the cases. # NOTE: conditions may have destructive statements in there. for el in tc_cond: if el is not None: into(el) # Put in the conditions. # And put in one of the bodies. return sc.tp_calc(then if cond_val.b else otherwise, vs, [], into), else: assert isinstance(cond_val, BoolType), cond_got # Maybe drop this? tc_t, tc_f = [], [] # Run both sides. if_t = sc.tp_calc(then, vs, [], tc_t.append) if_f = sc.tp_calc(otherwise, vs, [], tc_f.append) assert len(if_f) == len(if_t) ret_stack = [f.smoosh(t) for f,t in zip(if_t, if_f)] return (ret_stack, IfBlock(tc_cond, tc_t, tc_f, ret_stack))