~jasper/type_stack_calc

ref: 0f08de824079bf5edc9438eb3d6e603aca3bf761 type_stack_calc/type_stack_calc/base/component.py -rw-r--r-- 5.9 KiB
0f08de82 — Jasper den Ouden Avoiding use of unnecessary variables.. Not quite there yet, not sure how to get rid of `return` when thats needed.. 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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#  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.simple_ib_fun import SimpleInbuildFunction
from type_stack_calc.base.n_args import BaseNArgs

from type_stack_calc.extractor import Extractor
from type_stack_calc.pe.drop import PostExtractDrop

from type_stack_calc.ib.plain_component import PlainComponent

from type_stack_calc.util.stack_check import assert_acceptable_vals

class BaseComponentSet(BaseNArgs):
    """Sets a variable."""
    with_vars, n = True, 2
    c_name, infix, fun_tp = '=', True, 'method'

    def __init__(self, component):
        self.component = component
        self.initial_set, self.definitional = False, False

    def deal_relevant_comp(self, rl, args):
        args[0].relevant_comp = rl
        for c in rl.values():
            if getattr(c, 'affects_comp', None) is None:
                c.affects_comp = dict()
            c.affects_comp[id(args[0])] = args[0]

    def extract(self, extractor, gen, tp):
        """Only needs extraction if specifying type now. Though can be specified to always do it."""
        # TODO return for instance should _never_ need extraction?
        if self.initial_set or extractor.always_extract_set:
            # Extract a bit.
            ilist = []
            # Extractor for internals that includes the component that may replace the temporary-variable.
            ext = Extractor((ilist.append, extractor[1]))
            extractor[1](self)  # This should get the component.
            ext.extract_1(gen)
            varlist = ilist.copy()  # Variables into non-extracted also.
            ext.extract_1_w_var(gen, self.component)  # And this is the value.
            extractor[1](ilist + [PostExtractDrop])
            extractor[0](varlist)  # ... which goes into the arguments.
        else:  # Plainly set in side.
            self.extract_top(extractor, gen, tp)

    def extract_top(self, extractor, gen, tp):
        extractor[0](self)
        extractor.extract_1(gen)
        extractor.extract_1_w_var(gen, self.component)

    def to_c(self, tc, gen):
        wfile, prep = tc[:2]
        var = next(gen)
        assert isinstance(var, BaseComponent), (self, self.component, var, list(gen))

        if var.key == '~r':  # ~ indicates inbuilt "weirdo variable".
            wfile("return ")
        else:
            if self.initial_set:
                #assert var.val is not None, var  # TODO
                wfile((var.val and var.val.c_name or f"Bug({var})") + " ")
            wfile(f"{var.key} = ")
        tc.new_context(prep, '(').c_1(gen)

    def tp_calc(self, sc, vs, args):
        to, component = args
        if isinstance(to, BaseComponent):  # If component, get the value.
            to = to.val
            assert not isinstance(to, BaseComponent), f"More than one layer of components? ({to})"

        assert_acceptable_vals((to,), component, vs,
                               desc="Setting variable")

        self.initial_set = component.sc_set(sc, to)
        self.definitional = getattr(to, 'definitional', None)
        assert id(component.access_obj.get_comp(component.key)) == id(component)
        #self.initial_set = c.access_obj.sc_set_param(sc, c, to)
        sc.does.add('something')  # Variables/components were modified.

        if not getattr(self, 'destructive', None):
            self.destructive = getattr(to, 'destructive', None) and 'setcomp'
        return [to], self

    def __repr__(self): return ".set"

class BaseComponent:
    """Handles (global)variables, members of access_objects.
NOTE: it doesn't access `.set`, `.glob` from the value because the methods for those are `with_vars`, so `deal_with_var` won't unpack the variables then."""

    def __init__(self, access_obj, key):
        self.val = None
        assert_acceptable_vals((access_obj,), key,
            desc="Making component object for {access_obj}, {key}")
        assert access_obj is not None, key
        self.access_obj, self.key = access_obj, key
        if key[0] == '~': self.destructive = 'returnlike'

    @property
    def param_set(self):
        """The 'method' that sets stuff."""
        return self._param_set_cls(self)
    param_ = param_set  # Alias to empty string.(Just a dot accesses it)
    @property
    def setter(self):
        return [self, self.param_set]

    @property  # TODO remove?
    def tp_stack(self): return [self.val]

    def _param_glob(self):
        """Ask for global variable."""
        assert False, f"Only local variables can ask to become globals. {self} ({type(self)})"

    param_glob = SimpleInbuildFunction(1, _param_glob, with_vars=True,
                                       name='glob')

    def get_comp(self, key):
        """Gets a component. Looks in the variable before the value!"""
        if got := getattr(self, f"param_{key}", None):
            return PlainComponent(key, got)
        assert_acceptable_vals((self.val,), desc='Getting component value invalid')
        return self.val.get_comp(key)

    def __repr__(self):
        assert not isinstance(self.val, BaseComponent), (type(self), self.key)
        return f"{self._repr_kind}:{self.key}:{self.val}"

    @property
    def c_name(self): return self.key

    def to_c(self, tc, _gen):
        """Produce C code, if constant, it's used and the variable name commented out."""
        val = self.val
        assert val is not None, self
        const_c = val.is_const and getattr(val, 'c_name', None)
        tc[0](const_c + f"/*{self.key}*/" if const_c else self.key)

    def sc_set(self, _sc, _to):  # Placeholder.
        """Sets variable to a value. Will notify stuff of the name, and set/smoosh the type.
Not actually defined in BaseComponent, defined downstream."""
        assert False, f"BUG: probably sc_set not defined for {self}"