A fully working version of the scheduling language with added examples
This commit is contained in:
parent
ec42f74960
commit
ebfd85a666
126 changed files with 7235 additions and 981 deletions
197
transformation/schedule/generator.py
Normal file
197
transformation/schedule/generator.py
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
import sys
|
||||
import os
|
||||
from uuid import UUID
|
||||
|
||||
from black.trans import Callable
|
||||
from jinja2.runtime import Macro
|
||||
|
||||
from api.od import ODAPI
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
|
||||
class schedule_generator:
|
||||
def __init__(self, odApi: ODAPI):
|
||||
self.env = Environment(
|
||||
loader=FileSystemLoader(
|
||||
os.path.join(os.path.dirname(__file__), "templates")
|
||||
)
|
||||
)
|
||||
self.env.trim_blocks = True
|
||||
self.env.lstrip_blocks = True
|
||||
self.template = self.env.get_template("schedule_template.j2")
|
||||
self.template_wrap = self.env.get_template("schedule_template_wrap.j2")
|
||||
self.api = odApi
|
||||
|
||||
|
||||
def _get_slot_value_default(item: UUID, slot: str, default):
|
||||
if slot in self.api.get_slots(item):
|
||||
return self.api.get_slot_value(item, slot)
|
||||
return default
|
||||
|
||||
conn_data_event = {
|
||||
"Match": lambda item: False,
|
||||
"Rewrite": lambda item: False,
|
||||
"Modify": lambda item: True,
|
||||
"Merge": lambda item: True,
|
||||
"Loop": lambda item: True,
|
||||
"Action": lambda item: _get_slot_value_default(item, "event", False),
|
||||
"Print": lambda item: _get_slot_value_default(item, "event", False),
|
||||
"Store": lambda item: False,
|
||||
"Schedule": lambda item: False,
|
||||
"End": lambda item: False,
|
||||
}
|
||||
|
||||
arg_map = {
|
||||
"Loop": (name_dict := lambda item: {"name": self.api.get_name(item)}),
|
||||
"Start": lambda item: {
|
||||
**name_dict(item),
|
||||
"ports_exec_out": eval(
|
||||
self.api.get_slot_value_default(item, "ports_exec_out", "['out']")
|
||||
),
|
||||
"ports_data_out": eval(
|
||||
self.api.get_slot_value_default(item, "ports_data_out", "[]")
|
||||
),
|
||||
},
|
||||
"End": lambda item: {
|
||||
**name_dict(item),
|
||||
"ports_exec_in": eval(
|
||||
self.api.get_slot_value_default(item, "ports_exec_in", "['in']")
|
||||
),
|
||||
"ports_data_in": eval(
|
||||
self.api.get_slot_value_default(item, "ports_data_in", "[]")
|
||||
),
|
||||
},
|
||||
"Rewrite": (
|
||||
file_dict := lambda item: {
|
||||
**name_dict(item),
|
||||
"file": self.api.get_slot_value(item, "file"),
|
||||
}
|
||||
),
|
||||
"Match": lambda item: {
|
||||
**file_dict(item),
|
||||
"n": self.api.get_slot_value_default(item, "n", 'float("inf")'),
|
||||
},
|
||||
"Action": lambda item: {
|
||||
**name_dict(item),
|
||||
"ports_exec_in": self.api.get_slot_value_default(item, "ports_exec_in", ["in"]),
|
||||
"ports_exec_out": self.api.get_slot_value_default(item, "ports_exec_out", ["out"]),
|
||||
"ports_data_in": self.api.get_slot_value_default(item, "ports_data_in", []),
|
||||
"ports_data_out": self.api.get_slot_value_default(item, "ports_data_out", []),
|
||||
"action": repr(self.api.get_slot_value(item, "action")),
|
||||
"init": repr(
|
||||
self.api.get_slot_value_default(item, "init", "")
|
||||
),
|
||||
},
|
||||
"Modify": lambda item: {
|
||||
**name_dict(item),
|
||||
"rename": eval(self.api.get_slot_value_default(item, "rename", "{}")),
|
||||
"delete": eval(self.api.get_slot_value_default(item, "delete", "{}")),
|
||||
},
|
||||
"Merge": lambda item: {
|
||||
**name_dict(item),
|
||||
"ports_data_in": eval(
|
||||
self.api.get_slot_value_default(item, "ports_data_in", "[]")
|
||||
),
|
||||
},
|
||||
"Store": lambda item: {
|
||||
**name_dict(item),
|
||||
"ports": eval(self.api.get_slot_value_default(item, "ports", "[]")),
|
||||
},
|
||||
"Schedule": file_dict,
|
||||
"Print": lambda item: {
|
||||
**name_dict(item),
|
||||
"label": self.api.get_slot_value_default(item, "label", ""),
|
||||
"custom": self.api.get_slot_value_default(item, "custom", ""),
|
||||
},
|
||||
"Conn_exec": (
|
||||
conn_dict := lambda item: {
|
||||
"name_from": self.api.get_name(self.api.get_source(item)),
|
||||
"name_to": self.api.get_name(self.api.get_target(item)),
|
||||
"from": self.api.get_slot_value_default(item, "from", 0),
|
||||
"to": self.api.get_slot_value_default(item, "to", 0),
|
||||
}
|
||||
),
|
||||
"Conn_data": lambda item: {
|
||||
**conn_dict(item),
|
||||
"event": conn_data_event[
|
||||
self.api.get_type_name(target := self.api.get_target(item))
|
||||
](target),
|
||||
},
|
||||
}
|
||||
self.macro_args = {
|
||||
tp: (macro, arg_map.get(tp))
|
||||
for tp, macro in self.template.module.__dict__.items()
|
||||
if type(macro) == Macro
|
||||
}
|
||||
|
||||
def _render(self, item):
|
||||
type_name = self.api.get_type_name(item)
|
||||
macro, arg_gen = self.macro_args[type_name]
|
||||
return macro(**arg_gen(item))
|
||||
|
||||
def _dfs(
|
||||
self, stack: list[UUID], get_links: Callable, get_next_node: Callable
|
||||
) -> tuple[set[UUID], list[UUID]]:
|
||||
visited = set()
|
||||
connections = list()
|
||||
while len(stack) > 0:
|
||||
obj = stack.pop()
|
||||
if obj in visited:
|
||||
continue
|
||||
visited.add(obj)
|
||||
for conn in get_links(self.api, obj):
|
||||
connections.append(conn)
|
||||
stack.append(get_next_node(self.api, conn))
|
||||
return visited, connections
|
||||
|
||||
def generate_schedule(self, stream=sys.stdout):
|
||||
start = self.api.get_all_instances("Start")[0][1]
|
||||
end = self.api.get_all_instances("End")[0][1]
|
||||
out = {
|
||||
"blocks": [],
|
||||
"blocks_name": [],
|
||||
"blocks_start_end": [],
|
||||
"exec_conn": [],
|
||||
"data_conn": [],
|
||||
"match_files": set(),
|
||||
"matchers": [],
|
||||
"start": self.api.get_name(start),
|
||||
"end": self.api.get_name(end),
|
||||
}
|
||||
|
||||
stack = [start, end]
|
||||
exec_blocks, conn_exec = self._dfs(
|
||||
stack,
|
||||
lambda api, node: api.get_outgoing(node, "Conn_exec"),
|
||||
lambda api, conn: api.get_target(conn),
|
||||
)
|
||||
|
||||
for name, p in self.api.get_all_instances("Print"):
|
||||
if self.api.has_slot(p, "event") and self.api.get_slot_value(p, "event"):
|
||||
exec_blocks.add(p)
|
||||
|
||||
stack = list(exec_blocks)
|
||||
blocks, conn_data = self._dfs(
|
||||
stack,
|
||||
lambda api, node: api.get_incoming(node, "Conn_data"),
|
||||
lambda api, conn: api.get_source(conn),
|
||||
)
|
||||
|
||||
for exec_c in conn_exec:
|
||||
out["exec_conn"].append(self._render(exec_c))
|
||||
|
||||
for data_c in conn_data:
|
||||
out["data_conn"].append(self._render(data_c))
|
||||
|
||||
for block in blocks:
|
||||
out["blocks_name"].append(self.api.get_name(block))
|
||||
if block in [start, end]:
|
||||
out["blocks_start_end"].append(self._render(block))
|
||||
continue
|
||||
out["blocks"].append(self._render(block))
|
||||
if self.api.is_instance(block, "Rule"):
|
||||
d = self.macro_args[self.api.get_type_name(block)][1](block)
|
||||
out["match_files"].add(d["file"])
|
||||
out["matchers"].append(d)
|
||||
|
||||
print(self.template_wrap.render(out), file=stream)
|
||||
Loading…
Add table
Add a link
Reference in a new issue