f79cb89cedc994e8df39c2e79cfa3185e5559ff4 — Jasper den Ouden 4 months ago bf21887
C functions now made from objects instead of interpreting the strings of an Args. Also more comments.
M examples/c_fun.tsc => examples/c_fun.tsc +5 -1
@@ 1,4 1,8 @@

"sqr" (f64 !destructive) (x) (f64).c_fun sqr.set ;
-10 10 Set.Range f64.set ; 

#"sqr" (f64 !destructive) (x) (f64).c_fun sqr.set ;

f64 {f64} "c_sqr" (x).c_fun sqr.set

3 5 2 * + sqr

M type_stack_calc/base/function.py => type_stack_calc/base/function.py +1 -1
@@ 79,7 79,7 @@ NOTE: does the real work of counting arguments."""
            tc[0]("MISSING N {}".format(self.n))

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

    def __init__(self, name=None, args=None, infix=False, with_vars=False,
                 destructive=False, definitional=False, tp='method'):

M type_stack_calc/call/c_fun.py => type_stack_calc/call/c_fun.py +22 -21
@@ 1,42 1,43 @@

"""External C functions, defining and the objects."""

from type_stack_calc.base.component import BaseComponent
from type_stack_calc.ib.ib_fun import InbuildFunction

class CFun(InbuildFunction):

    def __init__(self, c_name, ret_tp, args, inp_tp, tp='plain'):
    def __init__(self, fun_tp, args, c_name, ret_tp, inp_tps):
        # TODO check that inputs are valid types.
        InbuildFunction.__init__(self, args, ret_tp, tp=tp)
        InbuildFunction.__init__(self, args, ret_tp, tp=fun_tp)

        self._c_name, self.ret_tp, self.inp_tp = c_name, ret_tp, inp_tp 
        self._c_name, self.ret_tp, self.inp_tp = c_name, ret_tp, inp_tps
        self.n = len(self.args)
        self.fun_tp = tp
        self.fun_tp = fun_tp

    @property  # TODO what's this for?
    def c_name(self): return self._c_name

    def tp_calc(self, sc, vs, inp):
        assert len(inp) == self.n
        assert all(a.settable(v) for a, v in zip(self.inp_tp, inp))
        if wrong := next(((a, v) for a, v in zip(self.inp_tp, inp)
                          if a.settable(v)), None):
            assert False, f"Cannot convert {v} to {a}"
        return InbuildFunction.tp_calc(self, sc, vs, inp)

def _list_types(vs, lst):  # TODO check that it is a type.
    return [getattr(val, 'of', val)
            for val in (vs[name].val for name in lst)]

class CFunDef:
    fun_tp = 'method'
    def __init__(self, tp):
        self.set_fun_tp = tp

    def _tp(self, vs, inp, args, ret, c_name):
        """Extracts values from the names, they should be valid types!"""
        assert isinstance(c_name, str), c_name
        assert isinstance(ret, type(inp)) # NOTE: Args but import conflict.
        assert isinstance(args, type(inp))
        ret = CFun(c_name, _list_types(vs, ret), args,
                  _list_types(vs, inp),
        return [ret], ret
    n = 4
    def tp_calc(self, _sc, vs, args):
        return self._tp(vs, *args)
    def tp_calc(self, sc, vs, inp):
        ret_tp, inp_tps, c_name, args = inp
        assert isinstance(c_name, str), f"Expected string for C function name, got {c_name}\n{inp}"
        assert type(args) != type(inp_tps), "`inp_tps` should be Code sections, presumably it's and Args section."
        # Calculate argument types.
        tps = sc.tp_calc(inp_tps, vs, [], lambda _dontcare:None)
        tps = [(t.val if isinstance(t, BaseComponent) else t) for t in tps]
        # TODO check if `tps` is all usable types.

        ret = CFun(self.set_fun_tp, args, c_name, ret_tp, tps)
        return [ret],

M type_stack_calc/ib/args.py => type_stack_calc/ib/args.py +10 -7
@@ 11,17 11,21 @@ from type_stack_calc.call.if_call import IfCall
from type_stack_calc.call.c_fun import CFunDef

class Via(tuple):
    """Makes a variable refer to a component by inserting the component-accessing-code."""
    definitional = True

    def insert_code(self, _sc, _code, _vs, stack):
        return [self[0], '.' + self[1]], stack[:-1]

class ExposeInserts:
    """Uses `Via` so that variables can access components instead.
Will defect if a temporary variable is needed."""

    def insert_code(self, _code, _sc, vs, stack):
        obj, args = stack[:2]
        if getattr(obj, 'is_var', None):  # Already a variable, fine.
            varname, insert = obj.key, []
        else:  # Needs a tempory variable name.
        else:  # Needs a temporary variable name.
            varname, n = "tmp1", 1  # TODO not-yet-set variables might interfere?
            while varname in vs:
                n = n + 1

@@ 37,19 41,18 @@ class Args(BaseCode):
    """Arguments objects, it has:
* `.if`: the `Args` content is a conditional statement the top of which must be Boolean. Expects two `Code` objects if-true and if-false.
* `.access`: put a whole bunch of components from top object on the stack. TODO entirely untested.
* `.expose`: similar, but instead makes the symbols as if they access the object."""
* `.expose`: similar, but instead rewrites in as if to access the object."""
    tp, close = '(', ')'
    pref_glob = False

    def param_access(self, obj):  # TODO not tested.
    def param_access(self, obj):  # TODO probably implement by as-if-direct-accesses
        """Access parts of the given object."""
        return [obj.get_comp(key) for key in self]

    param_expose = ExposeInserts()
    param_expose = ExposeInserts()  # Exposes components as if variables.

    param_if = IfCall()
    param_if = IfCall()  # If blocks. (blocks is only option)

    param_c_function = CFunDef('plain')
    param_c_function = CFunDef('plain')  # External C functions.
    param_c_method   = CFunDef('method')

    param_c_fun, param_c_meth = param_c_function, param_c_method