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