UNPKG

webgme-hfsm

Version:

WebGME Domain for creating Executable Heirarchical Finite State Machines (HFSMs). Contains metamodel, visualization, simulation, and code generation for Heirarchical Finite State Machines (HFSMs) following the UML State Machine specification.

318 lines (282 loc) 11.5 kB
define(['bower/handlebars/handlebars.min', 'underscore', 'text!./static/magic_enum.hpp', 'text!./static/state_base.hpp', 'text!./static/deep_history_state.hpp', 'text!./static/shallow_history_state.hpp', 'text!./InternalEvent.tmpl', 'text!./ExternalEvent.tmpl', 'text!./ExternalTransition.tmpl', 'text!./ExecuteTransition.tmpl', 'text!./InitTransition.tmpl', 'text!./Initialize.tmpl', 'text!./StateTempl.hpp', 'text!./StateTempl.cpp', 'text!./EndStateTempl.hpp', 'text!./ChoiceState.tmpl', 'text!./Pointer.hpp', 'text!./Constructor.tmpl', 'text!./GeneratedEventData.hpp', 'text!./GeneratedStates.hpp', 'text!./GeneratedStates.cpp'], function(handlebars, _, MagicEnumData, StateBaseData, DeepHistoryData, ShallowHistoryData, InternalEventTempl, ExternalEventTempl, ExternalTransitionTempl, ExecuteTransitionTempl, InitTransitionTempl, InitializeTempl, StateTemplHpp, StateTemplCpp, EndStateTemplHpp, ChoiceStateTempl, PointerTemplHpp, ConstructorTempl, GeneratedEventDataTemplHpp, GeneratedStatesTemplHpp, GeneratedStatesTemplCpp) { 'use strict'; var staticFiles = { 'magic_enum.hpp': MagicEnumData, }; var Partials = { InternalEventTempl: InternalEventTempl, ExternalEventTempl: ExternalEventTempl, ExternalTransitionTempl: ExternalTransitionTempl, ExecuteTransitionTempl: ExecuteTransitionTempl, InitTransitionTempl: InitTransitionTempl, InitializeTempl: InitializeTempl, StateTemplHpp: StateTemplHpp, StateTemplCpp: StateTemplCpp, EndStateTemplHpp: EndStateTemplHpp, ChoiceStateTempl: ChoiceStateTempl, PointerTemplHpp: PointerTemplHpp, ConstructorTempl: ConstructorTempl, GeneratedEventDataTemplHpp: GeneratedEventDataTemplHpp, GeneratedStatesTemplHpp: GeneratedStatesTemplHpp, GeneratedStatesTemplCpp: GeneratedStatesTemplCpp, StateBaseData: StateBaseData, DeepHistoryData: DeepHistoryData, ShallowHistoryData: ShallowHistoryData, }; var rootTemplates = [ "StateBaseData", "DeepHistoryData", "ShallowHistoryData", "GeneratedEventDataTemplHpp", "GeneratedStatesTemplHpp", "GeneratedStatesTemplCpp" ]; var keyTemplates = { 'StateBaseData': 'state_base.hpp', 'DeepHistoryData': 'deep_history_state.hpp', 'ShallowHistoryData': 'shallow_history_state.hpp', 'GeneratedEventDataTemplHpp': '{{{sanitizedName}}}_event_data.hpp', 'GeneratedStatesTemplHpp': '{{{sanitizedName}}}_generated_states.hpp', 'GeneratedStatesTemplCpp': '{{{sanitizedName}}}_generated_states.cpp', }; var dependencies = { 'GeneratedStatesTemplCpp': [ 'GeneratedStatesTemplHpp', ] }; var localRoot = null; function objInBranchOfRoot(obj, root) { return root && obj && obj.path && obj.path.indexOf( root.path ) > -1; }; function getBranch( obj ) { var branch = []; if ( objInBranchOfRoot(obj, localRoot) ) { // this obj is within the localRoot's tree var currentObj = localRoot; var matchedPath = currentObj.path; branch.push( currentObj ); while (matchedPath != obj.path) { var children = currentObj.State_list.filter(function(s) { return obj.path.indexOf( s.path ) > -1; }); if (children.length) { var child = children[0]; currentObj = child; branch.push( currentObj ); matchedPath = currentObj.path; } else break; } } return branch; }; function getCommonRoot( a, b ) { var commonRoot = b; var startList = getBranch( a ); var endList = getBranch( b ); var intersection = _.intersection(startList, endList); if (intersection.length) { commonRoot = intersection[ intersection.length - 1 ]; } return commonRoot; }; function sameBranch( a, b ) { return a.path.indexOf(b.path) > -1 || b.path.indexOf(a.path) > -1; }; function getStateExits( root, oldState, newState, isLocal ) { var rootList = getBranch( root ); var stateList = getBranch( oldState ); // cases: // 1. make sure external transitions along the branch re-enter root // 2. make sure local transitions along branch do not re-enter root if (isLocal) { } else { if (sameBranch(oldState, newState)) { rootList = rootList.filter((a) => { return a != root; }); } } var exits = _.difference( stateList, rootList ) || []; return exits.reverse(); }; function getStateEntries( root, oldState, newState, isLocal ) { var rootList = getBranch( root ); var stateList = getBranch( newState ); // cases: // 1. make sure external transitions along the branch re-enter root // 2. make sure local transitions along branch do not re-enter root if (isLocal) { } else { if (sameBranch(oldState, newState)) { rootList = rootList.filter((a) => { return a != root; }); } } // need to make sure not to render entries for history pseudostates if (["Deep History Pseudostate", "Shallow History Pseudostate"].indexOf(newState.type) > -1) { stateList = stateList.filter((a) => { return a != newState }); } var entries = _.difference( stateList, rootList ) || []; return entries; }; handlebars.registerHelper('renderTransition', function( options ) { var rendered = ''; var renderExit = options.hash.exit && options.hash.exit == "true"; var renderEntry = options.hash.entry && options.hash.entry == "true"; var transition = options.hash.transition; var transitions = new Array(); if (transition.previousTransitions) { transitions = transitions.concat( transition.previousTransitions); } transitions.push( transition ); var prevState = transitions[0].prevState; var nextState = transitions[ transitions.length - 1 ].nextState; var rootState = getCommonRoot( prevState, nextState ); var isLocal = transitions.length == 1 && transitions[0].isLocalTransition; if (renderExit) { // all exits from root down to new var exits = getStateExits(rootState, prevState, nextState, isLocal); rendered += [ '// Call all from prev state down exits', '_root->' + prevState.pointerName + '.exitChildren();', '' ].join('\n'); exits.map(function(e) { rendered += renderKey( e, 'exit' ); }); } // all transition actions from old to new transitions.map(function(trans) { // render action rendered += renderKey( trans, 'Action' ); }); if (renderEntry) { // all entries from root down to new var entries = getStateEntries(rootState, prevState, nextState, isLocal); if (isLocal) { entries = entries.filter((s) => { return s !== rootState && s !== prevState; }); } entries.map(function(e) { rendered += renderKey( e, 'entry' ); }); } var finalState = transition.nextState; rendered += renderDebugOutput( transitions[0].prevState, finalState ); return rendered; }); function renderKey( obj, key ) { var a = [ '// ' + obj.type + ' : ' + key + ' for: '+obj.path, ]; if (obj.pointerName) { a = a.concat([ '_root->' + obj.pointerName + '.'+key+'();', ]); } else { a = a.concat([ '_root->log("\\033[36mTRANSITION::ACTION for '+obj.path+'\\033[0m");', '', '//::::'+obj.path+'::::'+key+'::::', obj[key], ]); } a.push(''); return a.join('\n'); }; function renderDebugOutput( start, end ) { var a = []; if (start.fullyQualifiedName) { a = a.concat([ '_root->log("\\033[31mSTATE TRANSITION: '+ start.fullyQualifiedName+'->'+end.fullyQualifiedName+'\\033[0m");', '' ]); } return a.join('\n'); }; handlebars.registerHelper('addTransition', function(options) { var context = {}, mergeContext = function(obj) { for(var k in obj)context[k]=obj[k]; }; mergeContext(this); var trans = options.hash.trans; var previousTransitions = new Array(); if ( options.hash.previous ) previousTransitions = previousTransitions.concat( options.hash.previous ); previousTransitions.push( trans ); context.previousTransitions = previousTransitions; return options.fn(context); }); Object.keys(Partials).map(function(partialName) { handlebars.registerPartial( partialName, Partials[ partialName ] ); }); function getKey(templName, root) { var keyTempl = keyTemplates[ templName ]; return handlebars.compile( keyTempl )( root ); }; function getContext( templName, root ) { var key = getKey( templName, root ); var deps = dependencies[ templName ] || []; deps = deps.map(function(dep) { return getKey( dep, root ); }); return Object.assign({ key: key, dependencies: deps }, root); }; return { renderStatic: function() { return staticFiles; }, renderStates: function(root) { var rendered = {}; localRoot = root; rootTemplates.map(function(rootTemplName) { var context = getContext( rootTemplName, root ); rendered[ context.key ] = handlebars.compile( Partials[ rootTemplName ] )( context ); }); return rendered; }, }; }); // define( [], function() {} );