# 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))