diff --git a/TODO_StateMachine.md b/TODO_StateMachine.md deleted file mode 100644 index 5042206b..00000000 --- a/TODO_StateMachine.md +++ /dev/null @@ -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 Input - { - Invalid = 0, - Digit = 1, - Dot = 2, - Add = 3, - Mul = 4, - Equal = 5, - Clear = 6, - } - - enum State - { - Invalid = 0, - Start = 1, - Digits = 2, - Integer = 3, - Number = 4, - Calculate = 5, - } - - [cpp:Private] - var input: Input = ::Calculator::Input::Invalid; - - [cpp:Private] - var coroutine: ::system::Coroutine^ = null; - - [cpp:Private] - var i: int = 0; - - [cpp:Private] - func Resume(): void - { - var previousResult: ::system::CoroutineResult^ = null; - while (true) - { - if (coroutine: is null) - { - if (previousResult is not null) - { - if (previousResult.Failure is not null) - { - raise Result.Failure; - } - } - break; - } -            if (coroutine.Status != ::system::CoroutineStatus::Stopped) - { - var currentCoroutine = coroutine; - currentCoroutine.Status.Resume(true, previousResult); - if (coroutine == currentCoroutine) - { - break; // wait for input - } - else if (currentCoroutine.Status == ::system::CoroutineStatus::Stopped) - { - // leave a state machine - previousResult = new ::system::CoroutineResult^(); - if (currentCoroutine.Failure is not null) - { - previousResult.Failure = currentCoroutine.Failure; - } - } - else - { - // enter a state machine - break; - } - } -        } - } - - func Digit(i: int): void { input = ::Calculator::Input::Digit; i = i; Resume(); } - func Dot(): void { input = ::Calculator::Input::Dot; Resume(); } - func Add(): void { input = ::Calculator::Input::Add; Resume(); } - func Mul(): void { input = ::Calculator::Input::Mul; Resume(); } - func Equal(): void { input = ::Calculator::Input::Equal; Resume(); } - func Clear(): void { input = ::Calculator::Input::Clear; Resume(); } - - [cpp:Private] - func CreateCoroutine(startState: State): void - { - previousCoroutine = coroutine; - coroutine = $coroutine - { - try - { - var state : State = startState; - - while (true) - { - var currentState = state; - state = ::Calculator::State::Invalid; - switch (currentState) - { - case ::Calculator::State::Start : - { - state = ::Calculator::State::Calculate; - goto OUT_OF_STATES; // goto can only jump to the end of a containing block - goto OUT_OF_STATE_MACHINE; - } - case ::Calculator::State::Digits : - { - $pause; - switch (input) - { - case ::Calculator::Input::Digit - { - input = ::Calculator::Input::Invalid; - var i = i; - Value = Value & i; - state = ::Calculator::State::Digits; - goto OUT_OF_STATES; - } - } - goto OUT_OF_STATE_MACHINE; - } - case ::Calculator::State::Integer : - { - $pause; - switch (input) - { - case ::Calculator::Input::Digit - { - input = ::Calculator::Input::Invalid; - var i = i; - if (newNumber) // TODO: Declare the parameter - { - Value = i; - } - else - { - Value = Value & i; - } - state = ::Calculator::State::Digits; - goto OUT_OF_STATES; - } - } - goto OUT_OF_STATE_MACHINE; - } - case ::Calculator::State::Number : - { - // TODO: Pass the parameter (true) - CreateCoroutine(::Calculator::State::Integer); - $pause; - $pause; - switch (input) - { - case ::Calculator::::Input::Dot: - { - input = ::Calculator::Input::Invalid; - Value = Value & "."; - } - default: - { - goto OUT_OF_STATE_MACHINE; // pass_and_return - } - } - // TODO: Pass the parameter (false) - CreateCoroutine(::Calculator::State::Integer); - $pause; - } - case ::Calculator::State::Calculate : - { - CreateCoroutine(::Calculator::State::Number); - $pause; - $pause; - switch (input) - { - case ::Calculator::::Input::Add: - { - input = ::Calculator::Input::Invalid; - Calculate(); op = "+"; - } - case ::Calculator::::Input::Mul: - { - input = ::Calculator::Input::Invalid; - Calculate(); op = "*"; - } - case ::Calculator::::Input::Equal: - { - input = ::Calculator::Input::Invalid; - Calculate(); op = "="; - } - case ::Calculator::::Input::Clear: - { - input = ::Calculator::Input::Invalid; - valueFirst = ""; - op = ""; - Value = "0"; - } - case ::Calculator::::Input::Digit: - { - input = ::Calculator::Input::Invalid; - raise "Calculator::Digit cannot be called at this moment."; - } - case ::Calculator::::Input::Dot: - { - input = ::Calculator::Input::Invalid; - raise "Calculator::Dot cannot be called at this moment."; - } - } - state = ::Calculator::State::Calculate; - goto OUT_OF_STATES; - goto OUT_OF_STATE_MACHINE; - } - } - OUT_OF_CURRENT_STATE:; // label can only appear at the end of a block statement - } - OUT_OF_STATE_MACHINE:; - } - finally - { - coroutine = previousCoroutine; - } - }; - } - -    new() - { - CreateCoroutine(:Calculator::State::Start); - Resume(); - } -} -```