mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-05-12 18:40:11 +08:00
5.3 KiB
5.3 KiB
Proposal (Workflow State Machine)
Goal
To implement
- Async operations
- Delayed operations
- State machine (visual state, animation)
Agenda
- State Machine Interface
- Raw state machine
- Extension Syntax
- Extension (Enumerable, $Yield)
- Extension (Task, $Await, return)
- Extension (State Machine)
Extension (Syntax)
returnis always mapped toReturnAndExit- If
returnhas an expression, thanReturnAndExitshould also have an argument
- If
$<OPERATOR> ...;is available if<OPERATOR>AndReador<OPERATOR>AndPauseexistsvar NAME = $<OPERATOR> ...;is available if<OPERATOR>AndReadexists- The return type is object, except that there is a
static func CastResult(value : object):Tin one of the argument types - Use the first available and correct CastResult that is discovered
- The return type is object, except that there is a
- A function body begins with
${or$<PROVIDER>{means this is a coroutine function- If the provider is not omitted, it will search for a type named
<PROVIDER>, and than use<PROVIDER>Coroutineas the provider - If the provider is omitted, it will search the return type and its base types in order, and find the first existing
<TYPE>Coroutineclass as the provider - A provider is only choosen by name. If the class ending with
Coroutinedoesn't have appropriate functions, errors occur. - For example:
func F() : int[] ${}returnsint[], which issystem::Enumerable, sosystem::EnumerableCoroutineis used.func F() : IDownloadAsync^ ${}returnsIDownloadAsync, which has a base interfacesystem::Async, sosystem::AsyncCoroutineis used.func F() : void $Async{}has a providerAsync, sosystem::AsyncCoroutineis used.
- If the provider is not omitted, it will search for a type named
- If the function return type does not match the provider's
Createfunction- If the function returns void, then
CreateAndRunis used - In other cases:
- Cast from InterfaceA to InterfaceB
- InterfaceB is required to inherit from InterfaceA
- Fail if InterfaceB has extra methods
- If the function returns void, then
Extension (State Machine Interface)
Declare input methods in interfaces
$input Name(a:Ta, b:Tb);declarationfunc Name(a:Ta, b:Tb) : bool- Returns false if a failed input causes a retry
- No overloading
prop NameEnabled : bool {const}var <prop>NameEnabled : bool = false;func GetNameEnabled() : bool { ... }func SetNameEnabled(<value> : bool) : void { ... }
Statements in $state declarations
$input[_else_exit] { case <INPUT-NAME>(arguments...): { ... } ... }statement- If the input is failed to match
$input_else_exit: exit the current state scope$input: retry
- If the input is failed to match
$input[_else_exit] <INPUT-NAME>(arguments...) (;|{ ... })statement- Short for
$input[_else_exit] { case <INPUT-NAME>(arguments...): { ... } }
- Short for
$join <NAME>;statement- Enter the specified state
$join { ... }statement- Create a state scope, if any
$input_else_exitfailed inside, exit the$joinstatement
- Create a state scope, if any
Declare states inside a new interface expression
$state <NAME> { ... }- Define a sub state machine
$state { ... }- Define a state machine as the entry
- Cannot create dead loop for any failed input
- Example:
$state { while (true) { $join { $input_else_exit DoSomething(); } } }
- Example:
Sample
interface ICalculator : Coroutine
{
$input Digit(i : int);
$input Dot();
$input Add();
$input Mul();
$input Equal();
$input Clear();
prop Value : string {const}
}
var calculator = new ICalculator^
{
var valueFirst : string = "";
var op : string = "";
override 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 Digits()
{
while (true)
{
$input_else_exit Digit(i)
{
Value = Value & i;
}
}
}
$state Integer()
{
$input_else_exit Digit(i)
{
Value = i;
$join Digits();
}
}
$state Number()
{
$join Integer();
$input_else_exit Dot()
{
Value = Value & ".";
}
$input Digit(i)
{
Value = Value & i;
}
$join Digits();
}
$state
{
while (true)
{
$join Number();
$input
{
case Add(): {Calculate(); op = "+";}
case Mul(): {Calculate(); op = "-";}
case Equal(): {Calculate(); op = "=";}
case Clear():
{
valueFirst = "";
op = "";
Value = "0";
}
}
}
}
};