Skip to content

shuvalov-mdb/xstate-cpp-generator

Repository files navigation

C++ State Machine generator for Xstate

This package allows to convert TypeScript language State Machine developed using Xstate into C++ generated SM, no coding required.

Tutorials and Documentation

Features

  • Design and test the State Machine in Xstate and then convert to C++ without any changes
  • SM basic features supported: States, Events, Transitions
    • SM extra features supported: Actions
  • Generated C++ is fully synchronized, safe to use in multi-threaded environemnt without any changes
  • No external dependencies except STL. No boost dependency.
  • Callback model:
    • Entry, Exit and Trasition Actions are code generated as static methods in the template object used to declare the State Machine and can be implemented by the user
    • Every state and transtion callbacks are generated as virtual methods that can be overloaded by subclassing
  • Arbitrary user-defined data structure (called Context) can be stored in the SM
  • Any event can have an arbitrary user-defined payload attached. The event payload is propagated to related callbacks

Install and Quick Start Tutorial

1. Install the xstate-cpp-generator TypeScript package, locally (or globally with -g option):

   npm install xstate-cpp-generator

2. Create a simple Xstate model file engineer.ts with few lines to trigger C++ generation at the end:

(this example is located at https://github.com/shuvalov-mdb/xstate-cpp-generator/tree/master/demo-project)

const CppGen = require('xstate-cpp-generator');
const path = require('path');

import { Machine } from 'xstate';

const engineerMachine = Machine({
    id: 'engineer',
    initial: 'sleeping',
    states: {
        sleeping: {
            entry: 'startWakeupTimer',
            exit: 'morningRoutine',
            on: {
                'TIMER': { target: 'working', actions: ['startHungryTimer', 'startTiredTimer'] },
            }
        },
        working: {
            entry: ['checkEmail', 'startHungryTimer', 'checkIfItsWeekend' ],
            on: {
                'HUNGRY': { target: 'eating', actions: ['checkEmail']},
                'TIRED': { target: 'sleeping' },
                'ENOUGH': { target: 'weekend' }
            },
        },
        eating: {
            entry: 'startShortTimer',
            exit: [ 'checkEmail', 'startHungryTimer' ],
            on: {
                'TIMER': { target: 'working', actions: ['startHungryTimer'] },
                'TIRED': { target: 'sleeping' }
            }
        },
        weekend: {
            type: 'final',
        }
    }
});

CppGen.generateCpp({
    xstateMachine: engineerMachine,
    destinationPath: "",
    namespace: "engineer_demo",
    pathForIncludes: "",
    tsScriptName: path.basename(__filename)
  });

To visualize this State Machine copy-paste the 'Machine' method call to the online vizualizer.

3. Generate C++

Install all required dependencies:

   npm install

And run the C++ generator:

   ts-node engineer.ts

You should see new generated files:

engineer_sm.h  engineer_sm.cpp  engineer_test.cpp

The engineer_test.cpp is an automatically generated Unit Test for the model. Create a simple SConscript file to compile it:

env = Environment()

LIBS =''

common_libs = ['gtest_main', 'gtest', 'pthread']
env.Append( LIBS = common_libs )

env.Append(CCFLAGS=['-fsanitize=address,undefined',
                    '-fno-omit-frame-pointer'],
           LINKFLAGS='-fsanitize=address,undefined')

env.Program('engineer_test', ['engineer_sm.cpp', 'engineer_test.cpp'], 
            LIBS, LIBPATH='/opt/gtest/lib:/usr/local/lib', CXXFLAGS="-std=c++17")

and run it with:

   scons
   ./engineer_test

Release Notes

V 1.0.3

  • Full support of entry, exit and transition Actions
  • Multi-threading bugfixes

V 1.0.4

  • Converted onEnteredState() from move sematics && to shared_ptr
  • Started Tutorial