~jasper/type_stack_calc

ref: 6aca66fb1a7cf1e10f7dd3263f04537c8ff37590 type_stack_calc/type_stack_calc/ib/if_block.py -rw-r--r-- 2.4 KiB
6aca66fb — Jasper den Ouden Apparently `to_c` can already read ahead one, hopefully its this simple... 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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#  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.extractor import Extractor, StopMarker

def list_flatten(gen):
    for el in gen:
        if type(el) == list:
            for r_el in list_flatten(el): yield r_el
        else:
            yield el

def filter_none(lst): return [el for el in lst if el is not None]

class IfBlock:
    """`if_block.py`: `{..if..} {..else..} (..cond..).if` provider."""
    def __init__(self, cond, yes, no, ret_stack):
        self.cond, self.yes, self.no = map(filter_none, [cond, yes, no])
        self.stack = ret_stack

    def extract_cond(self, extractor, gen):
        lst = []
        e_c = Extractor((lst.append, extractor[1]))
        gen = reversed(self.cond)
        for el in gen:
            if el is not None:
                e_c._extract_1(gen, el)
        self.cond = list_flatten(lst)  # Remainder can stay.

    def extract(self, extractor, gen, _obj):
        self.extract_cond(extractor, gen)

        if len(self.stack) > 0:  # TODO permit multi-output stuff or not?
            assert len(self.stack) == 1
            tmp = extractor.tmp_var('if', self.stack[0])
            if deffer := getattr(tmp, 'deffer', None):
                extractor[1](deffer)
            if getattr(tmp, 'key', "")[:1] == '~':
                extractor[0](StopMarker)
            else:
                extractor[0](tmp)

            self.yes = [*self.yes, *tmp.setter]  # internals extracted later)
            self.no  = [*self.no, *tmp.setter]

        extractor[1](self)  # Thing itself extracts outside.

    def extract_top(self, extractor, gen, _obj):
        self.extract_cond(extractor, gen)
        extractor[0](self)  # Already on top, just place.

    # .yes and .no is done by `extracted_to_c`.
    def to_c(self, tc, _gen):
        wfile, prep = tc[:2]
        wfile(prep + "if(")
        tc.new_context(prep + "   ", '(').c(self.cond)
        wfile(") {")

        body_tc = tc.new_context(prep + "  ", ';')
        body_tc.extract_n_c(self.yes)
        if any(self.no):  # Only do non-empty elses.
            wfile(prep + "} else {")
            body_tc.extract_n_c(self.no)
            wfile(prep + "}")
        else:
            wfile(prep + "}")