feat: better code structure

This commit is contained in:
Ferrari Martino Giordano
2024-03-13 10:03:18 +01:00
parent 67e57d5372
commit 79f539a290
3 changed files with 506 additions and 488 deletions
+412
View File
@@ -0,0 +1,412 @@
import logging
import os
import common as doc
def doc_app_state(state, tab=""):
res = ""
if "+Threads" in state:
for i, tname in enumerate(state["+Threads"]):
if tname[0] == "+":
ch = "├─●" if i < len(state["+Threads"]) - 1 else "╰─●"
res += f"{tab} {ch} {tname[1:]}\n"
return res
def __doc_obj__(label, obj, id):
node = f' {id} [label="{label}&#92;n{obj["Class"]} | '
return node
def __doc_common_gam__(name, obj, edges, thread):
inputs = ""
outputs = ""
if "InputSignals" in obj:
for i, (l, sig) in enumerate(obj["InputSignals"].items()):
alias = doc.signal_alias(l, sig)
mtype = doc.signal_type(sig)
datasrc = sig["DataSource"]
edges.append(
doc.edge(
doc.signal(datasrc, alias, mtype),
doc.signal(name, l, mtype),
thread,
)
)
if i != 0:
inputs += " | "
inputs += f"<in_{doc.format_name(l)}> {l}"
if "OutputSignals" in obj:
for i, (l, sig) in enumerate(obj["OutputSignals"].items()):
alias = doc.signal_alias(l, sig)
mtype = doc.signal_type(sig)
datasrc = sig["DataSource"]
edges.append(
doc.edge(
doc.signal(name, l, mtype),
doc.signal(datasrc, alias, mtype),
thread,
)
)
if i != 0:
outputs += " | "
outputs += f"<out_{doc.format_name(l)}> {l}"
return "{ {" + inputs + " } | { " + outputs + "} }", edges
def __doc_triggered_iogam__(name, obj, edges, thread):
signals = ""
if "InputSignals" in obj:
for i, (l, sig) in enumerate(obj["InputSignals"].items()):
alias = doc.signal_alias(l, sig)
mtype = doc.signal_type(sig)
datasrc = sig["DataSource"]
edges.append(
doc.edge(
doc.signal(datasrc, alias, mtype),
doc.signal(name, l, mtype),
thread,
)
)
if i > 1:
signals += " | "
signals += f"<in_{doc.format_name(l)}> "
if i == 0:
signals += "Trigger | { { "
else:
signals += f"{l}"
signals += " } | { "
if "OutputSignals" in obj:
for i, (l, sig) in enumerate(obj["OutputSignals"].items()):
alias = doc.signal_alias(l, sig)
mtype = doc.signal_type(sig)
datasrc = sig["DataSource"]
edges.append(
doc.edge(
doc.signal(name, l, mtype),
doc.signal(datasrc, alias, mtype),
thread,
)
)
if i != 0:
signals += " | "
signals += f"<out_{doc.format_name(l)}> {l} "
signals += " } }"
node = f'{name} [tooltip=" TriggeredIOGAM::{name} ", label="{name}&#92;nTriggeredIOGAM | {signals}", style=filled, fillcolor="#eee"];\n'
return node, edges
def __doc_iogam__(id, obj, edges, thread):
node = ""
if "InputSignals" in obj and "OutputSignals" in obj:
inputs, outputs = obj["InputSignals"], obj["OutputSignals"]
output_names = list(outputs.keys())
input_names = list(inputs.keys())
j = 0
input_size = 0
output_size = 0
i = 0
irow = ""
orow = ""
counter = 0
while i < len(inputs) and j < len(outputs):
irelcount = 0
orelcount = 0
bold = False
while input_size <= output_size and i < len(inputs):
in_label = input_names[i]
input = inputs[in_label]
if irow:
irow += " | "
input_size += doc.signal_byte_size(input)
i += 1
alias = doc.signal_alias(in_label, input)
mtype = doc.signal_type(input)
if mtype[2]:
bold = True
irow += f"<in_{irelcount}> {doc.type_to_string(mtype)}"
datasrc = input["DataSource"]
edges.append(
doc.edge(
doc.signal(datasrc, alias, mtype),
doc.signal(f"{id}_{counter}", f"{irelcount}", mtype),
thread,
)
)
irelcount += 1
while output_size < input_size and j < len(outputs):
out_label = output_names[j]
output = outputs[out_label]
output_size += doc.signal_byte_size(output)
if orow:
orow += " | "
j += 1
alias = doc.signal_alias(out_label, output)
mtype = doc.signal_type(output)
if mtype[2]:
bold = True
orow += f"<out_{orelcount}> {doc.type_to_string(mtype)}"
datasrc = output["DataSource"]
edges.append(
doc.edge(
doc.signal(f"{id}_{counter}", f"{orelcount}", mtype),
doc.signal(datasrc, alias, mtype),
thread,
)
)
orelcount += 1
fill = "#fff"
fsize = 14.0
if bold or irelcount > 1 or orelcount > 1:
fill = "#333"
else:
irow = f"<in_{irelcount-1}> "
orow = f"<out_{orelcount-1}>"
fill = "#666"
fsize = 0.0
node += f'{id}_{counter} [tooltip=" IOGAM::{id} " label="'
node += "{ {" + irow + "} | {" + orow + "} }"
node += f'", fillcolor="{fill}", color="#666", style=filled,'
node += f' fontcolor="#fff", fontsize={fsize}, height=0, width=0];\n'
irow = ""
orow = ""
counter += 1
return node, edges
def __doc_constgam__(id, obj, edges, thread):
node = f' {id} [label="{id[2:]}&#92;n{obj["Class"]} | '
values = ""
types = ""
if "OutputSignals" in obj:
for i, (l, sig) in enumerate(obj["OutputSignals"].items()):
datasrc = sig["DataSource"]
alias = doc.signal_alias(l, sig)
mtype = doc.signal_type(sig)
edges.append(
doc.edge(
doc.signal(id, l, mtype),
doc.signal(datasrc, alias, mtype),
thread,
)
)
if i != 0:
values += " | "
types += " | "
values += f'<out_{doc.format_name(l)}> {sig["Default"]}'
types += doc.type_to_string(mtype)
node += "{{ " + types + " } | {" + values + "}}"
node += '", style=filled, fillcolor="#dff"];'
return node, edges
def __doc_events__(id, obj, edges, thread):
return "", edges
def __doc_gam__(label, obj, edges, thread):
id = f"fn{label}"
cls = obj["Class"]
node = f' {id} [label="{label}&#92;n{obj["Class"]} | '
if cls == "ConstantGAM":
return __doc_constgam__(id, obj, edges, thread)
elif cls == "IOGAM":
return __doc_iogam__(id, obj, edges, thread)
elif cls == "TriggeredIOGAM":
return __doc_triggered_iogam__(id, obj, edges, thread)
else:
sigs, edges = __doc_common_gam__(id, obj, edges, thread)
if sigs:
node += sigs + '"];'
else:
node = ""
if cls == "MessageGAM":
extra, edges = __doc_events__(id, obj, edges, thread)
return node, edges
def __process_gamds__(name, signals, edges):
node = ""
outputs = {}
inputs = {}
done = False
to_keep = []
while not done:
signals = {}
for edge in edges:
if edge[0][0] == name:
sig_name = edge[0][1]
signals[sig_name] = edge[0][2]
if sig_name not in outputs:
outputs[sig_name] = []
outputs[sig_name].append(edge)
elif edge[1][0] == name:
sig_name = edge[1][1]
signals[sig_name] = edge[1][2]
if sig_name not in inputs:
inputs[sig_name] = []
inputs[sig_name].append(edge)
to_reduce = []
to_keep = []
done = True
for sig_name in signals:
if sig_name in inputs and sig_name in outputs:
to_reduce.append(sig_name)
else:
to_keep.append(sig_name)
for sig_name in to_reduce:
ins = inputs[sig_name]
outs = outputs[sig_name]
for edge in ins:
if edge in edges:
done = False
edges.remove(edge)
for edge in outs:
if edge in edges:
done = False
edges.remove(edge)
for in_edge in ins:
for out_edge in outs:
edge = (in_edge[0], out_edge[1], in_edge[-1])
edges.append(edge)
for i, sig_name in enumerate(to_keep):
if i > 0:
node += " | "
sig_type = signals[sig_name]
node += (
f"<{doc.format_name(sig_name)}> {sig_name} ({doc.type_to_string(sig_type)})"
)
if node:
node = f'{name} [label="{name}&#92;nGAMDataSource | {node}", color=blue];\n'
return node, edges
def __process_ds__(name, obj, edges):
cls = obj["Class"]
sigs = {}
node = ""
thread = ""
multi_thread = False
for edge in edges:
if edge[0][0] == name:
sigs[edge[0][1]] = edge[0][2]
if not thread:
thread = edge[-1]
elif thread != edge[-1]:
multi_thread = True
if edge[1][0] == name:
sigs[edge[1][1]] = edge[1][2]
if not thread:
thread = edge[-1]
elif thread != edge[-1]:
multi_thread = True
if sigs:
if cls == "GAMDataSource":
node, edges = __process_gamds__(name, sigs, edges)
else:
order = []
lost = []
if "Signals" in obj:
for sig in obj["Signals"]:
if sig in sigs:
order.append(sig)
else:
order = list(sigs.keys())
for sig in sigs:
if sig not in order:
lost.append(sig)
node = f'{name} [label="{name}&#92;n{cls} | '
for i, sig_name in enumerate(order):
if i > 0:
node += " | "
sig_type = sigs[sig_name]
node += f"<{doc.format_name(sig_name)}> {sig_name} ({doc.type_to_string(sig_type)})"
for sig_name in lost:
logging.warning(f"Lost signal {name}:{sig_name}")
if node:
node += " | "
sig_type = sigs[sig_name]
node += f"<{doc.format_name(sig_name)}> {sig_name} ({doc.type_to_string(sig_type)})"
node += '", color=blue];\n'
if not multi_thread and node:
node = f"subgraph cluster_{thread}" + "{\n" + node + "};\n"
return node, edges
def __process_edges__(edges, datasources):
arrows = ""
for source, target, _ in edges:
src_obj = source[0]
src_sig = doc.format_name(source[1])
trg_obj = target[0]
trg_sig = doc.format_name(target[1])
a = f"{src_obj}"
b = f"{trg_obj}"
if src_obj in datasources:
a += f":{src_sig}"
else:
a += f":out_{src_sig}"
if trg_obj in datasources:
b += f":{trg_sig}"
else:
b += f":in_{trg_sig}"
in_type = doc.type_to_string(source[2])
out_type = doc.type_to_string(target[2])
mtype = in_type if in_type == out_type else f"{in_type} -> {out_type}"
arrows += f'{a} -> {b} [tooltip=" {mtype} ", labelfloat=false];\n'
return arrows
def doc_state(label, state, app):
global __PATH__
mdstate = ""
graph = f"digraph {label[1:]}" + "{\n"
graph += "ranksep = 1;\n"
graph += "nodesep = 0.5;\n"
graph += "rankdir = LR;\n"
graph += "node [shape=Mrecord];\n"
graph += "\n"
arrows = ""
ext = ""
edges = []
datasources = {}
if "+Threads" in state:
for tname, obj in state["+Threads"].items():
if tname[0] == "+":
graph += f"subgraph cluster_{tname[1:]}" + "{\n"
if "Functions" in obj:
fns = obj["Functions"]
for fn in fns:
obj = app["+Functions"][f"+{fn}"]
node, edges = __doc_gam__(fn, obj, edges, tname[1:])
graph += f"{node}\n"
graph += f"\n label = < <B>{tname[1:]}</B> >;\n"
graph += " fontsize = 24.0;\n"
graph += " penwidth = 3;\n"
graph += ' color = "#0A0";\n'
graph += "}\n"
if "+Data" in app:
for key, obj in app["+Data"].items():
if key[0] == "+":
datasources[key[1:]] = obj["Class"]
node, edges = __process_ds__(key[1:], obj, edges)
graph += node
arrows = __process_edges__(edges, datasources)
graph += "\n" + ext + "\n" + arrows
graph += "}\n"
fname = f"{label[1:]}"
with open(os.path.join(doc.path(), f"{fname}.dot"), "w") as file:
file.write(graph)
os.system(
f"dot -Tsvg -o{os.path.join(doc.path(), fname)}.svg {os.path.join(doc.path(), fname)}.dot"
)
mdstate += f"![{fname}]({fname}.svg)\n"
return mdstate