M doc/other/type_calc_process.dot => doc/other/type_calc_process.dot +9 -7
@@ 26,8 26,9 @@ Note2: there is a lot of logic about types,\nnot shown here!"
ufun [ label="user defined\nfunction" tooltip="Arguments and Code object used to make one" ]
ifun [ label="inbuilt function\ndefined by language"
tooltip="some get the raw type stack, which include variable objects not-unpacked. So variables can be set." ]
- ifun -> "quite a bit\nwith types(sets)"
- macro [ label="macro\naccesses\nraw stuff" tooltip="Stuff like if, code-parser. Probably should merge with word editor."]
+ ifun -> lot_w_types
+
+ lot_w_types [ label="quite a bit\nwith types(sets)" shape=box ]
stack [ shape=diamond
label = "type stack"
@@ 49,17 50,18 @@ Note2: there is a lot of logic about types,\nnot shown here!"
{ component variable } -> actionable
stack -> actionable [ style=dashed
+ xlabel="(input)"
tooltip="if method, the value the component is from is passed along." ]
- word_editor [ label="inbuilt word editor\n(rarely)"
- tooltip="basically just the components-of-object exposer" ]
+ raw_tp_calc [ label="raw\ntype calc"
+ tooltip="{} () code-section parser, components-of-object .expose" ]
actionable [ label="actionable value" tooltip="Have to do more than just put on stack." ]
- actionable -> { ufun ifun word_editor macro }
- word_editor -> words [ taillabel="add/remove\ncoming words" style=dashed ]
+ actionable -> { ufun ifun raw_tp_calc }
+ raw_tp_calc -> words [ taillabel="add/remove\ncoming words" style=dashed ]
- {ifun ufun_calc} -> stack [ taillabel=result style=dashed ]
+ {ifun ufun_calc raw_tp_calc} -> stack [ taillabel=result style=dashed ]
"function variants" -> ufun_calc [ style=dashed dir=both tooltip="set or get" ]
M test/integermath.py => test/integermath.py +3 -4
@@ 40,7 40,6 @@ from type_stack_calc.sc_parser import parser
from type_stack_calc.intro import intro
from type_stack_calc.ib.scope import scopify
-def ignore(_x): pass
vs = scopify(intro)
assert vs.get('Tp')
@@ 49,17 48,17 @@ def is_single(got, x):
return tuple(got[0][:2]) == (x,x)
for i in range(10):
- got, = StackCalc().tp_calc(parser(f"{i}"), vs, [], ignore)
+ got = list(StackCalc().tp_calc(parser(f"{i}"), vs, []))[-1][0]
assert is_single(got, i), (i, got)
# Introduce this function.
-StackCalc().tp_calc(parser("(x) {x x *}.fun sqr.set ;"), vs, [], ignore)
+list(StackCalc().tp_calc(parser("(x) {x x *}.fun sqr.set ;"), vs, []))
sym_cnt, run_cnt = 0, 100
for i in range(run_cnt):
val, s = add_n_stuff()
sym_cnt += len(s.split())
- got = StackCalc().tp_calc(parser(s), vs, [], ignore)
+ got = list(StackCalc().tp_calc(parser(s), vs, []))[-1]
assert len(got) == 1, (got, s)
got = got[0]
assert is_single(got, val), f"Mismatch tc:{got} vs {val}\n{s}"
M type_stack_calc/Main.py => type_stack_calc/Main.py +2 -2
@@ 119,7 119,7 @@ class Main(StackCalc):
self.want.remove(a[1:])
self.max_stage_n = max(map(self.want, self.stages.get))
else: # An actual input file to deal with, with _current_ setup.
- vs, tc_code = scopify(intro), []
+ vs = scopify(intro)
with open(a) as fd:
s = fd.read()
@@ 131,7 131,7 @@ class Main(StackCalc):
code = list(parser(s))
self.stage('parsed', a, " ".join(code))
- stack = self.tp_calc(code, vs, [], tc_code.append)
+ *tc_code, stack = self.tp_calc(code, vs, [])
tc_code = [c1 for c1 in tc_code if c1 is not None]
for n, el in enumerate(tc_code): # Note their existence.
if fun := getattr(el, 'notify_real', None): fun()
M type_stack_calc/call/c_fun.py => type_stack_calc/call/c_fun.py +1 -1
@@ 35,7 35,7 @@ class CFunDef:
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)
+ *_tc_code, tps = sc.tp_calc(inp_tps, vs, [])
tps = [(t.val if isinstance(t, BaseComponent) else t) for t in tps]
# TODO check if `tps` is all usable types.
M type_stack_calc/call/if_call.py => type_stack_calc/call/if_call.py +14 -15
@@ 14,9 14,9 @@ from type_stack_calc.tp.bool import TpBool
class IfCall:
"""Code objects have a `.if` are set to this. Produces an IfBlock if needed."""
- mac, n, fun_tp = True, 3, 'method'
+ n, fun_tp = 3, 'method'
- def tp_calc(self, sc, _code, vs, stack, into):
+ def tp_calc(self, sc, vs, stack):
assert len(stack) >= 3, \
f"If needs three blocks, the condition, if-true and if false. Got {stack}"
then, otherwise, cond = stack[:3]
@@ 30,34 30,33 @@ class IfCall:
assert not any(wrongs), "If:\n" + "\n".join(wrongs)
- tc_cond = []
- cond_got = sc.tp_calc(cond, vs, [], tc_cond.append)
+ *tc_cond, cond_got = sc.tp_calc(cond, vs, [])
assert len(cond_got) == 1, \
f"Only one boolean-like value, got: {cond_got}"
cond_val = cond_got[0]
if isinstance(cond_val, BaseComponent): # (not using variables)
- cond_val = cond_val.val
+ cond_val = cond_val.val # TODO can it even happen?
if isinstance(cond_val, TpIntersection):
assert len(cond_val) == 1
cond_val = cond_val[0]
assert isinstance(cond_val, TpBool), cond_val
- case = cond_val.case
+ c_case = cond_val.case
- if isinstance(case, bool): # Just one branch.
+ # TODO ideally stack passed does not need to be empty.
+ if isinstance(c_case, bool): # Just one branch.
# 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 case else otherwise, vs, [], into),
+ *tc_body, stack = sc.tp_calc(then if c_case else otherwise,
+ vs, [])
+ return stack, *tc_cond, *tc_body
else:
- assert case is None
- 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 c_case is None, "Not definite True/False but not None?"
+ *tc_t, if_t = sc.tp_calc(then, vs, [])
+ *tc_f, if_f = sc.tp_calc(otherwise, vs, [])
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))
+ return ret_stack, IfBlock(tc_cond, tc_t, tc_f, ret_stack)
M type_stack_calc/ib/args.py => type_stack_calc/ib/args.py +4 -4
@@ 14,14 14,14 @@ 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):
+ def raw_tp_calc(self, _sc, _code, _vs, stack):
return [self[0], '.' + self[1]], stack[:-1]
-class ExposeInserts:
+class ExposeInsertsCall:
"""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):
+ def raw_tp_calc(self, _sc, _code, vs, stack):
obj, args = stack[:2]
if getattr(obj, 'is_var', None): # Already a variable, fine.
varname, insert = obj.key, []
@@ 49,7 49,7 @@ class Args(BaseCode):
"""Access parts of the given object."""
return [obj.get_comp(key) for key in self]
- param_expose = ExposeInserts() # Exposes components as if variables.
+ param_expose = ExposeInsertsCall() # Exposes components as if variables.
param_if = IfCall() # If blocks. (blocks is only option)
M type_stack_calc/ib/loop.py => type_stack_calc/ib/loop.py +1 -3
@@ 42,14 42,12 @@ class LoopCall: # (used in call)
assert isinstance(body, list) and body.tp == '{', \
f"Not block/wrong type for Loop: {body}"
- tc_code = [] # Typecalc it, gather code result.
prev_vs = dict()
while True: # Do it until the type stabilizes. # TODO will it?
- sc.tp_calc(body, vs, [], tc_code.append)
+ *tc_code, _stack = sc.tp_calc(body, vs, [])
# Exact same condition for all variables.
if types_eq((e[1] for e in sorted(vs.items(), key=lambda e:e[0])),
(e[1] for e in sorted(prev_vs.items(), key=lambda e: e[0]))):
return ([vs['lr']] if 'lr' in vs else [],
LoopBlock(tc_code, vs))
prev_vs = vs.copy() # Update types things end up with.
- tc_code.clear() # Or one will appear for each time.
M type_stack_calc/ib/scope.py => type_stack_calc/ib/scope.py +4 -1
@@ 10,6 10,9 @@ from type_stack_calc.base.named import Named
from type_stack_calc.base.component import BaseComponent, BaseComponentSet
from type_stack_calc.ib.plain_component import PlainComponent
+def do_all(gen):
+ for _e in gen: pass
+
class ScopeVariableSet(BaseComponentSet): pass
# TODO separate: what the variable might be, as set by different places,
@@ 96,7 99,7 @@ class Scope(dict, Named):
def absorb(self, sc, code):
"""Run code to define constants in the space."""
assert not self.locked, "Can only absorb one, to extend use derive"
- sc.tp_calc(code, self, [], lambda _x:None)
+ do_all(sc.tp_calc(code, self, []))
self.locked = True # Cannot change afterwards.
def get_comp(self, name): # TODO provide some inbuilds?
M type_stack_calc/ib/tc_variant.py => type_stack_calc/ib/tc_variant.py +6 -8
@@ 98,8 98,6 @@ class TCVariant(Ided, BaseFunctionVariant):
for arg in self.inp_stack: # Notify input it was used as argument.
if fun := getattr(arg, 'notify_arg', None): fun(self.id)
- tc_code = [] # Gather type-calculated code in this.
-
# NOTE: it might be unclear what is being iterated, it is (should be) other functions that might call it itself back recurse with.
try_cnt, tp = 0, []
@@ 110,18 108,19 @@ class TCVariant(Ided, BaseFunctionVariant):
max_try_cnt = getattr(parent, f"max_try_cnt_{self.code_name}")
while True: # Calculate types it until the type stabilizes.
# Variables, same ach time, other functions is what changes.
- vs = parent.scope.sub(True, zip(args, inp), depth=self.depth + 1)
+ vs = parent.scope.sub(True, zip(args, inp),
+ name=self.parent.name + '_variant',
+ depth=self.depth + 1)
vs.get_comp('~r').set(ReturnCatchType(self_id))
# Type-calculate the code under these conditions & strip nonse.
- ret_stack = stack_calc.tp_calc(code, vs, [], tc_code.append)
+ *tc_code, ret_stack = stack_calc.tp_calc(code, vs, [])
tc_code = [c1 for c1 in tc_code if c1 is not None]
# If stack left at the end, assume it is returned values.
if len(ret_stack) > 0:
- extra = []
- stack_calc.tp_calc(['~r', '.set'], vs, ret_stack,
- extra.append)
+ *extra, _tp = stack_calc.tp_calc(['~r', '.set'], vs,
+ ret_stack)
tc_code = tc_code + [c1 for c1 in extra if c1 is not None]
assert isinstance(vs['~r'].val, ReturnCatchType), vs['~r']
tp = vs['~r'].val.ret_stack() # Fill return type.
@@ 159,7 158,6 @@ class TCVariant(Ided, BaseFunctionVariant):
# won't need it in any case?
return
self.unfinished = tp
- tc_code.clear() # Reset code, or it will appear for each time.
try_cnt += 1 # TODO log the number of rounds..
assert try_cnt < max_try_cnt, \
M type_stack_calc/ib/use.py => type_stack_calc/ib/use.py +2 -3
@@ 5,8 5,7 @@ class UseTpCalc:
Arguments for run are (stack_calc, vs, args)"""
fun_tp = 'method'
- def __init__(self, fun, with_vars=False, mac=False, n=None,
- name='anUseTpCalc'):
+ def __init__(self, fun, with_vars=False, n=None, name='anUseTpCalc'):
self.tp_calc = fun
- self.with_vars, self.mac, self.n = with_vars, mac, n
+ self.with_vars, self.n = with_vars, n
self.name = name
M type_stack_calc/intro/load.py => type_stack_calc/intro/load.py +4 -2
@@ 5,7 5,9 @@ from type_stack_calc.sc_parser import parser
from type_stack_calc.intro import intro
from type_stack_calc.ib.scope import scopify
-def _ignore(_c1): pass
+
+def do_all(gen):
+ for _e in gen: pass
class LoadCall(dict):
def __repr__(self): return "LoadCall{a dict}}"
@@ 20,7 22,7 @@ class LoadCall(dict):
p = Path(origin_path + path + ".tsc")
if p.exists():
new_vs = scopify(intro)
- sc.tp_calc(parser(p.read_text()), new_vs, [], _ignore)
+ do_all(sc.tp_calc(parser(p.read_text()), new_vs, []))
got = new_vs
break
assert got is not None, \
M type_stack_calc/intro/parse.py => type_stack_calc/intro/parse.py +3 -3
@@ 15,13 15,13 @@ def code_until_zero(code_iter, open_word, close_word):
class CodeParse(tuple):
"""Object that will parse a list-like code object.
Cuts right into the word stream, which are then not type calculated."""
- mac, n, is_const = True, 0, True
+ n, is_const = 0, True
fun_tp = 'plain'
- def tp_calc(self, _sc, code, _vs, _args, _into):
+ def raw_tp_calc(self, _sc, code, _vs, inp):
cls = self[0]
obj = cls(code_until_zero(code, cls.tp, cls.close))
- return ([obj],) # NOTE: code never appears in the tc code.
+ return [], inp[:-1] + [obj]
def __repr__(self): return "CodeParser"
M type_stack_calc/tp_calc.py => type_stack_calc/tp_calc.py +19 -20
@@ 42,7 42,7 @@ class StackCalc:
self.paths = [] if paths is None else paths
self.does = set()
- def deal_with_var(self, var, code, vs, stack, into):
+ def deal_with_var(self, var, code, vs, stack):
"""Gets variable, applies as function if relevant."""
val = var.val # For instance a function immediately called.
@@ 64,9 64,9 @@ class StackCalc:
if n is not None:
assert len(inp) == n, \
- f"Not enough arguments available {len(inp)} vs needed {n}\n {stack} {inp}"
+ f"Not enough arguments available {len(inp)} vs needed {n}\n {val}\n\n{stack} {inp}"
# Figure out the local variables that might be relevant.
- relevant_comp = dict()
+ relevant_comp = dict() # TODO relevant for what.
for a in inp:
if isinstance(a, ScopeVariable):
relevant_comp[id(a)] = a
@@ 77,13 77,12 @@ class StackCalc:
# If it won't deal with variables, extract the values for it.
if not getattr(val, 'with_vars', None):
inp = [(a.val if isinstance(a, BaseComponent) else a)
- for a in inp]
+ for a in inp]
assert not any(isinstance(a, BaseComponent) for a in inp)
# Actually calculate the type, return new stack and result.
- stack, *tc_code = (
- tp_fun(self, code, vs, inp, into)
- if getattr(val, 'mac', None) else
- tp_fun(self, vs, inp))
+ stack, *tc_code = tp_fun(self, vs, inp)
+ assert isinstance(stack, list), (val)
+ assert_acceptable_vals(tc_code, ".tp_calc output.")
assert_acceptable_vals(stack, inp, rest, code, var)
@@ 98,9 97,9 @@ class StackCalc:
return stack[:-1] + [var], var # No calculation needed.
- special_fun= {'+', '-', '*', '/', '%', '>', '<'}
+ special_fun = {'+', '-', '*', '/', '%', '>', '<'}
- def tp_calc(self, code, vs, stack, into): # (non-babysitting version)
+ def tp_calc(self, code, vs, stack):
"""Calculates types and also collects the calls again, with their types, some origins."""
code, inserted = iter(code), []
while True:
@@ 109,12 108,13 @@ class StackCalc:
else: # Next word from given code.
word = next(code, None)
if word is None:
- return stack
+ yield stack
+ return
val = interpret_word(word)
if val is not None: # It is a constant value.
stack.append(val)
- into(val) # Just put it in.
+ yield val # Just put it in.
continue
if word[:1] == '.' or word in self.special_fun: # It's a component.
@@ 132,14 132,13 @@ class StackCalc:
desc="Unacceptable value after component access.")
# It is a variable, or accesses something.
- if insert := getattr(got.val, 'insert_code', None):
- assert getattr(got.val, 'tp_calc', None) is None, "BUG: cannot have both `insert_code` and `tp_calc`."
- plus, stack = insert(self, code, vs, stack)
- inserted = plus + inserted
+ if raw_fun := getattr(got.val, 'raw_tp_calc', None):
+ assert getattr(got.val, 'tp_calc', None) is None, "BUG: cannot have both `raw_tp_calc` and `tp_calc`."
+ plus, stack, *tc_code = raw_fun(self, code, vs, stack)
+ inserted = plus + inserted # Can add-in some code.
+ yield from tc_code
else:
- stack, *otp = self.deal_with_var(got, code, vs, stack, into)
- assert_acceptable_vals(otp, "Producing type-calced-code.")
- for el in otp: # Insert the tc code.
- into(el)
+ stack, *tc_code = self.deal_with_var(got, code, vs, stack)
+ yield from tc_code # Insert the tc code.
assert_acceptable_vals(stack, got, code)