~jasper/type_stack_calc

ref: 84f5ae07ac5b8dfc401bde572d7cdc95a5d2e5fe type_stack_calc/type_stack_calc/call/if_call.py -rw-r--r-- 2.4 KiB
84f5ae07 — Jasper den Ouden minor 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#  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 = []  # Collect things that might be wrong.
        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), \
                "Outputs of `().if` must have same stack size."
            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))