/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppGlrParser.h"
#include "VlppReflection.h"
#include "VlppOS.h"
#include "Vlpp.h"
#include "VlppRegex.h"
/***********************************************************************
.\WFRUNTIMEINSTRUCTION.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)
Workflow::Runtime
Interfaces:
**********************************************************************/
#ifndef VCZH_WORKFLOW_RUNTIME_WFRUNTIMEINSTRUCTION
#define VCZH_WORKFLOW_RUNTIME_WFRUNTIMEINSTRUCTION
namespace vl
{
namespace workflow
{
namespace runtime
{
/***********************************************************************
Instruction
***********************************************************************/
enum class WfInsCode
{
// Instruction // param : -> in the order of
Nop, // : () -> () ;
LoadValue, // value : () -> Value ;
LoadFunction, // function : () -> Value ; push the function index
LoadException, // : () -> Value ;
LoadLocalVar, // variable : () -> Value ;
LoadCapturedVar, // variable : () -> Value ;
LoadGlobalVar, // variable : () -> Value ;
LoadMethodInfo, // IMethodInfo* : () -> IMethodInfo* ;
LoadMethodClosure, // IMethodInfo* : Value-this -> ;
LoadClosureContext, // : () -> ; load the current closure context
StoreLocalVar, // variable : Value -> () ;
StoreCapturedVar, // variable : Value -> () ;
StoreGlobalVar, // variable : Value -> () ;
Duplicate, // count : () -> Value ; copy stack[stack.Count()-1-count]
Pop, // : Value -> () ;
Return, // : Value -> Value ; (exit function)
NewArray, // count : Value-count, ..., Value-1 -> ; {1 2 3} -> <3 2 1>
NewList, // count : Value-count, ..., Value-1 -> ; {1 2 3} -> <3 2 1>
NewObservableList, // count : Value-count, ..., Value-1 -> ; {1 2 3} -> <3 2 1>
NewDictionary, // count : Value-count*2, ..., Value-1 ->
///
enum State
{ // Run Pause Stop StepOver StepInto
/// The associated thread is running Workflow script.
Running, // R *RTP *RTS
/// The target Workflow script is paused by operations other than break points.
PauseByOperation, // PBO *C *RTS *C *C
/// The target Workflow script is paused by break points.
PauseByBreakPoint, // PBB *C *RTS *C *C
/// The associated thread has stopped running Workflow script.
Stopped, // S *RTP * *
/// The debugger allows the target Workflow script to continue.
Continue, // C soon becomes Running
/// The target Workflow script is required to pause. This value can be observed in . Operations to continue executing the Workflow script await to be called.
RequiredToPause, // RTP soon becomes PauseByOperation (should be triggered in OnBlockExecution)
/// The target Workflow script is required to stop. It caused to Workflow script to stop by throwing an exception saying this.
RequiredToStop, // RTS soon becomes Stopped (should be triggered in OnBlockExecution)
};
enum RunningType
{
RunUntilBreakPoint,
RunStepOver,
RunStepInto,
};
struct InstructionLocation
{
vint contextIndex = -1;
WfAssembly* assembly = nullptr;
vint stackFrameIndex = -1;
vint instruction = -1;
bool BreakStepOver(const InstructionLocation& il, bool beforeCodegen);
bool BreakStepInto(const InstructionLocation& il, bool beforeCodegen);
};
static const vint InvalidBreakPoint = -1;
static const vint PauseBreakPoint = -2;
protected:
BreakPointList breakPoints;
collections::List freeBreakPointIndices;
volatile bool evaluatingBreakPoint = false;
volatile bool breakException = false;
ThreadContextList threadContexts;
volatile State state = Stopped;
volatile RunningType runningType = RunUntilBreakPoint;
volatile vint lastActivatedBreakPoint = InvalidBreakPoint;
bool stepBeforeCodegen = true;
InstructionLocation instructionLocation;
AssemblyBreakPointMap insBreakPoints;
AssemblyBreakPointMap getGlobalVarBreakPoints;
AssemblyBreakPointMap setGlobalVarBreakPoints;
PropertyBreakPointMap getPropertyBreakPoints;
PropertyBreakPointMap setPropertyBreakPoints;
EventBreakPointMap attachEventBreakPoints;
EventBreakPointMap detachEventBreakPoints;
EventBreakPointMap invokeEventBreakPoints;
MethodBreakPointMap invokeMethodBreakPoints;
TypeBreakPointMap createObjectBreakPoints;
/// Called for doing something when a break point is activated. This function will be called multiple times before some one let the debugger to continue.
/// This function must be overrided, or the Workflow script will hang when it is paused by any reason.
virtual void OnBlockExecution();
/// Called when a new Workflow program is about to run.
virtual void OnStartExecution();
/// Called when a Workflow program is stopped by any reason.
virtual void OnStopExecution();
InstructionLocation MakeCurrentInstructionLocation();
template
bool HandleBreakPoint(const TKey& key, collections::Dictionary& breakPointMap);
bool SetBreakPoint(const WfBreakPoint& breakPoint, bool available, vint index);
void EnterThreadContext(WfRuntimeThreadContext* context)override;
void LeaveThreadContext(WfRuntimeThreadContext* context)override;
bool BreakIns(WfAssembly* assembly, vint instruction)override;
bool BreakRead(WfAssembly* assembly, vint variable)override;
bool BreakWrite(WfAssembly* assembly, vint variable)override;
bool BreakGet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)override;
bool BreakSet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)override;
bool BreakAttach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)override;
bool BreakDetach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)override;
bool BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)override;
bool BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo)override;
bool BreakCreate(reflection::description::ITypeDescriptor* typeDescriptor)override;
bool BreakException(Ptr info)override;
bool WaitForContinue()override;
public:
/// Create a debugger.
WfDebugger();
~WfDebugger();
/// Add a new break point.
/// Returns the index of this break point. Returns -1 if failed.
/// The break point.
vint AddBreakPoint(const WfBreakPoint& breakPoint);
/// Add a new source code break point.
/// Returns the index of this break point. Returns -1 if failed.
/// The assembly.
/// The code index of a module.
/// The row number, starts from 0.
/// Set to true to apply source code information to original source code.
vint AddCodeLineBreakPoint(WfAssembly* assembly, vint codeIndex, vint row, bool beforeCodegen = true);
/// Get the number of all break points.
/// The number of all break points.
vint GetBreakPointCount();
/// Test if an index is an available break point.
/// Returns true if an index is an available break point. This function returns true for all disabled break points.
/// The index of the break point.
bool IsBreakPointAvailable(vint index);
/// Get a specified break point. For unavailable break points, is false.
/// The break point.
/// The index of the break point.
const WfBreakPoint& GetBreakPoint(vint index);
/// Delete a specified break point.
/// Returns true if this operation is succeeded.
/// The index of the break point.
/// After removing a break point, the break point becomes unavailable. The index will be reused later when a new break point is added to the debugger.
bool RemoveBreakPoint(vint index);
/// Enable or disable a specified break point.
/// Returns true if this operation is succeeded.
/// The index of the break point.
/// Set to true to enable a break point.
bool EnableBreakPoint(vint index, bool enabled);
/// Test if the exception break point is enabled or not.
/// Returns true if the exception break point is enabled.
bool GetBreakException();
/// Enable or disable the exception break point.
/// Set to true to enable the exception break point.
void SetBreakException(bool value);
/// Continue to run the Workflow program.
/// Returns true if this operation is succeeded.
bool Run();
/// Pause the Workflow program.
/// Returns true if this operation is succeeded.
bool Pause();
/// Stop the Workflow program.
/// Returns true if this operation is succeeded.
bool Stop();
/// Run until reached the next row in the same function or outside of this function.
/// Returns true if this operation is succeeded.
/// Set to true to apply the source code information to original source code.
bool StepOver(bool beforeCodegen = true);
/// Run until reached the next row.
/// Returns true if this operation is succeeded.
/// Set to true to apply the source code information to original source code.
bool StepInto(bool beforeCodegen = true);
/// Get the current state of the debugger.
/// The state of the debugger.
State GetState();
/// Get the running type of the debugger.
/// The running type of the debugger.
RunningType GetRunningType();
/// Get the index of the last activated break point.
/// The index of the last activated break point.
vint GetLastActivatedBreakPoint();
const ThreadContextList& GetThreadContexts();
WfRuntimeThreadContext* GetCurrentThreadContext();
/// Get the current position of the executing instruction in the source code.
/// The current position in the source code.
/// Set to true to apply the source code information to original source code.
/// Specify a thread context. Set to null to use the top thread context.
/// Specify a call stack index. Set to null to use the top call stack item of the specified thread context.
const glr::ParsingTextRange& GetCurrentPosition(bool beforeCodegen = true, WfRuntimeThreadContext* context = nullptr, vint callStackIndex = -1);
/// Get the variable value by name in the current scope.
/// The value.
/// The name.
/// Specify a thread context. Set to null to use the top thread context.
/// Specify a call stack index. Set to null to use the top call stack item of the specified thread context.
reflection::description::Value GetValueByName(const WString& name, WfRuntimeThreadContext* context = nullptr, vint callStackIndex = -1);
};
extern IWfDebuggerCallback* GetDebuggerCallback();
extern IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger);
/// Get the debugger for the current thread.
/// The debugger.
extern Ptr GetDebuggerForCurrentThread();
/// Set the debugger for the current thread.
/// The debugger.
extern void SetDebuggerForCurrentThread(Ptr debugger);
/// Reset the debugger for the current thread.
extern void ResetDebuggerForCurrentThread();
}
}
}
#endif
#endif
/***********************************************************************
.\WFRUNTIME.H
***********************************************************************/
/***********************************************************************
Vczh Library++ 3.0
Developer: Zihan Chen(vczh)
Workflow::Runtime
Interfaces:
**********************************************************************/
#ifndef VCZH_WORKFLOW_RUNTIME_WFRUNTIME
#define VCZH_WORKFLOW_RUNTIME_WFRUNTIME
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
namespace vl
{
namespace workflow
{
namespace runtime
{
/***********************************************************************
RuntimeEnvironment
***********************************************************************/
/// Variable storage.
class WfRuntimeVariableContext : public Object, public reflection::Description
{
typedef collections::Array VariableArray;
public:
/// Values of variables in runtime.
VariableArray variables;
};
/// Global context for executing a Workflow program. After the context is prepared, use [M:vl.workflow.runtime.LoadFunction`1] to call any functions inside the assembly. Function "<initialize>" should be the first to execute.
class WfRuntimeGlobalContext : public Object, public reflection::Description
{
public:
/// The loaded assembly.
Ptr assembly;
/// Global variable storages.
Ptr globalVariables;
/// Create a global context for executing a Workflow program.
/// The assembly.
WfRuntimeGlobalContext(Ptr _assembly);
~WfRuntimeGlobalContext();
};
struct WfRuntimeStackFrame
{
Ptr capturedVariables;
vint functionIndex = -1;
vint nextInstructionIndex = -1;
vint stackBase = 0;
vint fixedVariableCount = 0;
vint freeStackBase = 0;
};
struct WfRuntimeTrapFrame
{
vint stackFrameIndex = -1;
vint instructionIndex = -1;
vint stackPatternCount = -1;
};
/***********************************************************************
RuntimeException
***********************************************************************/
/// Representing a call stack item.
class WfRuntimeCallStackInfo : public Object, public virtual reflection::description::IValueCallStack
{
using IValueReadonlyDictionary = reflection::description::IValueReadonlyDictionary;
protected:
Ptr cachedLocalVariables;
Ptr cachedLocalArguments;
Ptr cachedCapturedVariables;
Ptr cachedGlobalVariables;
Ptr GetVariables(collections::List& names, Ptr context, Ptr& cache);
public:
WfRuntimeCallStackInfo();
WfRuntimeCallStackInfo(WfRuntimeThreadContext* context, const WfRuntimeStackFrame& stackFrame);
~WfRuntimeCallStackInfo();
/// The executing assembly.
Ptr assembly;
/// Global variable values.
Ptr global;
/// Captured variable values.
Ptr captured;
/// Argument values.
Ptr arguments;
/// Local variable values.
Ptr localVariables;
/// The executing function.
vint functionIndex = -1;
/// The executing instruction.
vint instruction = -1;
Ptr GetLocalVariables()override;
Ptr GetLocalArguments()override;
Ptr GetCapturedVariables()override;
Ptr GetGlobalVariables()override;
/// Get the name of the executing function.
/// The name of the execution function.
WString GetFunctionName()override;
/// Get the source code of the executing module.
/// The source code.
WString GetSourceCodeBeforeCodegen()override;
/// Get the source code of the executing module from generated syntax trees from the final compiling pass.
/// The source code.
WString GetSourceCodeAfterCodegen()override;
/// Get the row number (starts at 0) of the source code of the executing module.
/// The row number.
vint GetRowBeforeCodegen()override;
/// Get the row number (starts at 0) of the source code of the executing module from generated syntax trees from the final compiling pass.
/// The row number.
vint GetRowAfterCodegen()override;
};
/// Representing an raised exception.
class WfRuntimeExceptionInfo : public Object, public virtual reflection::description::IValueException
{
typedef collections::List> CallStackList;
using IValueReadonlyList = reflection::description::IValueReadonlyList;
protected:
Ptr cachedCallStack;
public:
/// Exception message.
WString message;
/// Fatal error flag.
bool fatal = false;
/// All call stack items.
CallStackList callStack;
WfRuntimeExceptionInfo(const WString& _message, bool _fatal);
~WfRuntimeExceptionInfo();
#pragma push_macro("GetMessage")
#if defined GetMessage
#undef GetMessage
#endif
WString GetMessage()override;
#pragma pop_macro("GetMessage")
bool GetFatal()override;
Ptr GetCallStack()override;
};
/// Representing an raised exception object for upper level C++ code.
class WfRuntimeException : public reflection::description::TypeDescriptorException
{
protected:
Ptr info;
bool fatal = false;
public:
WfRuntimeException(Ptr _info)
:reflection::description::TypeDescriptorException(_info->message)
, info(_info)
, fatal(_info->fatal)
{
}
WfRuntimeException(const WString& _message, bool _fatal)
:reflection::description::TypeDescriptorException(_message)
, fatal(_fatal)
{
}
/// Get the detailed information.
/// The detailed information.
Ptr GetInfo()const
{
return info;
}
/// Get the fatal error flag.
/// Returns true if this exception is a fatal error, which normally means state corruption in a Workflow runtime.
bool IsFatal()const
{
return fatal;
}
};
/***********************************************************************
RuntimeThreadContext
***********************************************************************/
enum class WfRuntimeExecutionStatus
{
Ready,
Executing,
RaisedException,
Finished,
FatalError,
};
enum class WfRuntimeExecutionAction
{
ExecuteInstruction,
UnwrapStack,
EnterStackFrame,
ExitStackFrame,
Nop,
};
enum class WfRuntimeThreadContextError
{
Success,
WrongStackItemIndex,
WrongVariableIndex,
WrongFunctionIndex,
WrongArgumentCount,
WrongCapturedVariableCount,
EmptyStackFrame,
EmptyTrapFrame,
EmptyStack,
TrapFrameCorrupted,
StackCorrupted,
};
/// A Workflow script call stack.
///
///
/// This object could be obtained by .
/// A thread could have multiple thread contexts,
/// a full list could be obtained by .
///
///
/// You are not recommended to update the call stack using this object.
///
///
/// In the current version,
/// the debug information doesn't contain enough data,
/// so that it could be difficult to read local variables in high-level function constructions,
/// like lambda expression or coroutines.
///
///
class WfRuntimeThreadContext
{
typedef collections::List VariableList;
typedef collections::List StackFrameList;
typedef collections::List TrapFrameList;
public:
Ptr globalContext;
Ptr exceptionInfo;
VariableList stack;
StackFrameList stackFrames;
TrapFrameList trapFrames;
WfRuntimeExecutionStatus status = WfRuntimeExecutionStatus::Finished;
WfRuntimeThreadContext(Ptr _context);
WfRuntimeThreadContext(Ptr _assembly);
WfRuntimeStackFrame& GetCurrentStackFrame();
WfRuntimeThreadContextError PushStackFrame(vint functionIndex, vint argumentCount, Ptr capturedVariables = 0);
WfRuntimeThreadContextError PopStackFrame();
WfRuntimeTrapFrame& GetCurrentTrapFrame();
WfRuntimeThreadContextError PushTrapFrame(vint instructionIndex);
WfRuntimeThreadContextError PopTrapFrame(vint saveStackPatternCount);
WfRuntimeThreadContextError PushRuntimeValue(const WfRuntimeValue& value);
WfRuntimeThreadContextError PushValue(const reflection::description::Value& value);
WfRuntimeThreadContextError PopValue(reflection::description::Value& value);
WfRuntimeThreadContextError RaiseException(const WString& exception, bool fatalError, bool skipDebugger = false);
WfRuntimeThreadContextError RaiseException(Ptr info, bool skipDebugger = false);
WfRuntimeThreadContextError LoadStackValue(vint stackItemIndex, reflection::description::Value& value);
WfRuntimeThreadContextError LoadGlobalVariable(vint variableIndex, reflection::description::Value& value);
WfRuntimeThreadContextError StoreGlobalVariable(vint variableIndex, const reflection::description::Value& value);
WfRuntimeThreadContextError LoadCapturedVariable(vint variableIndex, reflection::description::Value& value);
WfRuntimeThreadContextError StoreCapturedVariable(vint variableIndex, const reflection::description::Value& value);
WfRuntimeThreadContextError LoadLocalVariable(vint variableIndex, reflection::description::Value& value);
WfRuntimeThreadContextError StoreLocalVariable(vint variableIndex, const reflection::description::Value& value);
WfRuntimeExecutionAction ExecuteInternal(WfInstruction& ins, WfRuntimeStackFrame& stackFrame, IWfDebuggerCallback* callback);
WfRuntimeExecutionAction Execute(IWfDebuggerCallback* callback);
void ExecuteToEnd();
};
/***********************************************************************
Helper Functions
***********************************************************************/
/// Load a function from a global context, raise an exception if multiple functions are found under the same name. Function "<initialize>" should be the first to execute.
/// The loaded function.
/// The context to the evaluation environment.
/// The function name.
/// "<initialize>" must be the first function that is executed after an assembly is loaded. It has no argument or return value.
extern Ptr LoadFunction(Ptr context, const WString& name);
/// Load a C++ friendly function from a global context, raise an exception if multiple functions are found under the same name. Function "<initialize>" should be the first to execute.
/// Type of the function.
/// The loaded C++ friendly function.
/// The context to the evaluation environment.
/// The function name.
/// "<initialize>" must be the first function that is executed after an assembly is loaded. Its type is void().
template
Func LoadFunction(Ptr context, const WString& name)
{
auto proxy = LoadFunction(context, name);
return reflection::description::UnboxParameter>(reflection::description::Value::From(proxy)).Ref();
}
}
}
}
#endif
#endif