sync/gen_statemachine.ysl2
author Edouard Tisserant <edouard@pep-project.org>
Fri, 09 Dec 2016 01:36:57 +0100
changeset 1477 c0d761ae1fd9
parent 1476 61323550db84
child 1490 e375c22bc587
permissions -rw-r--r--
sync: obey new app notification enum names, this time with corresponding actions generated
vb@577
     1
// generate state machine code
vb@577
     2
vb@577
     3
// Copyleft (c) 2016, p≡p foundation
vb@577
     4
vb@577
     5
// Written by Volker Birk
vb@577
     6
vb@577
     7
include yslt.yml2
vb@577
     8
vb@577
     9
tstylesheet {
edouard@1460
    10
    include standardlib.ysl2
vb@623
    11
    include ./functions.ysl2
Edouard@605
    12
vb@811
    13
    template "/protocol" {
edouard@1467
    14
        document "generated/Makefile.protocols", "text"
vb@811
    15
            apply "fsm", 0, mode="make";
vb@811
    16
        apply "fsm", 0, mode=gen;
vb@811
    17
    }
vb@811
    18
vb@811
    19
    template "fsm", mode=make
vb@811
    20
    ||
vb@811
    21
    «@filename»_fsm.c: ../sync/devicegroup.fsm
vb@811
    22
    \tmake -C ../«@filename»
vb@811
    23
    ||
vb@811
    24
vb@811
    25
    template "fsm", mode=gen {
edouard@1467
    26
        document "generated/{@filename}_fsm.h", "text" {
vb@609
    27
        ||
vb@609
    28
        #pragma once
vb@577
    29
vb@609
    30
        // state machine for «@name»
vb@577
    31
vb@1099
    32
        #include "message_api.h"
vb@654
    33
        
vb@654
    34
        #ifdef __cplusplus
vb@654
    35
        extern "C" {
vb@654
    36
        #endif
vb@608
    37
vb@609
    38
        // types
Edouard@605
    39
vb@609
    40
        typedef pEp_identity * Identity;
vb@939
    41
        typedef stringlist_t * Stringlist;
vb@939
    42
        typedef union _param { Identity partner; stringlist_t *keylist; } param_t;
vb@583
    43
vb@609
    44
        // error values
vb@577
    45
vb@609
    46
        typedef enum _fsm_error {
vb@964
    47
            // these error values are corresponding to
vb@964
    48
            // PEP_SYNC_STATEMACHINE_ERROR - value
vb@743
    49
            invalid_state = -2,
vb@959
    50
            invalid_event = -3,
vb@959
    51
            invalid_condition = -4,
vb@964
    52
            invalid_action = -5,
vb@964
    53
vb@964
    54
            // out of memory condition
vb@964
    55
            invalid_out_of_memory = -128
vb@609
    56
        } fsm_error;
vb@583
    57
vb@951
    58
        // conditions
vb@951
    59
vb@959
    60
        `` for "func:distinctName(condition)" | int «@name»(PEP_SESSION session`apply "parm", 0`);
vb@951
    61
vb@609
    62
        // states
vb@578
    63
vb@609
    64
        typedef enum _«@name»_state {
vb@1043
    65
            // error values also in this namespace
vb@1043
    66
            «@name»_state_invalid_state = (int) invalid_state,
vb@1043
    67
            «@name»_state_invalid_event = (int) invalid_event,
vb@1043
    68
            «@name»_state_invalid_condition = (int) invalid_condition,
vb@1043
    69
            «@name»_state_invalid_action = (int) invalid_action,
vb@1043
    70
            «@name»_state_invalid_out_of_memory = (int) invalid_out_of_memory,
vb@1043
    71
vb@951
    72
            «@name»_state_NONE = 0,
vb@623
    73
        `` for "func:distinctName(state)" |> «@name»`if "position()!=last()" > , `
vb@609
    74
        } «@name»_state;
vb@583
    75
vb@609
    76
        // events
vb@578
    77
vb@609
    78
        typedef enum _«@name»_event {
vb@951
    79
            «@name»_event_NONE = 0,
vb@711
    80
        ||
vb@711
    81
        for "func:distinctName(state/event[not(not(/protocol/fsm/tag/@name=@name))])" {
vb@711
    82
            const "name", "@name";
vb@711
    83
            |> «$name» = «/protocol/fsm/tag[@name=$name]/@id»,
vb@711
    84
        }
vb@711
    85
        for "func:distinctName(state/event[not(/protocol/fsm/tag/@name=@name)])"
vb@711
    86
            |> «@name»`if "position()!=last()" > , `
vb@711
    87
        ||
vb@609
    88
        } «@name»_event;
vb@583
    89
vb@609
    90
        // actions
vb@582
    91
vb@690
    92
        `` const "name", "@name"
vb@939
    93
        `` for "func:distinctName(//action)" | PEP_STATUS «@name»(PEP_SESSION session, «$name»_state state, Identity partner, void *extra);
Edouard@605
    94
edouard@1205
    95
        // event injector
edouard@1205
    96
edouard@1205
    97
        PEP_STATUS inject_DeviceState_event(
edouard@1205
    98
            PEP_SESSION session, 
edouard@1205
    99
            DeviceState_event event,
edouard@1205
   100
            Identity partner,
edouard@1205
   101
            void *extra);
edouard@1205
   102
vb@951
   103
        // message receiver
vb@951
   104
        
edouard@1165
   105
        PEP_STATUS receive_DeviceState_msg(
edouard@1165
   106
                PEP_SESSION session, 
edouard@1165
   107
                message *src, 
edouard@1165
   108
                PEP_rating rating, 
edouard@1165
   109
                stringlist_t *keylist
edouard@1165
   110
            );
vb@951
   111
vb@626
   112
        // state machine
vb@626
   113
vb@626
   114
        «@name»_state fsm_«@name»(
vb@627
   115
                PEP_SESSION session,
vb@626
   116
                «@name»_state state,
vb@626
   117
                «@name»_event event,
vb@939
   118
                Identity partner,
edouard@1445
   119
                void *extra,
edouard@1445
   120
                time_t *timeout
vb@626
   121
            );
vb@626
   122
vb@609
   123
        // driver
Edouard@605
   124
vb@782
   125
        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
vb@690
   126
                PEP_SESSION session,
vb@690
   127
                «@name»_event event,
vb@690
   128
                Identity partner,
edouard@1445
   129
                void *extra,
edouard@1445
   130
                time_t *timeout
vb@690
   131
            );
Edouard@605
   132
vb@654
   133
        #ifdef __cplusplus
vb@654
   134
        }
vb@654
   135
        #endif
vb@654
   136
vb@609
   137
        ||
vb@711
   138
        }
edouard@1467
   139
        document "generated/{@filename}_driver.c", "text"
vb@690
   140
        ||
vb@690
   141
        // Driver for «@name» state machine
vb@690
   142
vb@690
   143
        #include <assert.h>
vb@690
   144
        #include "pEp_internal.h"
vb@690
   145
vb@690
   146
vb@743
   147
        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
vb@690
   148
                PEP_SESSION session,
vb@690
   149
                «@name»_event event,
vb@690
   150
                Identity partner,
edouard@1445
   151
                void *extra,
edouard@1445
   152
                time_t *timeout
vb@690
   153
            )
vb@690
   154
        {
vb@951
   155
            assert(session);
vb@951
   156
            if (!session)
vb@951
   157
                return PEP_ILLEGAL_VALUE;
vb@690
   158
edouard@1152
   159
            while(true)
edouard@1152
   160
            {
edouard@1152
   161
                «@name»_state new_state = fsm_«@name»(session,
edouard@1445
   162
                    session->«@filename»_state, event, partner, extra, timeout);
edouard@1157
   163
edouard@1152
   164
                if (new_state == «@name»_state_invalid_out_of_memory)
edouard@1152
   165
                    return PEP_OUT_OF_MEMORY;
edouard@1157
   166
edouard@1152
   167
                if (new_state < 0)
edouard@1152
   168
                    return PEP_SYNC_STATEMACHINE_ERROR - new_state;
edouard@1152
   169
                
edouard@1157
   170
                if (new_state == session->«@filename»_state)
edouard@1152
   171
                    break;
vb@690
   172
edouard@1157
   173
                event = Init;
edouard@1157
   174
                extra = NULL;
edouard@1152
   175
                session->«@filename»_state = new_state;
edouard@1152
   176
            } 
edouard@1152
   177
vb@951
   178
            return PEP_STATUS_OK;
vb@690
   179
        }
vb@690
   180
vb@690
   181
        ||
edouard@1467
   182
        document "generated/{@filename}_fsm.c", "text"
vb@609
   183
        ||
vb@1476
   184
        #include "pEp_internal.h"
vb@807
   185
        #include "«@filename»_fsm.h"
vb@609
   186
vb@609
   187
        // state machine for «@name»
vb@609
   188
vb@609
   189
        «@name»_state fsm_«@name»(
vb@627
   190
                PEP_SESSION session,
vb@609
   191
                «@name»_state state,
vb@609
   192
                «@name»_event event,
vb@939
   193
                Identity partner,
edouard@1445
   194
                void *extra,
edouard@1445
   195
                time_t *timeout
vb@609
   196
            )
vb@609
   197
        {
vb@964
   198
            int cond_result;
vb@959
   199
            PEP_STATUS status = PEP_STATUS_OK;
vb@959
   200
vb@609
   201
            switch (state) {
vb@951
   202
            `` apply "state", 2
vb@609
   203
                default:
vb@743
   204
                    return («@name»_state) invalid_state;
vb@609
   205
            }
vb@609
   206
vb@609
   207
            return state;
vb@577
   208
        }
vb@582
   209
vb@609
   210
        ||
vb@577
   211
    }
vb@577
   212
vb@580
   213
    template "state"
vb@577
   214
    ||
vb@577
   215
    case «@name»:
edouard@1460
   216
    {
edouard@1460
   217
        `` if "count(parm) > 1" error | # TODO composite state payload 
edouard@1460
   218
        `` apply "parm", 1 mode="stateParm"
edouard@1445
   219
        *timeout = «@timeout»;
vb@578
   220
        switch (event) {
edouard@1356
   221
        `` if "not(event[@name='Init'])" |>> case Init: break;
vb@578
   222
        `` apply "event", 2
vb@951
   223
            default:
vb@951
   224
                return («../@name»_state) invalid_event;
vb@578
   225
        }
vb@577
   226
        break;
edouard@1460
   227
    }
edouard@1460
   228
    ||
vb@577
   229
edouard@1460
   230
    template "parm" mode="stateParm" 
edouard@1460
   231
    {
edouard@1460
   232
        | «name(*[1])» «name(*[2])» = («name(*[1])»)session->sync_state_payload;
edouard@1460
   233
    }
vb@578
   234
vb@578
   235
    template "event"
vb@578
   236
    ||
vb@578
   237
    case «@name»:
edouard@1460
   238
    {
vb@951
   239
    `` apply "action|transition|condition";
vb@582
   240
    `` if "name(*[position()=last()]) != 'transition'" |> break;
edouard@1460
   241
    }
vb@578
   242
    ||
vb@578
   243
vb@582
   244
    template "action" {
vb@582
   245
        indent(0);
vb@959
   246
        > status = «@name»(session, state, 
vb@582
   247
        choose {
vb@582
   248
            when "parm" > «name(parm/*)»
vb@582
   249
            otherwise > NULL
vb@582
   250
        }
edouard@1166
   251
        choose {
edouard@1166
   252
            when "parm[2]" > , extra /*«name(parm[2]/*)»*/
edouard@1166
   253
            otherwise > , NULL
edouard@1166
   254
        }
edouard@1166
   255
        > );\n
vb@964
   256
        | if (status == PEP_OUT_OF_MEMORY)
vb@1043
   257
        |> return (int) invalid_out_of_memory;
vb@959
   258
        | if (status != PEP_STATUS_OK)
vb@1043
   259
        |> return (int) invalid_action;
vb@582
   260
    }
vb@582
   261
vb@951
   262
    template "condition" {
vb@959
   263
        | cond_result = «@name»(session`apply "parm", 0`);
vb@964
   264
        | if (cond_result < 0)
vb@964
   265
        |> return cond_result;
vb@959
   266
        | if (cond_result) {
vb@951
   267
        apply "action|transition|condition";
vb@951
   268
        | }
edouard@1477
   269
        const "else", "./following-sibling::*[position()=1][name(.)='else']";
edouard@1477
   270
        if "$else" {
edouard@1477
   271
        | else {
edouard@1477
   272
        apply "$else/action|transition|condition";
edouard@1477
   273
        | }
edouard@1477
   274
        }
vb@951
   275
    }
vb@951
   276
vb@951
   277
    template "parm" choose {
vb@951
   278
        when "count(*) = 1"
vb@951
   279
            > , «name(*)»
vb@951
   280
        otherwise
vb@951
   281
            > , «name(*[1])» «name(*[2])»
vb@951
   282
    }
vb@951
   283
edouard@1460
   284
    template "transition"{
edouard@1460
   285
        const "stateparm", "ancestor::state/child::parm";
edouard@1460
   286
        if "$stateparm" {
edouard@1460
   287
            | if(session->sync_state_payload){
edouard@1460
   288
            |     free_«yml:lcase(name($stateparm[1]/*))»((«name($stateparm[1]/*)»)session->sync_state_payload);
edouard@1460
   289
            |     session->sync_state_payload = NULL;
edouard@1460
   290
            | }
edouard@1460
   291
        }
edouard@1460
   292
        if "parm" {
edouard@1460
   293
            const "nextstatename", "@target";
edouard@1460
   294
            const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
edouard@1460
   295
            | session->sync_state_payload = «yml:lcase(name($nextstateparm/*))»_dup(«name(parm/*)»);
edouard@1460
   296
        }
edouard@1460
   297
        | return «@target»;
edouard@1460
   298
    }
vb@577
   299
}
vb@577
   300