sync/gen_statemachine.ysl2
author Volker Birk <vb@pep.foundation>
Mon, 22 Aug 2016 17:26:40 +0200
branchkeysync
changeset 1047 2a4a2ec1340b
parent 1046 73be5d9af815
child 1099 113463c3e85a
permissions -rw-r--r--
restructuring things (will not build)
     1 // generate state machine code
     2 
     3 // Copyleft (c) 2016, p≡p foundation
     4 
     5 // Written by Volker Birk
     6 
     7 include yslt.yml2
     8 
     9 tstylesheet {
    10     include ./functions.ysl2
    11 
    12     template "/protocol" {
    13         document "../src/Makefile.protocols", "text"
    14             apply "fsm", 0, mode="make";
    15         apply "fsm", 0, mode=gen;
    16     }
    17 
    18     template "fsm", mode=make
    19     ||
    20     «@filename»_fsm.c: ../sync/devicegroup.fsm
    21     \tmake -C ../«@filename»
    22     ||
    23 
    24     template "fsm", mode=gen {
    25         document "../src/{@filename}_fsm.h", "text" {
    26         ||
    27         #pragma once
    28 
    29         // state machine for «@name»
    30 
    31         #include "pEpEngine.h"
    32         #include "message.h"
    33         
    34         #ifdef __cplusplus
    35         extern "C" {
    36         #endif
    37 
    38         // types
    39 
    40         typedef pEp_identity * Identity;
    41         typedef stringlist_t * Stringlist;
    42         typedef union _param { Identity partner; stringlist_t *keylist; } param_t;
    43 
    44         // error values
    45 
    46         typedef enum _fsm_error {
    47             // these error values are corresponding to
    48             // PEP_SYNC_STATEMACHINE_ERROR - value
    49             invalid_state = -2,
    50             invalid_event = -3,
    51             invalid_condition = -4,
    52             invalid_action = -5,
    53 
    54             // out of memory condition
    55             invalid_out_of_memory = -128
    56         } fsm_error;
    57 
    58         // conditions
    59 
    60         `` for "func:distinctName(condition)" | int «@name»(PEP_SESSION session`apply "parm", 0`);
    61 
    62         // states
    63 
    64         typedef enum _«@name»_state {
    65             // error values also in this namespace
    66             «@name»_state_invalid_state = (int) invalid_state,
    67             «@name»_state_invalid_event = (int) invalid_event,
    68             «@name»_state_invalid_condition = (int) invalid_condition,
    69             «@name»_state_invalid_action = (int) invalid_action,
    70             «@name»_state_invalid_out_of_memory = (int) invalid_out_of_memory,
    71 
    72             «@name»_state_NONE = 0,
    73         `` for "func:distinctName(state)" |> «@name»`if "position()!=last()" > , `
    74         } «@name»_state;
    75 
    76         // events
    77 
    78         typedef enum _«@name»_event {
    79             «@name»_event_NONE = 0,
    80         ||
    81         for "func:distinctName(state/event[not(not(/protocol/fsm/tag/@name=@name))])" {
    82             const "name", "@name";
    83             |> «$name» = «/protocol/fsm/tag[@name=$name]/@id»,
    84         }
    85         for "func:distinctName(state/event[not(/protocol/fsm/tag/@name=@name)])"
    86             |> «@name»`if "position()!=last()" > , `
    87         ||
    88         } «@name»_event;
    89 
    90         // actions
    91 
    92         `` const "name", "@name"
    93         `` for "func:distinctName(//action)" | PEP_STATUS «@name»(PEP_SESSION session, «$name»_state state, Identity partner, void *extra);
    94 
    95         // message receiver
    96         
    97         PEP_STATUS receive_«@name»_msg(PEP_SESSION session, message *msg);
    98 
    99         // state machine
   100 
   101         «@name»_state fsm_«@name»(
   102                 PEP_SESSION session,
   103                 «@name»_state state,
   104                 «@name»_event event,
   105                 Identity partner,
   106                 void *extra
   107             );
   108 
   109         // driver
   110 
   111         DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
   112                 PEP_SESSION session,
   113                 «@name»_event event,
   114                 Identity partner,
   115                 void *extra
   116             );
   117 
   118         #ifdef __cplusplus
   119         }
   120         #endif
   121 
   122         ||
   123         }
   124         document "../src/{@filename}_driver.c", "text"
   125         ||
   126         // Driver for «@name» state machine
   127 
   128         #include <assert.h>
   129         #include "pEp_internal.h"
   130 
   131 
   132         DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
   133                 PEP_SESSION session,
   134                 «@name»_event event,
   135                 Identity partner,
   136                 void *extra
   137             )
   138         {
   139             assert(session);
   140             if (!session)
   141                 return PEP_ILLEGAL_VALUE;
   142 
   143             «@name»_state state = fsm_«@name»(session,
   144                     session->«@filename»_state, event, partner, extra);
   145             if (state == «@name»_state_invalid_out_of_memory)
   146                 return PEP_OUT_OF_MEMORY;
   147             if (state < 0)
   148                 return PEP_SYNC_STATEMACHINE_ERROR - state;
   149 
   150             session->«@filename»_state = state;
   151             return PEP_STATUS_OK;
   152         }
   153 
   154         ||
   155         document "../src/{@filename}_fsm.c", "text"
   156         ||
   157         #include "«@filename»_fsm.h"
   158 
   159         // state machine for «@name»
   160 
   161         «@name»_state fsm_«@name»(
   162                 PEP_SESSION session,
   163                 «@name»_state state,
   164                 «@name»_event event,
   165                 Identity partner,
   166                 void *extra
   167             )
   168         {
   169             int cond_result;
   170             PEP_STATUS status = PEP_STATUS_OK;
   171 
   172             switch (state) {
   173             `` apply "state", 2
   174                 default:
   175                     return («@name»_state) invalid_state;
   176             }
   177 
   178             return state;
   179         }
   180 
   181         ||
   182     }
   183 
   184     template "state"
   185     ||
   186     case «@name»:
   187         switch (event) {
   188         `` apply "event", 2
   189             default:
   190                 return («../@name»_state) invalid_event;
   191         }
   192         break;
   193 
   194     ||
   195 
   196     template "event"
   197     ||
   198     case «@name»:
   199     `` apply "action|transition|condition";
   200     `` if "name(*[position()=last()]) != 'transition'" |> break;
   201     ||
   202 
   203     template "action" {
   204         indent(0);
   205         > status = «@name»(session, state, 
   206         choose {
   207             when "parm" > «name(parm/*)»
   208             otherwise > NULL
   209         }
   210         > , NULL);\n
   211         | if (status == PEP_OUT_OF_MEMORY)
   212         |> return (int) invalid_out_of_memory;
   213         | if (status != PEP_STATUS_OK)
   214         |> return (int) invalid_action;
   215     }
   216 
   217     template "condition" {
   218         | cond_result = «@name»(session`apply "parm", 0`);
   219         | if (cond_result < 0)
   220         |> return cond_result;
   221         | if (cond_result) {
   222         apply "action|transition|condition";
   223         | }
   224     }
   225 
   226     template "parm" choose {
   227         when "count(*) = 1"
   228             > , «name(*)»
   229         otherwise
   230             > , «name(*[1])» «name(*[2])»
   231     }
   232 
   233     template "transition" | return «@target»;
   234 }
   235