.. _QN_EventTemplate: ==================================== QuickNote: Jinja Events (templating) ==================================== .. post:: 2023/7/26 :category: DesignStudy, CastleBlogs, rough :tags: Castle, WorkshopTools As we have seen in the recent :ref:`QS_QN` a lot of code (to send/handle events) is always the same, but for some details. A template engine, like `Jinja `__, can help in that. Let’s study how those templates can help us. .. seealso:: * The study of generated code in: :ref:`QN_SendEvent` * :file:`.../SIEVE/1.WorkCopy/CC-event-sieve.Castle-handCompiled.c` |BR| (`also on OSDN `__) Events, Eventshandlers & code ============================= A (Castle) event is always part of a (Castle) protocol. Only the combination of the **names** of both the *Protocol* and the *Event* leads to a uniquely generated name. (for C/rPy/... code). To be used in an EventHandler (within a component, for a port). Events in Protocols ------------------- Besides --and especially for C--, we need a functiontype (aka prototype) and a handler/dispatch-table index (as a constant). .. code-block:: ReasonML protocol StartSieve : Protocol { ... runTo(int:max); ... } .. code-block:: C typedef void (*CC_E_StartSieve_runTo_FT)(CC_selfType, CC_ComponentType, int); #define CC_P_StartSieve_runTo 42 // demo-no // The index-number is calculates by (e.g.) the number of *inherit* events plus literal index of protocol Eventshandlers -------------- We also need the event handler implementation, which is component and port specific. Here we focus only of the name of both the Castle and the generated (C-) function. .. code-block:: ReasonML implement Generator { ... StartSieve.runTo(max) on self.controll {...} .. code-block:: C void CC_E_Generator__StartSieve_runTo__controll(CC_C_Generator* self, CC_OutPortType sender, int max) { ... } Jinja macros ============ Below, we use a 3-step approach: #. Combine the protocol and event into an `protocol_event`; that is the base to #. generatedboth the `event_FT` (function-proto-type) and the `event_no` index (number constante). And we use it to #. generate the name of the `event_handler` (C-) implementation .. code-block:: jinja {%macro protocol_event(protocol, event) -%} {{protocol}}_{{event}} {%- endmacro %} .. code-block:: jinja {%macro event_FT(protocolEvent) -%} CC_E_{{protocolEvent}}_FT {%- endmacro %} {%macro event_no(protocolEvent) -%} CC_P_{{protocolEvent}} {%- endmacro %} .. code-block:: jinja {%macro event_handler(compName, protocolEvent, portName) CC_E_{{compName}}__{{protocolEvent}}__{{portName}} {%- endmacro %} .. caution:: The code above is not fully designed. We have to chain the part to make it work. Now the are freewheeling, independer, but readable piece. We use `macro_names` and `marcoNames`. The former is a (jinga) *function*, the latter act as an argument. When the are otherwise the same, the results of the function call is stored in the variable, and passed into the next marco as parameter. |BR| But we assume you understand that, and are able to add the plumbing (or combine/inline them -- convenient, but less readable! Generating C-Code ================= Here we use the above marco’s (without plumbing) to generate *parts* of the code. Other pieces are (for now) hardcoded. That will change later. Sending ------- CastleCode ~~~~~~~~~~ .. code-block:: ReasonML self.generator.controll.runTo(max); Template ~~~~~~~~ .. code-block:: C // Input jinja-marco’s: /// (Aside of the ones given above) /// All values are valid C-code snippets //// my_comp: “self” //// path2port: “generator->control” /// args: void* CC_E_Main__powerOn__power(CC_Main* self, CC_OutPortType sender, int max) { ... { struct CC_B_OutPort outport = {{my_comp}}->{{path2port}}; CC_ComponentType receiver = outport.connection; CC_B_eDispatchTable handlers = outport.handlers; {{event_FT(protocolEvent)}} signal = ({{event_FT(protocolEvent)}})handlers[{{event_no(protocolEvent)}}]; signal(receiver, (CC_selfType)self, {{args}}); // args: max } ... }; EventHandler ------------- CastleCode ~~~~~~~~~~ .. code-block:: ReasonML StartSieve.runTo(max) on self.controll // in Generator Template ~~~~~~~~ .. code-block:: C // Input jinja-marco’s: /// (Aside of the ones given above) /// All values are valid C-code snippets /// typedParms: void {{eventHandler}}(CC_C_{{compName}}* self, CC_OutPortType sender, {{typedParms}}) {...}