STM by CSV is converted according to the following rules.
The replacement map is described according to the following specifications.
Since the string generated by this function is the source code of the D language, it can be embedded in the actual code after saving it in the file, or it can be used directly by mixin(). The "states" are generated as an enum type named State, and the "events" are generated as an enum type named Event. STM instance is generated by executing the generated factory function that name can be specified by factoryName with makeStm as its default name.
Example is following.
This case explains how to operate the music player with the start button and the stop button. The players play music when the start button is pressed while stopping. And when you press the start button during playing, the behavior will change and music playback will pause. When the stop button is pressed, the player stops music playback and returns to the initial state.
When this specification is made to STM, the following table can be created.
stmcsv:
*MusicPlayer* | #>stop | #>play | #>pause |
---|---|---|---|
StartAct. | |||
EndAct. | |||
onStart | #>play - Start music | #>pause - Stop music | #>play - Start music |
onStop | #>stop - Stop music - Return to first | #>stop - Return to first |
In each cell of the table, the transition destination and processing are described in natural language. Representations in natural language are replaced by the following map table and converted into a program expression in D. One line in each cell is subject to replacement. However, those that do not exist in the replacement map are not replaced.
mapcsv:
#>stop | stop |
#>play | play |
#>pause | pause |
- Start music | startMusic(); |
- Stop music | stopMusic(); |
- Return to first | resetMusic(); |
To execute the pair of STM and replacement map as code, see the following code:
1 import std.string, std.datetime.stopwatch; 2 // STM 3 enum stmcsv = ` 4 *MusicPlayer*,#>stop,#>play,#>pause 5 StartAct,,, 6 EndAct,,, 7 onStart,"#>play\n- Start music","#>pause\n- Stop music","#>play\n- Start music" 8 onStop,,"#>stop\n- Stop music\n- Return to first","#>stop\n- Return to first"` 9 .strip("\n").outdent.replace(`\n`,"\n"); 10 11 // replacement mapping data 12 enum mapcsv = ` 13 #>stop,stop 14 #>play,play 15 #>pause,pause 16 - Start music,startMusic(); 17 - Stop music,stopMusic(); 18 - Return to first,resetMusic();` 19 .strip("\n").outdent.replace(`\n`,"\n"); 20 21 // Programs to be driven by STM 22 string status = "stopped"; 23 StopWatch playTime; 24 void startMusic() { playTime.start(); status = "playing"; } 25 void stopMusic() { playTime.stop(); status = "stopped"; } 26 void resetMusic() { playTime.reset(); } 27 28 // Generate code from STM(csv data) and mapping data 29 enum stmcode = decodeStmFromCsv(stmcsv, mapcsv, null, null, "#>", "makeStm"); 30 // string mixin. Here the code is expanded. 31 // The code contains the enum of State and Event, 32 // activity functions and proccess when transtition. 33 mixin(stmcode); 34 35 // Create StateTransitor instance 36 // By executing this function, construction of StateTransitor, 37 // registration of various handlers, name setting of the matrix and states / events are performed. 38 auto stm = makeStm(); 39 40 // Initial state is "stop" that most left state. 41 assert(stm.currentState == State.stop); 42 // At run time, display names of the state are gettable 43 assert(stm.getStateName(stm.currentState) == "#>stop"); 44 // Likewise, event names are also gettable 45 // In this case, event names are not replaced by mapcsv datas, 46 // this code in following line gets the same string as the enum member of Event. 47 assert(stm.getEventName(Event.onStart) == "onStart"); 48 49 // When the onStart event occurs, based on the STM, 50 // it transit to the "#>play" state and play music. 51 stm.put(Event.onStart); 52 assert(stm.currentState == State.play); 53 assert(playTime.running); 54 () @trusted { import core.thread; Thread.sleep(10.msecs); }(); // progress in playing... 55 assert(playTime.peek != 0.msecs); 56 57 // If push the play button again during playing, it pauses. 58 stm.put(Event.onStart); 59 assert(stm.currentState == State.pause); 60 assert(!playTime.running); 61 62 // When you press the stop button, the player stops and returns to the first stop state 63 stm.put(Event.onStop); 64 assert(stm.currentState == State.stop); 65 assert(!playTime.running); 66 () @trusted { import core.thread; Thread.sleep(10.msecs); }(); // progress in stopped... 67 assert(playTime.peek == 0.msecs);
Following example is case of network communication in Japanese.
1 import std.string; 2 enum stmcsv = ` 3 ,▽初期,▽接続中,▽通信中,▽切断中 4 スタートアクティビティ,,接続要求を開始,,切断要求を開始 5 エンドアクティビティ,,接続要求を停止,,切断要求を停止 6 接続の開始指示を受けたら,▽接続中,,x,x 7 接続の停止指示を受けたら,,▽切断中,▽切断中, 8 通信が開始されたら,▽切断中,▽通信中,x,x 9 通信が切断されたら,x,▽初期,▽初期,▽初期` 10 .strip("\n").outdent.replace(`\n`,"\n"); 11 12 enum replaceData = ` 13 ▽初期,init 14 ▽接続中,connectBeginning 15 ▽通信中,connecting 16 ▽切断中,connectClosing 17 通信が開始されたら,openedConnection 18 通信が切断されたら,closedConnection 19 接続の開始指示を受けたら,openConnection 20 接続の停止指示を受けたら,closeConnection 21 接続要求を開始,startBeginConnect(); 22 接続要求を停止,endBeginConnect(); 23 切断要求を開始,startCloseConnect(); 24 切断要求を停止,endCloseConnect();` 25 .strip("\n").outdent.replace(`\n`,"\n"); 26 27 enum stmcode = decodeStmFromCsv(stmcsv, replaceData); 28 int x; 29 void startBeginConnect() 30 { 31 x = 1; 32 } 33 void endBeginConnect() 34 { 35 x = 2; 36 } 37 void startCloseConnect() 38 { 39 x = 3; 40 } 41 void endCloseConnect() 42 { 43 x = 4; 44 } 45 46 mixin(stmcode); 47 auto stm = makeStm(); 48 assert(stm.getStateName(State.init) == "▽初期"); 49 assert(stm.getStateName(stm.currentState) == "▽初期"); 50 assert(x == 0); 51 stm.put(Event.openConnection); 52 assert(x == 1); 53 assert(stm.getStateName(stm.currentState) == "▽接続中"); 54 assert(stm.currentState == State.connectBeginning); 55 stm.put(Event.openedConnection); 56 assert(x == 2); 57 assert(stm.getStateName(stm.currentState) == "▽通信中"); 58 assert(stm.currentState == State.connecting); 59 stm.put(Event.closeConnection); 60 assert(x == 3); 61 assert(stm.getStateName(stm.currentState) == "▽切断中"); 62 assert(stm.currentState == State.connectClosing); 63 stm.put(Event.closedConnection); 64 assert(x == 4); 65 assert(stm.getStateName(stm.currentState) == "▽初期"); 66 assert(stm.currentState == State.init);
Decode to D language code from STM of CSV
In the first argument, STM in CSV format is passed as a string. And in the second argument, replacement map in CSV format is passed as a string. This CSV pair will be decoded into the code in D language.