sync/gen_statemachine.ysl2
author Krista Bennett <krista@pep-project.org>
Thu, 18 Jan 2018 00:46:19 +0100
changeset 2410 721952accdee
parent 2287 026ab4dae779
child 2829 e444c3c960bb
permissions -rw-r--r--
DANGER! MERGED IN ENGINE-289! SOME DOC BUGS STILL EXIST - USE WITH CARE!!!
krista@2271
     1
// This file is under GNU General Public License 3.0
krista@2271
     2
// see LICENSE.txt
krista@2271
     3
krista@2271
     4
// generate state machine code
krista@2271
     5
krista@2271
     6
// Copyleft (c) 2016, p≡p foundation
krista@2271
     7
krista@2271
     8
// Written by Volker Birk
krista@2271
     9
krista@2271
    10
include yslt.yml2
krista@2271
    11
krista@2271
    12
tstylesheet {
krista@2271
    13
    include standardlib.ysl2
krista@2271
    14
    include ./functions.ysl2
krista@2271
    15
krista@2271
    16
    template "/protocol" {
krista@2271
    17
        document "generated/Makefile.protocols", "text"
krista@2271
    18
            apply "fsm", 0, mode="make";
krista@2271
    19
        apply "fsm", 0, mode=gen;
krista@2271
    20
    }
krista@2271
    21
krista@2271
    22
    template "fsm", mode=make
krista@2271
    23
    ||
krista@2271
    24
    «@filename»_fsm.c: ../sync/devicegroup.fsm
krista@2271
    25
    \tmake -C ../«@filename»
krista@2271
    26
    ||
krista@2271
    27
krista@2271
    28
    template "fsm", mode=gen {
krista@2271
    29
        document "generated/{@filename}_fsm.h", "text" {
krista@2271
    30
        ||
krista@2271
    31
        #pragma once
krista@2271
    32
krista@2271
    33
        // state machine for «@name»
krista@2271
    34
krista@2271
    35
        #include "message_api.h"
krista@2271
    36
        
krista@2271
    37
        #ifdef __cplusplus
krista@2271
    38
        extern "C" {
krista@2271
    39
        #endif
krista@2271
    40
krista@2271
    41
        // types
krista@2271
    42
krista@2271
    43
        typedef pEp_identity * Identity;
krista@2271
    44
        typedef stringlist_t * Stringlist;
krista@2271
    45
krista@2271
    46
        // error values
krista@2271
    47
krista@2271
    48
        typedef enum _fsm_error {
krista@2271
    49
            // these error values are corresponding to
krista@2271
    50
            // PEP_SYNC_STATEMACHINE_ERROR - value
krista@2271
    51
            invalid_state = -2,
krista@2271
    52
            invalid_event = -3,
krista@2271
    53
            invalid_condition = -4,
krista@2271
    54
            invalid_action = -5,
krista@2271
    55
krista@2271
    56
            // out of memory condition
krista@2271
    57
            invalid_out_of_memory = -128
krista@2271
    58
        } fsm_error;
krista@2271
    59
krista@2271
    60
        // conditions
krista@2271
    61
krista@2271
    62
        `` for "func:distinctName(condition)" | int «@name»(PEP_SESSION session`apply "parm", 0`);
krista@2271
    63
krista@2271
    64
        // states
krista@2271
    65
krista@2271
    66
        typedef enum _«@name»_state {
krista@2271
    67
            // error values also in this namespace
krista@2271
    68
            «@name»_state_invalid_state = (int) invalid_state,
krista@2271
    69
            «@name»_state_invalid_event = (int) invalid_event,
krista@2271
    70
            «@name»_state_invalid_condition = (int) invalid_condition,
krista@2271
    71
            «@name»_state_invalid_action = (int) invalid_action,
krista@2271
    72
            «@name»_state_invalid_out_of_memory = (int) invalid_out_of_memory,
krista@2271
    73
krista@2271
    74
            «@name»_state_NONE = 0,
krista@2271
    75
        `` for "func:distinctName(state)" |> «@name»`if "position()!=last()" > , `
krista@2271
    76
        } «@name»_state;
krista@2271
    77
krista@2271
    78
        // events
krista@2271
    79
krista@2271
    80
        typedef enum _«@name»_event {
krista@2271
    81
            «@name»_event_NONE = 0,
krista@2271
    82
        ||
krista@2271
    83
        for "func:distinctName(state/event[not(not(/protocol/fsm/tag/@name=@name))])" {
krista@2271
    84
            const "name", "@name";
krista@2271
    85
            |> «$name» = «/protocol/fsm/tag[@name=$name]/@id»,
krista@2271
    86
        }
krista@2271
    87
        for "func:distinctName(state/event[not(/protocol/fsm/tag/@name=@name)])"
krista@2271
    88
            |> «@name»`if "position()!=last()" > , `
krista@2271
    89
        ||
krista@2271
    90
        } «@name»_event;
krista@2271
    91
krista@2271
    92
        // actions
krista@2271
    93
krista@2271
    94
        `` const "name", "@name"
krista@2271
    95
        `` for "func:distinctName(//action)" | PEP_STATUS «@name»(PEP_SESSION session, «$name»_state state, Identity partner, void *extra);
krista@2271
    96
krista@2271
    97
        // event injector
krista@2271
    98
krista@2271
    99
        PEP_STATUS inject_DeviceState_event(
krista@2271
   100
            PEP_SESSION session, 
krista@2271
   101
            DeviceState_event event,
krista@2271
   102
            Identity partner,
krista@2271
   103
            void *extra);
krista@2271
   104
krista@2271
   105
        // message receiver
krista@2271
   106
        
krista@2271
   107
        PEP_STATUS receive_DeviceState_msg(
krista@2271
   108
                PEP_SESSION session, 
krista@2271
   109
                message *src, 
krista@2271
   110
                PEP_rating rating, 
krista@2271
   111
                stringlist_t *keylist
krista@2271
   112
            );
krista@2271
   113
krista@2271
   114
        // state machine
krista@2271
   115
krista@2271
   116
        «@name»_state fsm_«@name»(
krista@2271
   117
                PEP_SESSION session,
krista@2271
   118
                «@name»_state state,
krista@2271
   119
                «@name»_event event,
krista@2271
   120
                Identity partner,
krista@2271
   121
                void *extra,
krista@2271
   122
                time_t *timeout
krista@2271
   123
            );
krista@2271
   124
krista@2271
   125
        // driver
krista@2271
   126
krista@2271
   127
        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
krista@2271
   128
                PEP_SESSION session,
krista@2271
   129
                «@name»_event event,
krista@2271
   130
                Identity partner,
krista@2271
   131
                void *extra,
krista@2271
   132
                time_t *timeout
krista@2271
   133
            );
krista@2271
   134
krista@2271
   135
        #ifdef __cplusplus
krista@2271
   136
        }
krista@2271
   137
        #endif
krista@2271
   138
krista@2271
   139
        ||
krista@2271
   140
        }
krista@2271
   141
        document "generated/{@filename}_driver.c", "text"
krista@2271
   142
        ||
krista@2271
   143
        // Driver for «@name» state machine
krista@2271
   144
krista@2271
   145
        #include <assert.h>
krista@2271
   146
        #include "pEp_internal.h"
krista@2271
   147
krista@2271
   148
krista@2271
   149
        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
krista@2271
   150
                PEP_SESSION session,
krista@2271
   151
                «@name»_event event,
krista@2271
   152
                Identity partner,
krista@2271
   153
                void *extra,
krista@2271
   154
                time_t *timeout
krista@2271
   155
            )
krista@2271
   156
        {
krista@2271
   157
            assert(session);
krista@2271
   158
            if (!session)
krista@2271
   159
                return PEP_ILLEGAL_VALUE;
krista@2271
   160
krista@2271
   161
            while(true)
krista@2271
   162
            {
krista@2271
   163
                «@name»_state new_state = fsm_«@name»(session,
krista@2271
   164
                    session->«@filename»_state, event, partner, extra, timeout);
krista@2271
   165
krista@2271
   166
                if (new_state == «@name»_state_invalid_out_of_memory)
krista@2271
   167
                    return PEP_OUT_OF_MEMORY;
krista@2271
   168
krista@2271
   169
                if (new_state < 0)
krista@2271
   170
                    return PEP_SYNC_STATEMACHINE_ERROR - new_state;
krista@2271
   171
                
krista@2271
   172
                if (new_state == session->«@filename»_state)
krista@2271
   173
                    break;
krista@2271
   174
krista@2271
   175
                event = Init;
krista@2271
   176
                extra = NULL;
krista@2271
   177
                session->«@filename»_state = new_state;
krista@2271
   178
            } 
krista@2271
   179
krista@2271
   180
            return PEP_STATUS_OK;
krista@2271
   181
        }
krista@2271
   182
krista@2271
   183
        ||
krista@2271
   184
        document "generated/{@filename}_fsm.c", "text"
krista@2271
   185
        ||
krista@2271
   186
        #include "pEp_internal.h"
krista@2271
   187
        #include "«@filename»_fsm.h"
krista@2271
   188
        #include "«@filename»_impl.h"
krista@2271
   189
krista@2271
   190
        // local definitions for «@name»'s state machine 
krista@2271
   191
krista@2271
   192
        `` apply "state", 0 mode="declStatePayload"
krista@2271
   193
krista@2271
   194
        // state machine for «@name»
krista@2271
   195
krista@2271
   196
        «@name»_state fsm_«@name»(
krista@2271
   197
                PEP_SESSION session,
krista@2271
   198
                «@name»_state state,
krista@2271
   199
                «@name»_event event,
krista@2271
   200
                Identity partner,
krista@2271
   201
                void *extra,
krista@2271
   202
                time_t *timeout
krista@2271
   203
            )
krista@2271
   204
        {
krista@2271
   205
            PEP_STATUS status = PEP_STATUS_OK;
krista@2271
   206
krista@2271
   207
            switch (state) {
krista@2271
   208
            `` apply "state", 2
krista@2271
   209
                default:
krista@2271
   210
                    return («@name»_state) invalid_state;
krista@2271
   211
            }
krista@2271
   212
krista@2271
   213
            return state;
krista@2271
   214
        }
krista@2271
   215
krista@2271
   216
        ||
krista@2271
   217
    }
krista@2271
   218
krista@2271
   219
    template "state" {
krista@2271
   220
        ||
krista@2271
   221
        case «@name»:
krista@2271
   222
        {
krista@2271
   223
            DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»")
krista@2271
   224
        ||
krista@2271
   225
krista@2271
   226
        if "count(parm) > 0" 
krista@2271
   227
        || 
krista@2271
   228
            assert(session->sync_state_payload);
krista@2271
   229
            if(!session->sync_state_payload) return («../@name»_state) invalid_state;
krista@2271
   230
            `` apply "parm", 1 mode="unpackStatePayloadParm" with "stateName", "@name"
krista@2271
   231
        ||
krista@2271
   232
krista@2271
   233
        ||
krista@2271
   234
            switch (event) {
krista@2271
   235
        ||
krista@2271
   236
krista@2271
   237
        if "not(event[@name='Init'])" 
krista@2271
   238
        ||
krista@2271
   239
                case Init: 
krista@2271
   240
                    DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") 
krista@2271
   241
                    *timeout = «@timeout»;
krista@2271
   242
                    break;
krista@2271
   243
        ||
krista@2271
   244
krista@2271
   245
        apply "event", 2;
krista@2271
   246
krista@2271
   247
        ||
krista@2271
   248
                default:
krista@2271
   249
                    return («../@name»_state) invalid_event;
krista@2271
   250
            }
krista@2271
   251
            break;
krista@2271
   252
        }
krista@2271
   253
        ||
krista@2271
   254
    }
krista@2271
   255
krista@2271
   256
    function "pEp_type" {
krista@2271
   257
        param "type";
krista@2271
   258
krista@2271
   259
        choose {
krista@2271
   260
            when "$type = 'Identity'" > Identity
krista@2271
   261
            when "$type = 'IdentityList'" > identity_list*
krista@2271
   262
            when "$type = 'GroupKeys'" > group_keys_extra_t*
krista@2271
   263
            otherwise value "$type";
krista@2271
   264
        }
krista@2271
   265
    }
krista@2271
   266
krista@2271
   267
    function "pEp_type_op_radix" {
krista@2271
   268
        param "type";
krista@2271
   269
krista@2271
   270
        choose {
krista@2271
   271
            when "$type = 'Identity'" > identity
krista@2271
   272
            when "$type = 'IdentityList'" > identity_list
krista@2271
   273
            when "$type = 'GroupKeys'" > group_keys_extra
krista@2271
   274
            otherwise call "pEp_type" with "type", "$type";
krista@2271
   275
        }
krista@2271
   276
    }
krista@2271
   277
krista@2271
   278
    template "parm" mode="unpackStatePayloadParm" 
krista@2271
   279
    {
krista@2271
   280
        param "stateName";
krista@2271
   281
        const "pEpType" call "pEp_type" with "type","name(*[1])"; 
krista@2271
   282
        | «$pEpType» «name(*[2])» = ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»;
krista@2271
   283
    }
krista@2271
   284
krista@2271
   285
    template "state" mode="declStatePayload" if "count(parm) > 0"
krista@2271
   286
    ||
krista@2271
   287
    typedef struct _«@name»_state_payload {
krista@2271
   288
        `` apply "parm", 1 mode="declStatePayloadParm"
krista@2271
   289
    } «@name»_state_payload_t;
krista@2271
   290
krista@2271
   291
    ||
krista@2271
   292
krista@2271
   293
    template "parm" mode="declStatePayloadParm" {
krista@2271
   294
        const "pEpType" call "pEp_type" with "type","name(*[1])"; 
krista@2271
   295
        | «$pEpType» «name(*[2])»;
krista@2271
   296
    }
krista@2271
   297
krista@2271
   298
    template "event" {
krista@2271
   299
        ||
krista@2271
   300
        case «@name»:
krista@2271
   301
        {
krista@2271
   302
            DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
krista@2271
   303
        `` if "@name='Init'" |> *timeout = «../@timeout»;
krista@2271
   304
        ||
krista@2271
   305
krista@2271
   306
        if "count(parm) > 1" {
krista@2271
   307
            // TODO get ride of void *extra, pass per-event struct incl all params.
krista@2271
   308
            const "extrapEpType" call "pEp_type" with "type","name(parm[2]/*[1])"; 
krista@2271
   309
            const "extraArgName","name(parm[2]/*[2])"; 
krista@2271
   310
            |> «$extrapEpType» «$extraArgName» = («$extrapEpType»)extra;
krista@2271
   311
        }
krista@2271
   312
krista@2271
   313
        ||
krista@2271
   314
        `` apply "action|transition|condition";
krista@2271
   315
        `` if "name(*[position()=last()]) != 'transition'" |> break;
krista@2271
   316
        }
krista@2271
   317
        ||
krista@2271
   318
    }
krista@2271
   319
krista@2271
   320
    template "action" {
krista@2271
   321
        | DEBUG_LOG("FSM action", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "action=«@name»")
krista@2271
   322
        indent(0);
krista@2271
   323
        > status = «@name»(session, state, 
krista@2271
   324
        choose {
krista@2271
   325
            when "parm" > «name(parm/*)»
krista@2271
   326
            otherwise > NULL
krista@2271
   327
        }
krista@2271
   328
        choose {
krista@2271
   329
            when "count(parm) > 1" > , «name(parm[2]/*)»
krista@2271
   330
            otherwise > , NULL
krista@2271
   331
        }
krista@2271
   332
        > );\n
krista@2271
   333
        | if (status == PEP_OUT_OF_MEMORY)
krista@2271
   334
        |> return (int) invalid_out_of_memory;
krista@2271
   335
        | if (status != PEP_STATUS_OK)
krista@2271
   336
        |> return (int) invalid_action;
krista@2271
   337
    }
krista@2271
   338
krista@2271
   339
    template "condition" {
krista@2271
   340
        | {
krista@2271
   341
        |> int cond_result = «@name»(session`apply "parm", 0`);
krista@2271
   342
        |> #ifndef NDEBUG
krista@2271
   343
        |> char resstr[11] = {0,};
krista@2271
   344
        |> snprintf(resstr,10,"result=%d",cond_result);
krista@2271
   345
        |> #endif
krista@2271
   346
        |> DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr)
krista@2271
   347
        |> if (cond_result < 0)
krista@2271
   348
        |>> return cond_result;
krista@2271
   349
        |> if (cond_result) {
krista@2271
   350
        apply "action|transition|condition";
krista@2271
   351
        |> }
krista@2271
   352
        const "alternative", "./following-sibling::*[position()=1][name(.)='alternative']";
krista@2271
   353
        if "$alternative" {
krista@2271
   354
        |> else {
krista@2271
   355
        apply "$alternative/action|$alternative/transition|$alternative/condition";
krista@2271
   356
        |> }
krista@2271
   357
        }
krista@2271
   358
        | }
krista@2271
   359
    }
krista@2271
   360
krista@2271
   361
    template "parm" choose {
krista@2271
   362
        when "count(*) = 1"
krista@2271
   363
            > , «name(*)»
krista@2271
   364
        otherwise
krista@2271
   365
            > , «name(*[1])» «name(*[2])»
krista@2271
   366
    }
krista@2271
   367
krista@2271
   368
    template "transition"{
krista@2271
   369
        const "stateparm", "ancestor::state/child::parm";
krista@2271
   370
        if "count($stateparm) > 0" {
krista@2271
   371
            ||
krista@2271
   372
            assert(session->sync_state_payload);
krista@2271
   373
            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_state;
krista@2271
   374
            `` apply "$stateparm", 0 mode="freeStatePayloadParm" with "stateName", "ancestor::state/@name"
krista@2271
   375
            free(session->sync_state_payload);
krista@2271
   376
            session->sync_state_payload = NULL;
krista@2271
   377
            ||
krista@2271
   378
        }
krista@2271
   379
        if "count(parm) > 0" {
krista@2271
   380
            const "nextstatename", "@target";
krista@2271
   381
            const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
krista@2271
   382
            if "count(parm) != count($nextstateparm)" 
krista@2271
   383
                error > different state parameters and transition parameters count state=«ancestor::state/@name», event=«ancestor::event/@name» target=«@target»
krista@2271
   384
            ||
krista@2271
   385
            session->sync_state_payload = malloc(sizeof(«$nextstatename»_state_payload_t));
krista@2271
   386
            assert(session->sync_state_payload);
krista@2271
   387
            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_out_of_memory;
krista@2271
   388
            ||
krista@2271
   389
            apply "$nextstateparm", 0 mode="dupStatePayloadParm" {
krista@2271
   390
                with "stateName", "$nextstatename";
krista@2271
   391
                with "transitionParms", "parm";
krista@2271
   392
            }
krista@2271
   393
        }
krista@2271
   394
        | DEBUG_LOG("FSM transition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "target=«@target»")
krista@2271
   395
        | return «@target»;
krista@2271
   396
    }
krista@2271
   397
krista@2271
   398
    template "parm" mode="freeStatePayloadParm" 
krista@2271
   399
    {
krista@2271
   400
        param "stateName";
krista@2271
   401
        const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; 
krista@2271
   402
        | free_«$pEpTypeOpRadix»(((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»);
krista@2271
   403
    }
krista@2271
   404
krista@2271
   405
    template "parm" mode="dupStatePayloadParm" 
krista@2271
   406
    {
krista@2271
   407
        param "stateName";
krista@2271
   408
        param "transitionParms";
krista@2271
   409
        const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; 
krista@2271
   410
        const "pos", "position()";
krista@2271
   411
        | ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])» =
krista@2271
   412
        |     «$pEpTypeOpRadix»_dup(«name($transitionParms[$pos]/*)»);
krista@2271
   413
    }
krista@2271
   414
}
krista@2271
   415