~jasper/type_stack_calc

ref: 6aca66fb1a7cf1e10f7dd3263f04537c8ff37590 type_stack_calc/type_stack_calc/base/function.py -rw-r--r-- 3.7 KiB
6aca66fb — Jasper den Ouden Apparently `to_c` can already read ahead one, hopefully its this simple... 1 year, 1 month 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
#  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.base.named import Named
from type_stack_calc.base.n_args import BaseNArgs

from type_stack_calc.to_c import ToC

def listing_do_c_args(gen, n, prep, ctx):
    for _i in range(n):
        ret = []
        ToC((ret.append, prep, ctx)).c_1(gen)
        yield ret

class BaseFunctionVariant(BaseNArgs):

    @property
    def c_name(self):
        assert isinstance(self.parent.c_name, str), (self, self.parent, self.parent.c_name, type(self), type(self.parent))
        return self.parent.c_name

    # extract, extract_top uses `n` value.

    precedence = ['*', '%', '/', '+', '-',
                  '<<', '>>',
                  '<', '<=', '>', '>=', '==', '!=',
                  '&', '^', '|', '&&', '||']

    def to_c(self, tc, gen):
        """Convert function variant/to C. Uses context a bit to see if parenthesis are needed.
NOTE: does the real work of counting arguments."""
        parent = self.parent
        if p_to_c := getattr(parent, 'to_c', None):  # (its definition overrides)
            p_to_c(tc, gen)
            return
        prep, ctx = tc[1:]
        s = ""
        # NOTE: compiling into string, because reversing below
        # Makes doing it "stream-wise" hopeless..
        # NOTE: if we want it stream wise need to run it the other way round and tag the functions?
        if ctx == ';':
            s += prep
        cname, n = self.c_name, self.n  #  Get number or arguments, c name.
        if isinstance(n, int):
            infix, surround = parent.infix, True
            if infix:  # For infixed, look at precedence.
                p = self.precedence
                surround = ctx in ('(', ';') or cname not in p \
                    or ctx not in p \
                    or p.index(cname) >= p.index(ctx)
            else:  # Not infix, start with name.
                s += cname

            if surround:
                s += '('  # Infix-separated arguments. (, for functions)

            if infix is True:  # Interpret `infix`.
                infix = " " + cname + " "
            elif not isinstance(infix, str):
                assert infix is False
                infix = ", "

            if n > 0:  # The arguments come from the generator.
                c_outputs = listing_do_c_args(gen, n,
                                              self[1], cname or '(')
                # Need it reversed.
                c_outputs = reversed(list(c_outputs))
                s += infix.join(''.join(cl) for cl in c_outputs)

            if surround:
                s += ")"
            tc[0](s)
        else:
            tc[0]("MISSING N {}".format(self.n))

class BaseFunction(Named):
    definitional, is_const = True, True

    def __init__(self, name=None, args=None, infix=False, with_vars=False,
                 destructive=False, definitional=False, tp='method'):
        Named.__init__(self, name)
        self.n    = args if isinstance(args, int) else len(args)
        self.args = args if isinstance(args, (tuple, list)) else None

        self.infix, self.with_vars = infix, with_vars
        self.destructive, self.definitional = destructive, definitional
        self.fun_tp = tp

    def tp_calc(self, _sc, _args, _vs):
        assert False, "You must define `tp_calc` if deriving form `BaseFunction`."
        # return (self.tp(sc, args), (self, args))

    def __repr__(self):
        return "{}:{}:{}".format(self.repr_name, self.seen_name or "", self.n)