From 200f2a3edeeffb90f6fab9076e501a25ce16ea76 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Tue, 17 Dec 2024 15:32:24 +0100 Subject: [PATCH] add jinja2-based renderer for object diagrams --- .../textual_od/objectdiagrams.jinja2 | 18 ++++++ concrete_syntax/textual_od/renderer_jinja2.py | 58 +++++++++++++++++++ examples/petrinet/runner.py | 9 ++- requirements.txt | 3 +- 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 concrete_syntax/textual_od/objectdiagrams.jinja2 create mode 100644 concrete_syntax/textual_od/renderer_jinja2.py diff --git a/concrete_syntax/textual_od/objectdiagrams.jinja2 b/concrete_syntax/textual_od/objectdiagrams.jinja2 new file mode 100644 index 0000000..51425d2 --- /dev/null +++ b/concrete_syntax/textual_od/objectdiagrams.jinja2 @@ -0,0 +1,18 @@ +{% macro render_name(name) %}{{ name if not hide_names or name.startswith("__") else "" }}{% endmacro %} + +{% macro render_attributes(obj) %} { + {% for attr_name in odapi.get_slots(obj) %} + {{ attr_name}} = {{ display_value( + val=odapi.get_slot_value(obj, attr_name), + type_name=odapi.get_type_name(odapi.get_slot(obj, attr_name)), + indentation=4) }}; + {% endfor %} +}{% endmacro %} + +{% for obj_name, obj in objects %} +{{ render_name(obj_name) }}:{{ odapi.get_type_name(obj) }}{{ render_attributes(obj) }} +{% endfor %} + +{% for lnk_name, lnk in links %} +{{ render_name(obj_name) }}:{{ odapi.get_type_name(lnk) }} ({{odapi.get_name(odapi.get_source(lnk))}} -> {{odapi.get_name(odapi.get_target(lnk))}}){{ render_attributes(lnk) }} +{% endfor %} diff --git a/concrete_syntax/textual_od/renderer_jinja2.py b/concrete_syntax/textual_od/renderer_jinja2.py new file mode 100644 index 0000000..54279e7 --- /dev/null +++ b/concrete_syntax/textual_od/renderer_jinja2.py @@ -0,0 +1,58 @@ +import jinja2 +import os +from uuid import UUID + +THIS_DIR = os.path.dirname(__file__) + +from api.od import ODAPI +from concrete_syntax import common +from services.bottom.V0 import Bottom +from util.module_to_dict import module_to_dict + +def render_od_jinja2(state, m, mm): + bottom = Bottom(state) + type_model_id = state.read_dict(state.read_root(), "SCD") + scd_model = UUID(state.read_value(type_model_id)) + type_odapi = ODAPI(state, mm, scd_model) + + objects = [] + links = [] + + to_add = bottom.read_keys(m) + already_added = set() + + while len(to_add) > 0: + next_round = [] + for obj_name in to_add: + obj = state.read_dict(m, obj_name) + src, tgt = state.read_edge(obj) + if src == None: + # not a link + objects.append((obj_name, obj)) + already_added.add(obj) + else: + # A link can only be written out after its source and target have been written out + if src in already_added and tgt in already_added: + links.append((obj_name, obj)) + else: + # try again later + next_round.append(obj_name) + if len(next_round) == len(to_add): + raise Exception("We got stuck!", next_round) + to_add = next_round + + loader = jinja2.FileSystemLoader(searchpath=THIS_DIR) + environment = jinja2.Environment( + loader=loader, + # whitespace control: + trim_blocks=True, + lstrip_blocks=True, + ) + template = environment.get_template("objectdiagrams.jinja2") + return template.render({ + 'objects': objects, + 'links': links, + 'odapi': ODAPI(state, m, mm), + **globals()['__builtins__'], + **module_to_dict(common), + }) diff --git a/examples/petrinet/runner.py b/examples/petrinet/runner.py index 5a04699..b2d0c51 100644 --- a/examples/petrinet/runner.py +++ b/examples/petrinet/runner.py @@ -1,12 +1,13 @@ from state.devstate import DevState from api.od import ODAPI from concrete_syntax.textual_od.renderer import render_od +# from concrete_syntax.textual_od.renderer_jinja2 import render_od_jinja2 from bootstrap.scd import bootstrap_scd from util import loader from transformation.rule import RuleMatcherRewriter, ActionGenerator from transformation.ramify import ramify from examples.semantics.operational import simulator -from examples.petrinet.renderer import render_petri_net +from examples.petrinet.renderer import show_petri_net if __name__ == "__main__": @@ -48,11 +49,15 @@ if __name__ == "__main__": matcher_rewriter = RuleMatcherRewriter(state, mm_rt, mm_rt_ramified) action_generator = ActionGenerator(matcher_rewriter, rules) + def render_callback(od): + show_petri_net(od) + return render_od(state, od.m, od.mm) + sim = simulator.Simulator( action_generator=action_generator, decision_maker=simulator.InteractiveDecisionMaker(auto_proceed=False), # decision_maker=simulator.RandomDecisionMaker(seed=0), - renderer=lambda od: render_petri_net(od) + render_od(state, od.m, od.mm), + renderer=render_callback, # renderer=lambda od: render_od(state, od.m, od.mm), ) diff --git a/requirements.txt b/requirements.txt index 81a260c..2105b38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -lark==1.1.9 \ No newline at end of file +lark==1.1.9 +jinja2==3.1.4 \ No newline at end of file