Delete TODO_StateMachine.md

This commit is contained in:
Zihan Chen
2017-11-30 00:03:49 -08:00
committed by GitHub
parent 79f1bf94e0
commit 8222f8a307
-383
View File
@@ -1,383 +0,0 @@
## State Machine
### Goal
- Author methods, maybe override, using state machine
### Syntax
- `$state_machine` declaration (add methods to a class or an anonymous interface)
- `$state_input` definition
- Declare a function, which will be implemented in the state machine
- Add `override` if necessary
- If an input is not used, an error occurs
- `$state` definition
- Optional parameters
- `$goto_state` statement
- Jump to the state, providing arguments
- `$push_state` statement
- Await for a new state machine
- `$switch` statement
- Await for inputs
- Configuration for default:
- `$switch`: `default { raise "not supported input ... "; }`
- `$switch(ignore[_and_return])`: `default {[return;]}`
- `$switch(pass[_and_return])`: `default {$pass_input; [return;]}`
- `$pass_input` statement
- The next `$switch` will use the current input
### Sample
```
class Calculator
{
var valueFirst : string = "";
var op : string = "";
prop Value : string = "0";
func Update(value : string) : void
{
SetValue(value);
valueFirst = value;
}
func Calculate() : void
{
if (valueFirst == "")
{
valueFirst = value;
}
else if (op == "+")
{
Update((cast double valueFirst) + (cast double Value));
}
else if (op == "*")
{
Update((cast double valueFirst) * (cast double Value));
}
else
{
raise $"Unrecognized operator: $(op)";
}
}
$state_machine
{
$state_input Digit(i : int);
$state_input Dot();
$state_input Add();
$state_input Mul();
$state_input Equal();
$state_input Clear();
$state Digits()
{
$switch(pass)
{
case Digit(i)
{
Value = Value & i;
$goto_state Digits();
}
}
}
$state Integer(newNumber: bool)
{
$switch(pass)
{
case Digit(i)
{
if (newNumber)
{
Value = i;
}
else
{
Value = Value & i;
}
$goto_state Digits();
}
}
}
$state Number()
{
$push_state Integer(true);
$switch(pass_and_return)
{
case Dot()
{
Value = Value & ".";
}
}
$push_state Integer(false);
}
$state Calculate()
{
$push_state Number();
$switch
{
case Add(): {Calculate(); op = "+";}
case Mul(): {Calculate(); op = "-";}
case Equal(): {Calculate(); op = "=";}
case Clear():
{
valueFirst = "";
op = "";
Value = "0";
}
}
$goto_state Calculate();
}
$state
{
$goto_state Calculate();
}
}
}
func Main(): string
{
var calculator = new Calculator^();
calculator.Digit(1);
calculator.Digit(2);
calculator.Add();
calculator.Digit(3);
calculator.Digit(4);
calculator.Equal();
return calculator.Value; // "46"
}
```
### Generated
```
class Calculator
{
   ... // ignored everything before $state_machine
enum <state>Input
{
<state>Invalid = 0,
Digit = 1,
Dot = 2,
Add = 3,
Mul = 4,
Equal = 5,
Clear = 6,
}
enum <state>State
{
<state>Invalid = 0,
<state>Start = 1,
Digits = 2,
Integer = 3,
Number = 4,
Calculate = 5,
}
[cpp:Private]
var <state>input: <State>Input = ::Calculator::<state>Input::<state>Invalid;
[cpp:Private]
var <state>coroutine: ::system::Coroutine^ = null;
[cpp:Private]
var <statep-Digit>i: int = 0;
[cpp:Private]
func <state>Resume(): void
{
var <state>previousResult: ::system::CoroutineResult^ = null;
while (true)
{
if (<state>coroutine: is null)
{
if (<state>previousResult is not null)
{
if (<state>previousResult.Failure is not null)
{
raise <state>Result.Failure;
}
}
break;
}
           if (<state>coroutine.Status != ::system::CoroutineStatus::Stopped)
{
var <state>currentCoroutine = <state>coroutine;
<state>currentCoroutine.Status.Resume(true, <state>previousResult);
if (<state>coroutine == <state>currentCoroutine)
{
break; // wait for input
}
else if (<state>currentCoroutine.Status == ::system::CoroutineStatus::Stopped)
{
// leave a state machine
<state>previousResult = new ::system::CoroutineResult^();
if (<state>currentCoroutine.Failure is not null)
{
<state>previousResult.Failure = <state>currentCoroutine.Failure;
}
}
else
{
// enter a state machine
break;
}
}
       }
}
func Digit(i: int): void { <state>input = ::Calculator::<state>Input::Digit; <statep-Digit>i = i; <state>Resume(); }
func Dot(): void { <state>input = ::Calculator::<state>Input::Dot; <state>Resume(); }
func Add(): void { <state>input = ::Calculator::<state>Input::Add; <state>Resume(); }
func Mul(): void { <state>input = ::Calculator::<state>Input::Mul; <state>Resume(); }
func Equal(): void { <state>input = ::Calculator::<state>Input::Equal; <state>Resume(); }
func Clear(): void { <state>input = ::Calculator::<state>Input::Clear; <state>Resume(); }
[cpp:Private]
func <state>CreateCoroutine(<state>startState: <state>State): void
{
<state>previousCoroutine = <state>coroutine;
<state>coroutine = $coroutine
{
try
{
var <state>state : <state>State = <state>startState;
while (true)
{
var <state>currentState = <state>state;
<state>state = ::Calculator::<state>State::<state>Invalid;
switch (<state>currentState)
{
case ::Calculator::<state>State::<state>Start :
{
<state>state = ::Calculator::<state>State::Calculate;
goto <state-label>OUT_OF_STATES; // goto can only jump to the end of a containing block
goto <state-label>OUT_OF_STATE_MACHINE;
}
case ::Calculator::<state>State::Digits :
{
$pause;
switch (<state>input)
{
case ::Calculator::<state>Input::Digit
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
var i = <statep-Digit>i;
Value = Value & i;
<state>state = ::Calculator::<state>State::Digits;
goto <state-label>OUT_OF_STATES;
}
}
goto <state-label>OUT_OF_STATE_MACHINE;
}
case ::Calculator::<state>State::Integer :
{
$pause;
switch (<state>input)
{
case ::Calculator::<state>Input::Digit
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
var i = <statep-Digit>i;
if (newNumber) // TODO: Declare the parameter
{
Value = i;
}
else
{
Value = Value & i;
}
<state>state = ::Calculator::<state>State::Digits;
goto <state-label>OUT_OF_STATES;
}
}
goto <state-label>OUT_OF_STATE_MACHINE;
}
case ::Calculator::<state>State::Number :
{
// TODO: Pass the parameter (true)
<state>CreateCoroutine(::Calculator::<state>State::Integer);
$pause;
$pause;
switch (<state>input)
{
case ::Calculator::<state>::Input::Dot:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
Value = Value & ".";
}
default:
{
goto <state-label>OUT_OF_STATE_MACHINE; // pass_and_return
}
}
// TODO: Pass the parameter (false)
<state>CreateCoroutine(::Calculator::<state>State::Integer);
$pause;
}
case ::Calculator::<state>State::Calculate :
{
<state>CreateCoroutine(::Calculator::<state>State::Number);
$pause;
$pause;
switch (<state>input)
{
case ::Calculator::<state>::Input::Add:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
Calculate(); op = "+";
}
case ::Calculator::<state>::Input::Mul:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
Calculate(); op = "*";
}
case ::Calculator::<state>::Input::Equal:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
Calculate(); op = "=";
}
case ::Calculator::<state>::Input::Clear:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
valueFirst = "";
op = "";
Value = "0";
}
case ::Calculator::<state>::Input::Digit:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
raise "Calculator::Digit cannot be called at this moment.";
}
case ::Calculator::<state>::Input::Dot:
{
<state>input = ::Calculator::<state>Input::<state>Invalid;
raise "Calculator::Dot cannot be called at this moment.";
}
}
<state>state = ::Calculator::<state>State::Calculate;
goto <state-label>OUT_OF_STATES;
goto <state-label>OUT_OF_STATE_MACHINE;
}
}
<state-label>OUT_OF_CURRENT_STATE:; // label can only appear at the end of a block statement
}
<state-label>OUT_OF_STATE_MACHINE:;
}
finally
{
<state>coroutine = <state>previousCoroutine;
}
};
}
   new()
{
<state>CreateCoroutine(:Calculator::<state>State::<state>Start);
<state>Resume();
}
}
```