sync/gen_statemachine.ysl2
author Edouard Tisserant <edouard@pep-project.org>
Thu, 08 Dec 2016 00:51:41 +0100
changeset 1467 ff7c60d14af0
parent 1460 66ceb5a7f718
child 1476 61323550db84
permissions -rw-r--r--
sync: documentation, moved generated code, updated .hgignore, cleaning
     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 standardlib.ysl2
    11     include ./functions.ysl2
    12 
    13     template "/protocol" {
    14         document "generated/Makefile.protocols", "text"
    15             apply "fsm", 0, mode="make";
    16         apply "fsm", 0, mode=gen;
    17     }
    18 
    19     template "fsm", mode=make
    20     ||
    21     «@filename»_fsm.c: ../sync/devicegroup.fsm
    22     \tmake -C ../«@filename»
    23     ||
    24 
    25     template "fsm", mode=gen {
    26         document "generated/{@filename}_fsm.h", "text" {
    27         ||
    28         #pragma once
    29 
    30         // state machine for «@name»
    31 
    32         #include "message_api.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         // event injector
    96 
    97         PEP_STATUS inject_DeviceState_event(
    98             PEP_SESSION session, 
    99             DeviceState_event event,
   100             Identity partner,
   101             void *extra);
   102 
   103         // message receiver
   104         
   105         PEP_STATUS receive_DeviceState_msg(
   106                 PEP_SESSION session, 
   107                 message *src, 
   108                 PEP_rating rating, 
   109                 stringlist_t *keylist
   110             );
   111 
   112         // state machine
   113 
   114         «@name»_state fsm_«@name»(
   115                 PEP_SESSION session,
   116                 «@name»_state state,
   117                 «@name»_event event,
   118                 Identity partner,
   119                 void *extra,
   120                 time_t *timeout
   121             );
   122 
   123         // driver
   124 
   125         DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
   126                 PEP_SESSION session,
   127                 «@name»_event event,
   128                 Identity partner,
   129                 void *extra,
   130                 time_t *timeout
   131             );
   132 
   133         #ifdef __cplusplus
   134         }
   135         #endif
   136 
   137         ||
   138         }
   139         document "generated/{@filename}_driver.c", "text"
   140         ||
   141         // Driver for «@name» state machine
   142 
   143         #include <assert.h>
   144         #include "pEp_internal.h"
   145 
   146 
   147         DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
   148                 PEP_SESSION session,
   149                 «@name»_event event,
   150                 Identity partner,
   151                 void *extra,
   152                 time_t *timeout
   153             )
   154         {
   155             assert(session);
   156             if (!session)
   157                 return PEP_ILLEGAL_VALUE;
   158 
   159             while(true)
   160             {
   161                 «@name»_state new_state = fsm_«@name»(session,
   162                     session->«@filename»_state, event, partner, extra, timeout);
   163 
   164                 if (new_state == «@name»_state_invalid_out_of_memory)
   165                     return PEP_OUT_OF_MEMORY;
   166 
   167                 if (new_state < 0)
   168                     return PEP_SYNC_STATEMACHINE_ERROR - new_state;
   169                 
   170                 if (new_state == session->«@filename»_state)
   171                     break;
   172 
   173                 event = Init;
   174                 extra = NULL;
   175                 session->«@filename»_state = new_state;
   176             } 
   177 
   178             return PEP_STATUS_OK;
   179         }
   180 
   181         ||
   182         document "generated/{@filename}_fsm.c", "text"
   183         ||
   184         #include "«@filename»_fsm.h"
   185         #include "pEp_internal.h"
   186 
   187         // state machine for «@name»
   188 
   189         «@name»_state fsm_«@name»(
   190                 PEP_SESSION session,
   191                 «@name»_state state,
   192                 «@name»_event event,
   193                 Identity partner,
   194                 void *extra,
   195                 time_t *timeout
   196             )
   197         {
   198             int cond_result;
   199             PEP_STATUS status = PEP_STATUS_OK;
   200 
   201             switch (state) {
   202             `` apply "state", 2
   203                 default:
   204                     return («@name»_state) invalid_state;
   205             }
   206 
   207             return state;
   208         }
   209 
   210         ||
   211     }
   212 
   213     template "state"
   214     ||
   215     case «@name»:
   216     {
   217         `` if "count(parm) > 1" error | # TODO composite state payload 
   218         `` apply "parm", 1 mode="stateParm"
   219         *timeout = «@timeout»;
   220         switch (event) {
   221         `` if "not(event[@name='Init'])" |>> case Init: break;
   222         `` apply "event", 2
   223             default:
   224                 return («../@name»_state) invalid_event;
   225         }
   226         break;
   227     }
   228     ||
   229 
   230     template "parm" mode="stateParm" 
   231     {
   232         | «name(*[1])» «name(*[2])» = («name(*[1])»)session->sync_state_payload;
   233     }
   234 
   235     template "event"
   236     ||
   237     case «@name»:
   238     {
   239     `` apply "action|transition|condition";
   240     `` if "name(*[position()=last()]) != 'transition'" |> break;
   241     }
   242     ||
   243 
   244     template "action" {
   245         indent(0);
   246         > status = «@name»(session, state, 
   247         choose {
   248             when "parm" > «name(parm/*)»
   249             otherwise > NULL
   250         }
   251         choose {
   252             when "parm[2]" > , extra /*«name(parm[2]/*)»*/
   253             otherwise > , NULL
   254         }
   255         > );\n
   256         | if (status == PEP_OUT_OF_MEMORY)
   257         |> return (int) invalid_out_of_memory;
   258         | if (status != PEP_STATUS_OK)
   259         |> return (int) invalid_action;
   260     }
   261 
   262     template "condition" {
   263         | cond_result = «@name»(session`apply "parm", 0`);
   264         | if (cond_result < 0)
   265         |> return cond_result;
   266         | if (cond_result) {
   267         apply "action|transition|condition";
   268         | }
   269     }
   270 
   271     template "parm" choose {
   272         when "count(*) = 1"
   273             > , «name(*)»
   274         otherwise
   275             > , «name(*[1])» «name(*[2])»
   276     }
   277 
   278     template "transition"{
   279         const "stateparm", "ancestor::state/child::parm";
   280         if "$stateparm" {
   281             | if(session->sync_state_payload){
   282             |     free_«yml:lcase(name($stateparm[1]/*))»((«name($stateparm[1]/*)»)session->sync_state_payload);
   283             |     session->sync_state_payload = NULL;
   284             | }
   285         }
   286         if "parm" {
   287             const "nextstatename", "@target";
   288             const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
   289             | session->sync_state_payload = «yml:lcase(name($nextstateparm/*))»_dup(«name(parm/*)»);
   290         }
   291         | return «@target»;
   292     }
   293 }
   294