mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-05-19 02:25:04 +08:00
Delete TODO_StateMachine.md
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user