mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-05 11:30:07 +08:00
1834 lines
75 KiB
C++
1834 lines
75 KiB
C++
/***********************************************************************
|
|
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 : <Stack-Pattern> -> <Stack-Pattern> in the order of <bottom ---- top>
|
|
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 -> <function> ;
|
|
LoadClosureContext, // : () -> <closure-context> ; 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 -> <array> ; {1 2 3} -> <3 2 1>
|
|
NewList, // count : Value-count, ..., Value-1 -> <array> ; {1 2 3} -> <3 2 1>
|
|
NewObservableList, // count : Value-count, ..., Value-1 -> <observable-list> ; {1 2 3} -> <3 2 1>
|
|
NewDictionary, // count : Value-count*2, ..., Value-1 -> <map> ; {1:2 3:4} -> <3 4 1 2>
|
|
CreateClosureContext, // count : Value-1, ..., Value-count -> <closure-context> ;
|
|
CreateClosure, // : <closure-context>, Value-function-index -> <closure> ;
|
|
CreateInterface, // IMethodInfo*, count : <closure-context>, Value-count, ..., Value-1 -> <map> ; {"Get":a "Set":b} -> new TInterface(InterfaceProxy^)
|
|
CreateRange, // I1248/U1248 : Value-begin, Value-end -> <enumerable> ;
|
|
CreateStruct, // flag, typeDescriptor : () -> Value ;
|
|
DeleteRawPtr, // : Value -> () ;
|
|
ConvertToType, // flag, typeDescriptor : Value -> Value ;
|
|
TryConvertToType, // flag, typeDescriptor : Value -> Value ;
|
|
TestType, // flag, typeDescriptor : Value -> <bool> ;
|
|
GetType, // : Value -> <ITypeDescriptor*> ;
|
|
Jump, // label : () -> () ;
|
|
JumpIf, // label : <bool> -> () ;
|
|
Invoke, // function, count : Value-1, ..., Value-n -> Value ;
|
|
InvokeWithContext, // function, count : Value-1, ..., Value-n -> Value ;
|
|
GetProperty, // IPropertyInfo* : Value-this -> Value ;
|
|
SetProperty, // IPropertyInfo* : Value, Value-this -> () ;
|
|
UpdateProperty, // IPropertyInfo* : Value-this, Value -> Value-this ;
|
|
InvokeProxy, // count : Value-1, ..., Value-n, Value-this -> Value ;
|
|
InvokeMethod, // IMethodInfo*, count : Value-1, ..., Value-n, Value-this -> Value ;
|
|
InvokeEvent, // IEventInfo*, count : Value-1, ..., Value-n, Value-this -> <null> ;
|
|
InvokeBaseCtor, // IMethodInfo*, count : Value-1, ..., Value-n, Value-this -> <null> ;
|
|
AttachEvent, // IEventInfo* : Value-this, <function> -> <Listener> ;
|
|
DetachEvent, // IEventInfo* : Value-this, <Listener> -> bool ;
|
|
InstallTry, // label : () -> () ;
|
|
UninstallTry, // count : () -> () ;
|
|
RaiseException, // : Value -> () ; (trap)
|
|
TestElementInSet, // : Value-element, Value-set -> bool ;
|
|
CompareLiteral, // I48/U48/F48/S : Value, Value -> <int> ;
|
|
CompareReference, // : Value, Value -> <bool> ;
|
|
CompareValue, // : Value, Value -> <bool> ;
|
|
OpNot, // B/I1248/U1248 : Value -> Value ;
|
|
OpPositive, // I1248/U1248 : Value -> Value ;
|
|
OpNegative, // I1248 : Value -> Value ;
|
|
OpConcat, // : <string>, <string> -> <string> ;
|
|
OpExp, // I48/U48/F48 : Value, Value -> Value ;
|
|
OpAdd, // I48/U48/F48 : Value, Value -> Value ;
|
|
OpSub, // I48/U48/F48 : Value, Value -> Value ;
|
|
OpMul, // I48/U48/F48 : Value, Value -> Value ;
|
|
OpDiv, // I48/U48/F48 : Value, Value -> Value ;
|
|
OpMod, // I48/U48 : Value, Value -> Value ;
|
|
OpShl, // I48/U48 : Value, Value -> Value ;
|
|
OpShr, // I48/U48 : Value, Value -> Value ;
|
|
OpXor, // B/I1248/U1248 : <bool>, <bool> -> <bool> ;
|
|
OpAnd, // B/I1248/U1248 : <bool>, <bool> -> <bool> ;
|
|
OpOr, // B/I1248/U1248 : <bool>, <bool> -> <bool> ;
|
|
OpLT, // : <int> -> <bool> ;
|
|
OpGT, // : <int> -> <bool> ;
|
|
OpLE, // : <int> -> <bool> ;
|
|
OpGE, // : <int> -> <bool> ;
|
|
OpEQ, // : <int> -> <bool> ;
|
|
OpNE, // : <int> -> <bool> ;
|
|
};
|
|
|
|
#define INSTRUCTION_CASES(APPLY, APPLY_VALUE, APPLY_FUNCTION, APPLY_FUNCTION_COUNT, APPLY_VARIABLE, APPLY_COUNT, APPLY_FLAG_TYPEDESCRIPTOR, APPLY_PROPERTY, APPLY_METHOD, APPLY_METHOD_COUNT, APPLY_EVENT, APPLY_EVENT_COUNT, APPLY_LABEL, APPLY_TYPE)\
|
|
APPLY(Nop)\
|
|
APPLY_VALUE(LoadValue)\
|
|
APPLY_FUNCTION(LoadFunction)\
|
|
APPLY(LoadException)\
|
|
APPLY_VARIABLE(LoadLocalVar)\
|
|
APPLY_VARIABLE(LoadCapturedVar)\
|
|
APPLY_VARIABLE(LoadGlobalVar)\
|
|
APPLY_METHOD(LoadMethodInfo)\
|
|
APPLY_METHOD(LoadMethodClosure)\
|
|
APPLY(LoadClosureContext)\
|
|
APPLY_VARIABLE(StoreLocalVar)\
|
|
APPLY_VARIABLE(StoreCapturedVar)\
|
|
APPLY_VARIABLE(StoreGlobalVar)\
|
|
APPLY_COUNT(Duplicate)\
|
|
APPLY(Pop)\
|
|
APPLY(Return)\
|
|
APPLY_COUNT(NewArray)\
|
|
APPLY_COUNT(NewList)\
|
|
APPLY_COUNT(NewObservableList)\
|
|
APPLY_COUNT(NewDictionary)\
|
|
APPLY_COUNT(CreateClosureContext)\
|
|
APPLY(CreateClosure)\
|
|
APPLY_METHOD_COUNT(CreateInterface)\
|
|
APPLY_TYPE(CreateRange)\
|
|
APPLY_FLAG_TYPEDESCRIPTOR(CreateStruct)\
|
|
APPLY(DeleteRawPtr)\
|
|
APPLY_FLAG_TYPEDESCRIPTOR(ConvertToType)\
|
|
APPLY_FLAG_TYPEDESCRIPTOR(TryConvertToType)\
|
|
APPLY_FLAG_TYPEDESCRIPTOR(TestType)\
|
|
APPLY(GetType)\
|
|
APPLY_LABEL(Jump)\
|
|
APPLY_LABEL(JumpIf)\
|
|
APPLY_FUNCTION_COUNT(Invoke)\
|
|
APPLY_FUNCTION_COUNT(InvokeWithContext)\
|
|
APPLY_PROPERTY(GetProperty)\
|
|
APPLY_PROPERTY(SetProperty)\
|
|
APPLY_PROPERTY(UpdateProperty)\
|
|
APPLY_COUNT(InvokeProxy)\
|
|
APPLY_METHOD_COUNT(InvokeMethod)\
|
|
APPLY_EVENT_COUNT(InvokeEvent)\
|
|
APPLY_METHOD_COUNT(InvokeBaseCtor)\
|
|
APPLY_EVENT(AttachEvent)\
|
|
APPLY_EVENT(DetachEvent)\
|
|
APPLY_LABEL(InstallTry)\
|
|
APPLY_COUNT(UninstallTry)\
|
|
APPLY(RaiseException)\
|
|
APPLY(TestElementInSet)\
|
|
APPLY_TYPE(CompareLiteral)\
|
|
APPLY(CompareReference)\
|
|
APPLY(CompareValue)\
|
|
APPLY_TYPE(OpNot)\
|
|
APPLY_TYPE(OpPositive)\
|
|
APPLY_TYPE(OpNegative)\
|
|
APPLY(OpConcat)\
|
|
APPLY_TYPE(OpExp)\
|
|
APPLY_TYPE(OpAdd)\
|
|
APPLY_TYPE(OpSub)\
|
|
APPLY_TYPE(OpMul)\
|
|
APPLY_TYPE(OpDiv)\
|
|
APPLY_TYPE(OpMod)\
|
|
APPLY_TYPE(OpShl)\
|
|
APPLY_TYPE(OpShr)\
|
|
APPLY_TYPE(OpXor)\
|
|
APPLY_TYPE(OpAnd)\
|
|
APPLY_TYPE(OpOr)\
|
|
APPLY(OpLT)\
|
|
APPLY(OpGT)\
|
|
APPLY(OpLE)\
|
|
APPLY(OpGE)\
|
|
APPLY(OpEQ)\
|
|
APPLY(OpNE)\
|
|
|
|
enum class WfInsType
|
|
{
|
|
Bool,
|
|
I1,
|
|
I2,
|
|
I4,
|
|
I8,
|
|
U1,
|
|
U2,
|
|
U4,
|
|
U8,
|
|
F4,
|
|
F8,
|
|
String,
|
|
Unknown,
|
|
};
|
|
|
|
struct WfRuntimeValue
|
|
{
|
|
// U8 with ITypeDescriptor* -> enum
|
|
// Unknown with ITypeDescriptor* -> type
|
|
// Unknown -> Null
|
|
WfInsType type = WfInsType::Unknown;
|
|
reflection::description::ITypeDescriptor* typeDescriptor = nullptr;
|
|
WString stringValue;
|
|
union
|
|
{
|
|
bool boolValue;
|
|
vint8_t i1Value;
|
|
vint16_t i2Value;
|
|
vint32_t i4Value;
|
|
vint64_t i8Value;
|
|
vuint8_t u1Value;
|
|
vuint16_t u2Value;
|
|
vuint32_t u4Value;
|
|
vuint64_t u8Value = 0;
|
|
float f4Value;
|
|
double f8Value;
|
|
};
|
|
|
|
WfRuntimeValue() {}
|
|
WfRuntimeValue(bool value) : type(WfInsType::Bool), boolValue(value) {}
|
|
WfRuntimeValue(vint8_t value) : type(WfInsType::I1), i1Value(value) {}
|
|
WfRuntimeValue(vint16_t value) : type(WfInsType::I2), i2Value(value) {}
|
|
WfRuntimeValue(vint32_t value) : type(WfInsType::I4), i4Value(value) {}
|
|
WfRuntimeValue(vint64_t value) : type(WfInsType::I8), i8Value(value) {}
|
|
WfRuntimeValue(vuint8_t value) : type(WfInsType::U1), u1Value(value) {}
|
|
WfRuntimeValue(vuint16_t value) : type(WfInsType::U2), u2Value(value) {}
|
|
WfRuntimeValue(vuint32_t value) : type(WfInsType::U4), u4Value(value) {}
|
|
WfRuntimeValue(vuint64_t value) : type(WfInsType::U8), u8Value(value) {}
|
|
WfRuntimeValue(float value) : type(WfInsType::F4), f4Value(value) {}
|
|
WfRuntimeValue(double value) : type(WfInsType::F8), f8Value(value) {}
|
|
WfRuntimeValue(WString value) : type(WfInsType::String), stringValue(value) {}
|
|
WfRuntimeValue(vuint64_t value, reflection::description::ITypeDescriptor* enumType)
|
|
: type(WfInsType::U8), typeDescriptor(enumType), u8Value(value) {}
|
|
WfRuntimeValue(reflection::description::ITypeDescriptor* td)
|
|
: type(WfInsType::Unknown), typeDescriptor(td) {}
|
|
};
|
|
|
|
struct WfInstruction
|
|
{
|
|
WfInsCode code = WfInsCode::Nop;
|
|
WfRuntimeValue valueParameter;
|
|
vint countParameter = 0;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
reflection::description::Value::ValueType flagParameter;
|
|
reflection::description::ITypeDescriptor* typeDescriptorParameter;
|
|
};
|
|
WfInsType typeParameter;
|
|
vint indexParameter;
|
|
reflection::description::IPropertyInfo* propertyParameter;
|
|
reflection::description::IMethodInfo* methodParameter;
|
|
reflection::description::IEventInfo* eventParameter;
|
|
};
|
|
|
|
WfInstruction();
|
|
|
|
#define CTOR(NAME) static WfInstruction NAME();
|
|
#define CTOR_VALUE(NAME) static WfInstruction NAME(const WfRuntimeValue& value);
|
|
#define CTOR_FUNCTION(NAME) static WfInstruction NAME(vint function);
|
|
#define CTOR_FUNCTION_COUNT(NAME) static WfInstruction NAME(vint function, vint count);
|
|
#define CTOR_VARIABLE(NAME) static WfInstruction NAME(vint variable);
|
|
#define CTOR_COUNT(NAME) static WfInstruction NAME(vint count);
|
|
#define CTOR_FLAG_TYPEDESCRIPTOR(NAME) static WfInstruction NAME(reflection::description::Value::ValueType flag, reflection::description::ITypeDescriptor* typeDescriptor);
|
|
#define CTOR_PROPERTY(NAME) static WfInstruction NAME(reflection::description::IPropertyInfo* propertyInfo);
|
|
#define CTOR_METHOD(NAME) static WfInstruction NAME(reflection::description::IMethodInfo* methodInfo);
|
|
#define CTOR_METHOD_COUNT(NAME) static WfInstruction NAME(reflection::description::IMethodInfo* methodInfo, vint count);
|
|
#define CTOR_EVENT(NAME) static WfInstruction NAME(reflection::description::IEventInfo* eventInfo);
|
|
#define CTOR_EVENT_COUNT(NAME) static WfInstruction NAME(reflection::description::IEventInfo* eventInfo, vint count);
|
|
#define CTOR_LABEL(NAME) static WfInstruction NAME(vint label);
|
|
#define CTOR_TYPE(NAME) static WfInstruction NAME(WfInsType type);
|
|
|
|
INSTRUCTION_CASES(
|
|
CTOR,
|
|
CTOR_VALUE,
|
|
CTOR_FUNCTION,
|
|
CTOR_FUNCTION_COUNT,
|
|
CTOR_VARIABLE,
|
|
CTOR_COUNT,
|
|
CTOR_FLAG_TYPEDESCRIPTOR,
|
|
CTOR_PROPERTY,
|
|
CTOR_METHOD,
|
|
CTOR_METHOD_COUNT,
|
|
CTOR_EVENT,
|
|
CTOR_EVENT_COUNT,
|
|
CTOR_LABEL,
|
|
CTOR_TYPE)
|
|
|
|
#undef CTOR
|
|
#undef CTOR_VALUE
|
|
#undef CTOR_FUNCTION
|
|
#undef CTOR_FUNCTION_COUNT
|
|
#undef CTOR_VARIABLE
|
|
#undef CTOR_COUNT
|
|
#undef CTOR_FLAG_TYPEDESCRIPTOR
|
|
#undef CTOR_PROPERTY
|
|
#undef CTOR_METHOD
|
|
#undef CTOR_METHOD_COUNT
|
|
#undef CTOR_EVENT
|
|
#undef CTOR_EVENT_COUNT
|
|
#undef CTOR_LABEL
|
|
#undef CTOR_TYPE
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\WFRUNTIMETYPEDESCRIPTOR.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Workflow::Runtime
|
|
|
|
Interfaces:
|
|
**********************************************************************/
|
|
|
|
#ifndef VCZH_WORKFLOW_RUNTIME_WFRUNTIMETYPEDESCRIPTOR
|
|
#define VCZH_WORKFLOW_RUNTIME_WFRUNTIMETYPEDESCRIPTOR
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace workflow
|
|
{
|
|
namespace typeimpl
|
|
{
|
|
class WfClassInstance;
|
|
class WfInterfaceInstance;
|
|
}
|
|
}
|
|
|
|
namespace reflection
|
|
{
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
#define DEFINE_DESCRIPTION(TYPE)\
|
|
template<>\
|
|
class Description<workflow::typeimpl::TYPE> : public virtual DescriptableObject\
|
|
{\
|
|
private:\
|
|
description::ITypeDescriptor* associatedTypeDescriptor;\
|
|
public:\
|
|
Description(description::ITypeDescriptor* _associatedTypeDescriptor)\
|
|
:associatedTypeDescriptor(_associatedTypeDescriptor)\
|
|
{\
|
|
typeDescriptor = &associatedTypeDescriptor;\
|
|
}\
|
|
};\
|
|
|
|
DEFINE_DESCRIPTION(WfClassInstance)
|
|
DEFINE_DESCRIPTION(WfInterfaceInstance)
|
|
|
|
#undef DEFINE_DESCRIPTION
|
|
#endif
|
|
}
|
|
|
|
namespace workflow
|
|
{
|
|
namespace runtime
|
|
{
|
|
class WfRuntimeGlobalContext;
|
|
}
|
|
|
|
namespace typeimpl
|
|
{
|
|
class WfCustomType;
|
|
class WfTypeImpl;
|
|
|
|
/***********************************************************************
|
|
Method
|
|
***********************************************************************/
|
|
|
|
class WfMethodProxy : public Object, public virtual reflection::description::IValueFunctionProxy
|
|
{
|
|
typedef reflection::description::IMethodInfo IMethodInfo;
|
|
typedef reflection::description::IValueReadonlyList IValueReadonlyList;
|
|
typedef reflection::description::Value Value;
|
|
protected:
|
|
Value thisObject;
|
|
IMethodInfo* methodInfo;
|
|
|
|
public:
|
|
WfMethodProxy(const Value& _thisObject, IMethodInfo* _methodInfo);
|
|
~WfMethodProxy();
|
|
|
|
Value Invoke(Ptr<IValueReadonlyList> arguments)override;
|
|
};
|
|
|
|
class WfMethodBase : public reflection::description::MethodInfoImpl
|
|
{
|
|
friend class WfCustomType;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
protected:
|
|
typedef reflection::description::Value Value;
|
|
runtime::WfRuntimeGlobalContext* globalContext = nullptr;
|
|
|
|
Value CreateFunctionProxyInternal(const Value& thisObject)override;
|
|
void SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext);
|
|
public:
|
|
WfMethodBase(bool isStatic);
|
|
~WfMethodBase();
|
|
|
|
ICpp* GetCpp()override;
|
|
runtime::WfRuntimeGlobalContext* GetGlobalContext();
|
|
void SetReturn(Ptr<ITypeInfo> type);
|
|
};
|
|
|
|
class WfStaticMethod : public WfMethodBase
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
protected:
|
|
|
|
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override;
|
|
public:
|
|
vint functionIndex = -1;
|
|
|
|
WfStaticMethod();
|
|
};
|
|
|
|
/***********************************************************************
|
|
Class Method
|
|
***********************************************************************/
|
|
|
|
class WfClassConstructor : public WfMethodBase
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
protected:
|
|
|
|
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override;
|
|
public:
|
|
vint functionIndex = -1;
|
|
|
|
WfClassConstructor(Ptr<ITypeInfo> type);
|
|
|
|
void InvokeBaseCtor(const Value& thisObject, collections::Array<Value>& arguments);
|
|
};
|
|
|
|
class WfClassMethod : public WfMethodBase
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
protected:
|
|
|
|
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override;
|
|
public:
|
|
vint functionIndex = -1;
|
|
|
|
WfClassMethod();
|
|
};
|
|
|
|
/***********************************************************************
|
|
Interface Method
|
|
***********************************************************************/
|
|
|
|
class WfInterfaceConstructor : public WfMethodBase
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
protected:
|
|
|
|
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override;
|
|
public:
|
|
WfInterfaceConstructor(Ptr<ITypeInfo> type);
|
|
};
|
|
|
|
class WfInterfaceMethod : public WfMethodBase
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
protected:
|
|
|
|
Value InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)override;
|
|
public:
|
|
WfInterfaceMethod();
|
|
};
|
|
|
|
/***********************************************************************
|
|
Event
|
|
***********************************************************************/
|
|
|
|
class WfEvent : public reflection::description::EventInfoImpl
|
|
{
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
typedef reflection::description::IEventHandler IEventHandler;
|
|
typedef reflection::description::IValueFunctionProxy IValueFunctionProxy;
|
|
typedef reflection::description::IValueReadonlyList IValueReadonlyList;
|
|
typedef reflection::description::Value Value;
|
|
|
|
class EventHandlerImpl : public Object, public IEventHandler
|
|
{
|
|
public:
|
|
bool isAttached = true;
|
|
Ptr<IValueFunctionProxy> proxy;
|
|
|
|
EventHandlerImpl(Ptr<IValueFunctionProxy> _proxy)
|
|
:proxy(_proxy)
|
|
{
|
|
}
|
|
|
|
bool IsAttached()override
|
|
{
|
|
return isAttached;
|
|
}
|
|
};
|
|
|
|
typedef collections::Group<WfEvent*, Ptr<EventHandlerImpl>> EventHandlerGroup;
|
|
class EventRecord : public Object
|
|
{
|
|
public:
|
|
EventHandlerGroup handlers;
|
|
};
|
|
|
|
static const wchar_t* EventRecordInternalPropertyName;
|
|
protected:
|
|
|
|
Ptr<EventRecord> GetEventRecord(DescriptableObject* thisObject, bool createIfNotExist);
|
|
Ptr<IEventHandler> AttachInternal(DescriptableObject* thisObject, Ptr<IValueFunctionProxy> handler)override;
|
|
bool DetachInternal(DescriptableObject* thisObject, Ptr<IEventHandler> handler)override;
|
|
void InvokeInternal(DescriptableObject* thisObject, Ptr<IValueReadonlyList> arguments)override;
|
|
Ptr<ITypeInfo> GetHandlerTypeInternal()override;
|
|
public:
|
|
WfEvent(ITypeDescriptor* ownerTypeDescriptor, const WString& name);
|
|
~WfEvent();
|
|
|
|
ICpp* GetCpp()override;
|
|
void SetHandlerType(Ptr<ITypeInfo> typeInfo);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Field
|
|
***********************************************************************/
|
|
|
|
class WfField : public reflection::description::FieldInfoImpl
|
|
{
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
typedef reflection::description::Value Value;
|
|
typedef collections::Dictionary<WfField*, Value> FieldValueMap;
|
|
|
|
class FieldRecord : public Object
|
|
{
|
|
public:
|
|
FieldValueMap values;
|
|
};
|
|
|
|
static const wchar_t* FieldRecordInternalPropertyName;
|
|
protected:
|
|
|
|
Ptr<FieldRecord> GetFieldRecord(DescriptableObject* thisObject, bool createIfNotExist);
|
|
Value GetValueInternal(const Value& thisObject)override;
|
|
void SetValueInternal(Value& thisObject, const Value& newValue)override;
|
|
public:
|
|
WfField(ITypeDescriptor* ownerTypeDescriptor, const WString& name);
|
|
~WfField();
|
|
|
|
ICpp* GetCpp()override;
|
|
void SetReturn(Ptr<ITypeInfo> typeInfo);
|
|
};
|
|
|
|
class WfStructField : public reflection::description::FieldInfoImpl
|
|
{
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
typedef reflection::description::Value Value;
|
|
protected:
|
|
|
|
Value GetValueInternal(const Value& thisObject)override;
|
|
void SetValueInternal(Value& thisObject, const Value& newValue)override;
|
|
public:
|
|
WfStructField(ITypeDescriptor* ownerTypeDescriptor, const WString& name);
|
|
~WfStructField();
|
|
|
|
ICpp* GetCpp()override;
|
|
void SetReturn(Ptr<ITypeInfo> typeInfo);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Property
|
|
***********************************************************************/
|
|
|
|
class WfProperty : public reflection::description::PropertyInfoImpl
|
|
{
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::MethodInfoImpl MethodInfoImpl;
|
|
typedef reflection::description::EventInfoImpl EventInfoImpl;
|
|
public:
|
|
WfProperty(ITypeDescriptor* ownerTypeDescriptor, const WString& name);
|
|
~WfProperty();
|
|
|
|
void SetGetter(MethodInfoImpl* value);
|
|
void SetSetter(MethodInfoImpl* value);
|
|
void SetValueChangedEvent(EventInfoImpl* value);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Custom Type
|
|
***********************************************************************/
|
|
|
|
struct WfTypeInfoContent : reflection::description::TypeInfoContent
|
|
{
|
|
WString workflowTypeName;
|
|
|
|
WfTypeInfoContent(const WString& _workflowTypeName);
|
|
};
|
|
|
|
template<typename TBase>
|
|
class WfCustomTypeBase : private WfTypeInfoContent, public TBase
|
|
{
|
|
public:
|
|
WfCustomTypeBase(reflection::description::TypeDescriptorFlags typeDescriptorFlags, const WString& typeName)
|
|
:WfTypeInfoContent(typeName)
|
|
, TBase(typeDescriptorFlags, this)
|
|
{
|
|
}
|
|
|
|
const WString& GetTypeName() override
|
|
{
|
|
// TypeDescriptorImplBase::GetTypeName returns WString(this->typeName, false)
|
|
// which is this->workflowTypeName.Obj()
|
|
// will become a dangling pointer after this type is unloaded
|
|
return workflowTypeName;
|
|
}
|
|
};
|
|
|
|
class WfCustomType : public WfCustomTypeBase<reflection::description::TypeDescriptorImpl>
|
|
{
|
|
protected:
|
|
typedef reflection::description::TypeDescriptorFlags TypeDescriptorFlags;
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::ITypeInfo ITypeInfo;
|
|
typedef reflection::description::IMethodGroupInfo IMethodGroupInfo;
|
|
typedef collections::List<ITypeDescriptor*> TypeDescriptorList;
|
|
|
|
protected:
|
|
runtime::WfRuntimeGlobalContext* globalContext = nullptr;
|
|
bool baseTypeExpanded = false;
|
|
TypeDescriptorList expandedBaseTypes;
|
|
|
|
void SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext, IMethodGroupInfo* group);
|
|
void SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext);
|
|
void LoadInternal()override;
|
|
public:
|
|
WfCustomType(TypeDescriptorFlags typeDescriptorFlags, const WString& typeName);
|
|
~WfCustomType();
|
|
|
|
runtime::WfRuntimeGlobalContext* GetGlobalContext();
|
|
const TypeDescriptorList& GetExpandedBaseTypes();
|
|
|
|
void AddBaseType(ITypeDescriptor* type);
|
|
void AddMember(const WString& name, Ptr<WfMethodBase> value);
|
|
void AddMember(Ptr<WfClassConstructor> value);
|
|
void AddMember(Ptr<WfInterfaceConstructor> value);
|
|
void AddMember(Ptr<WfField> value);
|
|
void AddMember(Ptr<WfProperty> value);
|
|
void AddMember(Ptr<WfEvent> value);
|
|
};
|
|
|
|
class WfClass : public WfCustomType
|
|
{
|
|
friend class WfTypeImpl;
|
|
public:
|
|
vint destructorFunctionIndex = -1;
|
|
|
|
WfClass(const WString& typeName);
|
|
~WfClass();
|
|
};
|
|
|
|
class WfInterface : public WfCustomType
|
|
{
|
|
friend class WfTypeImpl;
|
|
public:
|
|
WfInterface(const WString& typeName);
|
|
~WfInterface();
|
|
};
|
|
|
|
class WfStruct : public WfCustomTypeBase<reflection::description::ValueTypeDescriptorBase>
|
|
{
|
|
using FieldMap = collections::Dictionary<WString, Ptr<WfStructField>>;
|
|
using IPropertyInfo = reflection::description::IPropertyInfo;
|
|
using IValueType = reflection::description::IValueType;
|
|
using IBoxedValue = reflection::description::IBoxedValue;
|
|
|
|
protected:
|
|
class WfValueType : public Object, public virtual IValueType
|
|
{
|
|
using Value = reflection::description::Value;
|
|
|
|
protected:
|
|
WfStruct* owner;
|
|
|
|
public:
|
|
WfValueType(WfStruct* _owner);
|
|
|
|
Value CreateDefault()override;
|
|
};
|
|
|
|
protected:
|
|
FieldMap fields;
|
|
|
|
public:
|
|
WfStruct(const WString& typeName);
|
|
~WfStruct();
|
|
|
|
vint GetPropertyCount()override;
|
|
IPropertyInfo* GetProperty(vint index)override;
|
|
bool IsPropertyExists(const WString& name, bool inheritable)override;
|
|
IPropertyInfo* GetPropertyByName(const WString& name, bool inheritable)override;
|
|
|
|
void AddMember(Ptr<WfStructField> value);
|
|
};
|
|
|
|
class WfEnum : public WfCustomTypeBase<reflection::description::ValueTypeDescriptorBase>
|
|
{
|
|
using EnumItemMap = collections::Dictionary<WString, vuint64_t>;
|
|
using IValueType = reflection::description::IValueType;
|
|
using IBoxedValue = reflection::description::IBoxedValue;
|
|
using IEnumType = reflection::description::IEnumType;
|
|
using Value = reflection::description::Value;
|
|
|
|
protected:
|
|
class WfValueType : public Object, public virtual IValueType
|
|
{
|
|
protected:
|
|
WfEnum* owner;
|
|
|
|
public:
|
|
WfValueType(WfEnum* _owner);
|
|
|
|
Value CreateDefault()override;
|
|
};
|
|
|
|
class WfEnumType : public Object, public virtual IEnumType
|
|
{
|
|
protected:
|
|
WfEnum* owner;
|
|
|
|
public:
|
|
WfEnumType(WfEnum* _owner);
|
|
|
|
bool IsFlagEnum()override;
|
|
vint GetItemCount()override;
|
|
WString GetItemName(vint index)override;
|
|
vuint64_t GetItemValue(vint index)override;
|
|
vint IndexOfItem(WString name)override;
|
|
Value ToEnum(vuint64_t value)override;
|
|
vuint64_t FromEnum(const Value& value)override;
|
|
};
|
|
|
|
protected:
|
|
EnumItemMap enumItems;
|
|
|
|
public:
|
|
WfEnum(bool isFlags, const WString& typeName);
|
|
~WfEnum();
|
|
|
|
void AddEnumItem(const WString& name, vuint64_t value);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Instance
|
|
***********************************************************************/
|
|
|
|
class WfClassInstance : public Object, public reflection::Description<WfClassInstance>
|
|
{
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::Value Value;
|
|
protected:
|
|
WfClass* classType = nullptr;
|
|
|
|
public:
|
|
WfClassInstance(ITypeDescriptor* _typeDescriptor);
|
|
~WfClassInstance();
|
|
|
|
void InstallBaseObject(ITypeDescriptor* td, Value& value);
|
|
};
|
|
|
|
class WfInterfaceInstance : public Object, public reflection::IDescriptable, public reflection::Description<WfInterfaceInstance>
|
|
{
|
|
typedef reflection::description::ITypeDescriptor ITypeDescriptor;
|
|
typedef reflection::description::IMethodInfo IMethodInfo;
|
|
typedef reflection::description::IValueInterfaceProxy IValueInterfaceProxy;
|
|
protected:
|
|
Ptr<IValueInterfaceProxy> proxy;
|
|
|
|
public:
|
|
WfInterfaceInstance(ITypeDescriptor* _typeDescriptor, Ptr<IValueInterfaceProxy> _proxy, collections::List<IMethodInfo*>& baseCtors);
|
|
~WfInterfaceInstance();
|
|
|
|
Ptr<IValueInterfaceProxy> GetProxy();
|
|
};
|
|
|
|
class WfStructInstance : public Object, public reflection::description::IBoxedValue
|
|
{
|
|
using FieldValueMap = collections::Dictionary<WfStructField*, reflection::description::Value>;
|
|
|
|
public:
|
|
reflection::description::ITypeDescriptor* typeDescriptor = nullptr;
|
|
FieldValueMap fieldValues;
|
|
|
|
WfStructInstance(reflection::description::ITypeDescriptor* _typeDescriptor);
|
|
|
|
reflection::description::PredefinedBoxableType GetBoxableType() override;
|
|
Ptr<IBoxedValue> Copy() override;
|
|
CompareResult ComparePrimitive(Ptr<IBoxedValue> boxedValue) override;
|
|
};
|
|
|
|
class WfEnumInstance : public Object, public reflection::description::IBoxedValue
|
|
{
|
|
public:
|
|
reflection::description::ITypeDescriptor* typeDescriptor = nullptr;
|
|
vuint64_t value = 0;
|
|
|
|
WfEnumInstance(reflection::description::ITypeDescriptor* _typeDescriptor);
|
|
|
|
reflection::description::PredefinedBoxableType GetBoxableType() override;
|
|
Ptr<IBoxedValue> Copy() override;
|
|
CompareResult ComparePrimitive(Ptr<IBoxedValue> boxedValue) override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Plugin
|
|
***********************************************************************/
|
|
|
|
class WfTypeImpl : public Object, public reflection::description::ITypeLoader, public reflection::Description<WfTypeImpl>
|
|
{
|
|
protected:
|
|
runtime::WfRuntimeGlobalContext* globalContext = nullptr;
|
|
|
|
public:
|
|
collections::List<Ptr<WfClass>> classes;
|
|
collections::List<Ptr<WfInterface>> interfaces;
|
|
collections::List<Ptr<WfStruct>> structs;
|
|
collections::List<Ptr<WfEnum>> enums;
|
|
|
|
runtime::WfRuntimeGlobalContext* GetGlobalContext();
|
|
void SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext);
|
|
void Load(reflection::description::ITypeManager* manager)override;
|
|
void Unload(reflection::description::ITypeManager* manager)override;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\WFRUNTIMEASSEMBLY.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Workflow::Runtime
|
|
|
|
Interfaces:
|
|
**********************************************************************/
|
|
|
|
#ifndef VCZH_WORKFLOW_RUNTIME_WFRUNTIMEASSEMBLY
|
|
#define VCZH_WORKFLOW_RUNTIME_WFRUNTIMEASSEMBLY
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace workflow
|
|
{
|
|
namespace runtime
|
|
{
|
|
|
|
/***********************************************************************
|
|
Assembly
|
|
***********************************************************************/
|
|
|
|
/// <summary>Representing a compiled function.</summary>
|
|
class WfAssemblyFunction : public Object
|
|
{
|
|
public:
|
|
/// <summary>Name of the function.</summary>
|
|
WString name;
|
|
/// <summary>Argument names of the function. This index is for accessing [F:vl.workflow.runtime.WfRuntimeVariableContext.variables] in [F:vl.workflow.runtime.WfRuntimeCallStackInfo.arguments] when debugging.</summary>
|
|
collections::List<WString> argumentNames;
|
|
/// <summary>Captured variable names of the function. This index is for accessing [F:vl.workflow.runtime.WfRuntimeVariableContext.variables] in [F:vl.workflow.runtime.WfRuntimeCallStackInfo.captured] when debugging.</summary>
|
|
collections::List<WString> capturedVariableNames;
|
|
/// <summary>Local variable names of the function. This index is for accessing [F:vl.workflow.runtime.WfRuntimeVariableContext.variables] in [F:vl.workflow.runtime.WfRuntimeCallStackInfo.localVariables] when debugging.</summary>
|
|
collections::List<WString> localVariableNames;
|
|
/// <summary>First instruction index of the function. This index is for accessing [F:vl.workflow.runtime.WfAssembly.instructions].</summary>
|
|
vint firstInstruction = -1;
|
|
/// <summary>Last instruction index of the function. This index is for accessing [F:vl.workflow.runtime.WfAssembly.instructions].</summary>
|
|
vint lastInstruction = -1;
|
|
};
|
|
|
|
/// <summary>Representing debug informations.</summary>
|
|
class WfInstructionDebugInfo : public Object
|
|
{
|
|
public:
|
|
|
|
/// <summary>Module codes.</summary>
|
|
collections::List<WString> moduleCodes; // codeIndex -> code
|
|
/// <summary>Mapping information from every instruction to code. Use[F:vl.parsing.ParsingTextRange.codeIndex] for accessing <see cref="moduleCodes"/>.</summary>
|
|
collections::List<glr::ParsingTextRange> instructionCodeMapping; // instruction -> range
|
|
/// <summary>Mapping information from every row in codes to instructions. Value of the key is (codeIndex, row).</summary>
|
|
collections::Group<Tuple<vint, vint>, vint> codeInstructionMapping; // (codeIndex, row) -> instruction [generated]
|
|
|
|
void Initialize();
|
|
};
|
|
|
|
/// <summary>Representing metadata errors during loading an assembly.</summary>
|
|
class WfAssemblyLoadErrors
|
|
{
|
|
public:
|
|
/// <summary>All unresolvable types.</summary>
|
|
collections::List<WString> unresolvedTypes;
|
|
|
|
/// <summary>All duplicated types. Types are shared in the process, there is no isolation between assemblies.</summary>
|
|
collections::List<WString> duplicatedTypes;
|
|
|
|
/// <summary>All unresolvable members in resolved types.</summary>
|
|
collections::List<WString> unresolvedMembers;
|
|
};
|
|
|
|
/// <summary>Representing a Workflow assembly.</summary>
|
|
class WfAssembly : public Object, public reflection::Description<WfAssembly>
|
|
{
|
|
public:
|
|
/// <summary>Debug informations using the module code.</summary>
|
|
Ptr<WfInstructionDebugInfo> insBeforeCodegen;
|
|
/// <summary>Debug informations using the module code from generated syntax trees from the final compiling pass.</summary>
|
|
Ptr<WfInstructionDebugInfo> insAfterCodegen;
|
|
/// <summary>Global variable names. This index is for accessing [F:vl.workflow.runtime.WfRuntimeVariableContext.variables] in [F:vl.workflow.runtime.WfRuntimeCallStackInfo.global] when debugging.</summary>
|
|
collections::List<WString> variableNames;
|
|
/// <summary>Mapping from function names to function indexes for accessing <see cref="functions"/>.</summary>
|
|
collections::Group<WString, vint> functionByName;
|
|
/// <summary>Functions.</summary>
|
|
collections::List<Ptr<WfAssemblyFunction>> functions;
|
|
/// <summary>Instructions.</summary>
|
|
collections::List<WfInstruction> instructions;
|
|
/// <summary>Custom types.</summary>
|
|
Ptr<typeimpl::WfTypeImpl> typeImpl;
|
|
|
|
/// <summary>Create an empty assembly.</summary>
|
|
WfAssembly();
|
|
|
|
void Initialize();
|
|
|
|
/// <summary>Deserialize an assembly.</summary>
|
|
/// <returns>The deserialized assembly. Returns null if there are errors.</returns>
|
|
/// <param name="input">Serialized binary data.</param>
|
|
/// <param name="errors">Errors during loading an assembly.</param>
|
|
static Ptr<WfAssembly> Deserialize(stream::IStream& input, WfAssemblyLoadErrors& errors);
|
|
|
|
/// <summary>Serialize an assembly.</summary>
|
|
/// <param name="output">Serialized binary data.</param>
|
|
void Serialize(stream::IStream& output);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\WFRUNTIMECONSTRUCTIONS.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Workflow::Runtime
|
|
|
|
Interfaces:
|
|
**********************************************************************/
|
|
|
|
#ifndef VCZH_WORKFLOW_RUNTIME_WFRUNTIMECONSTRUCTIONS
|
|
#define VCZH_WORKFLOW_RUNTIME_WFRUNTIMECONSTRUCTIONS
|
|
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
namespace vl
|
|
{
|
|
namespace workflow
|
|
{
|
|
namespace runtime
|
|
{
|
|
class WfRuntimeGlobalContext;
|
|
class WfRuntimeVariableContext;
|
|
|
|
/***********************************************************************
|
|
Range
|
|
***********************************************************************/
|
|
|
|
template<typename T>
|
|
class WfRuntimeRange : public Object, public reflection::description::IValueEnumerable
|
|
{
|
|
protected:
|
|
T begin;
|
|
T end;
|
|
|
|
class Enumerator : public Object, public reflection::description::IValueEnumerator
|
|
{
|
|
protected:
|
|
T begin;
|
|
T end;
|
|
T current;
|
|
public:
|
|
Enumerator(T _begin, T _end)
|
|
:begin(_begin), end(_end), current(_begin - 1)
|
|
{
|
|
}
|
|
|
|
reflection::description::Value GetCurrent()
|
|
{
|
|
return reflection::description::BoxValue<T>(current);
|
|
}
|
|
|
|
vint GetIndex()
|
|
{
|
|
return (vint)(current - begin);
|
|
}
|
|
|
|
bool Next()
|
|
{
|
|
if (current >= end) return false;
|
|
current++;
|
|
return true;
|
|
}
|
|
};
|
|
public:
|
|
WfRuntimeRange(T _begin, T _end)
|
|
:begin(_begin), end(_end)
|
|
{
|
|
}
|
|
|
|
Ptr<reflection::description::IValueEnumerator> CreateEnumerator()override
|
|
{
|
|
return Ptr(new Enumerator(begin, end));
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Lambda
|
|
***********************************************************************/
|
|
|
|
class WfRuntimeLambda : public Object, public reflection::description::IValueFunctionProxy
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
public:
|
|
// use raw pointer because
|
|
// if a lambda is stored in a global variable
|
|
// it is stored in globalContext->globalVariables->variables[i]
|
|
// so that globalContext has a cyclic reference to itself
|
|
WfRuntimeGlobalContext* globalContext = nullptr;
|
|
Ptr<WfRuntimeVariableContext> capturedVariables;
|
|
vint functionIndex;
|
|
|
|
WfRuntimeLambda(Ptr<WfRuntimeGlobalContext> _globalContext, Ptr<WfRuntimeVariableContext> _capturedVariables, vint _functionIndex);
|
|
|
|
Value Invoke(Ptr<reflection::description::IValueReadonlyList> arguments)override;
|
|
static Value Invoke(Ptr<WfRuntimeGlobalContext> globalContext, Ptr<WfRuntimeVariableContext> capturedVariables, vint functionIndex, Ptr<reflection::description::IValueReadonlyList> arguments);
|
|
};
|
|
|
|
/***********************************************************************
|
|
InterfaceInstance
|
|
***********************************************************************/
|
|
|
|
class WfRuntimeInterfaceInstance : public Object, public reflection::description::IValueInterfaceProxy
|
|
{
|
|
typedef reflection::description::Value Value;
|
|
typedef reflection::description::IMethodInfo IMethodInfo;
|
|
typedef reflection::description::IValueFunctionProxy IValueFunctionProxy;
|
|
typedef reflection::description::IValueReadonlyList IValueReadonlyList;
|
|
typedef collections::Dictionary<IMethodInfo*, vint> FunctionMap;
|
|
public:
|
|
// use raw pointer because
|
|
// if a lambda is stored in a global variable
|
|
// it is stored in globalContext->globalVariables->variables[i]
|
|
// so that globalContext has a cyclic reference to itself
|
|
WfRuntimeGlobalContext* globalContext = nullptr;
|
|
Ptr<WfRuntimeVariableContext> capturedVariables;
|
|
FunctionMap functions;
|
|
|
|
Value Invoke(IMethodInfo* methodInfo, Ptr<IValueReadonlyList> arguments)override;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\WFRUNTIMEDEBUGGER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Workflow::Runtime
|
|
|
|
Interfaces:
|
|
**********************************************************************/
|
|
|
|
#ifndef VCZH_WORKFLOW_RUNTIME_WFRUNTIMEDEBUGGER
|
|
#define VCZH_WORKFLOW_RUNTIME_WFRUNTIMEDEBUGGER
|
|
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
namespace vl
|
|
{
|
|
namespace workflow
|
|
{
|
|
namespace runtime
|
|
{
|
|
class WfRuntimeThreadContext;
|
|
class WfRuntimeExceptionInfo;
|
|
class IWfDebuggerCallback;
|
|
class WfDebugger;
|
|
|
|
/***********************************************************************
|
|
Debugger
|
|
***********************************************************************/
|
|
|
|
/// <summary>Break point action. It will </summary>
|
|
class IWfBreakPointAction : public virtual Interface
|
|
{
|
|
public:
|
|
/// <summary>Called a break point is about to activate.</summary>
|
|
/// <returns>Returns false to skip this break point.</returns>
|
|
/// <param name="debugger">The current attached debugger.</param>
|
|
virtual bool EvaluateCondition(WfDebugger* debugger) = 0;
|
|
/// <summary>Called when a break point is about to activate, even <see cref="EvaluateCondition"/> returns false.</summary>
|
|
/// <param name="debugger">The current attached debugger.</param>
|
|
/// <param name="activated">The return value from <see cref="EvaluateCondition"/>.</param>
|
|
virtual void PostAction(WfDebugger* debugger, bool activated) = 0;
|
|
};
|
|
|
|
/// <summary>Break point.</summary>
|
|
struct WfBreakPoint
|
|
{
|
|
enum Type
|
|
{
|
|
Instruction, // assembly, instruction
|
|
ReadGlobalVar, // assembly, variable
|
|
WriteGlobalVar, // assembly, variable
|
|
GetProperty, // [thisObject], propertyInfo
|
|
SetProperty, // [thisObject], propertyInfo
|
|
AttachEvent, // [thisObject], eventInfo
|
|
DetachEvent, // [thisObject], eventInfo
|
|
InvokeEvent, // [thisObject], eventInfo
|
|
InvokeMethod, // [thisObject], methodInfo
|
|
CreateObject, // typeDescriptor
|
|
};
|
|
|
|
vint id = -1;
|
|
bool available = false;
|
|
bool enabled = false;
|
|
Ptr<IWfBreakPointAction> action;
|
|
|
|
Type type;
|
|
WfAssembly* assembly = nullptr;
|
|
union
|
|
{
|
|
vint instruction = -1;
|
|
vint variable;
|
|
};
|
|
|
|
reflection::DescriptableObject* thisObject = nullptr;
|
|
union
|
|
{
|
|
reflection::description::IPropertyInfo* propertyInfo = nullptr;
|
|
reflection::description::IEventInfo* eventInfo;
|
|
reflection::description::IMethodInfo* methodInfo;
|
|
reflection::description::ITypeDescriptor* typeDescriptor;
|
|
};
|
|
|
|
/// <summary>Create an instruction break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="assembly">The assembly that contains the instruction.</param>
|
|
/// <param name="instruction">The index of the instruction.</param>
|
|
static WfBreakPoint Ins(WfAssembly* assembly, vint instruction);
|
|
|
|
/// <summary>Create an global variable reading break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="assembly">The assembly that contains the instruction.</param>
|
|
/// <param name="variable">The index of the global variable.</param>
|
|
static WfBreakPoint Read(WfAssembly* assembly, vint variable);
|
|
|
|
/// <summary>Create an global variable writing break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="assembly">The assembly that contains the instruction.</param>
|
|
/// <param name="variable">The index of the global variable.</param>
|
|
static WfBreakPoint Write(WfAssembly* assembly, vint variable);
|
|
|
|
/// <summary>Create an property reading break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="thisObject">The target object. Set to null to apply to every object.</param>
|
|
/// <param name="propertyInfo">The property.</param>
|
|
static WfBreakPoint Get(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo);
|
|
|
|
/// <summary>Create an property writing break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="thisObject">The target object. Set to null to apply to every object.</param>
|
|
/// <param name="propertyInfo">The property.</param>
|
|
static WfBreakPoint Set(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo);
|
|
|
|
/// <summary>Create an event attaching break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="thisObject">The target object. Set to null to apply to every object.</param>
|
|
/// <param name="eventInfo">The event.</param>
|
|
static WfBreakPoint Attach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo);
|
|
|
|
/// <summary>Create an event detaching break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="thisObject">The target object. Set to null to apply to every object.</param>
|
|
/// <param name="eventInfo">The event.</param>
|
|
static WfBreakPoint Detach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo);
|
|
|
|
/// <summary>Create an event invoking break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="thisObject">The target object. Set to null to apply to every object.</param>
|
|
/// <param name="eventInfo">The event.</param>
|
|
static WfBreakPoint Invoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo);
|
|
|
|
/// <summary>Create an function invoking break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="thisObject">The target object. Set to null to apply to every object.</param>
|
|
/// <param name="methodInfo">The function.</param>
|
|
static WfBreakPoint Invoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo);
|
|
|
|
/// <summary>Create an object creating break point.</summary>
|
|
/// <returns>The created break point.</returns>
|
|
/// <param name="typeDescriptor">The target object type.</param>
|
|
static WfBreakPoint Create(reflection::description::ITypeDescriptor* typeDescriptor);
|
|
};
|
|
|
|
class IWfDebuggerCallback : public virtual Interface
|
|
{
|
|
public:
|
|
virtual void EnterThreadContext(WfRuntimeThreadContext* context) = 0;
|
|
virtual void LeaveThreadContext(WfRuntimeThreadContext* context) = 0;
|
|
virtual bool BreakIns(WfAssembly* assembly, vint instruction) = 0;
|
|
virtual bool BreakRead(WfAssembly* assembly, vint variable) = 0;
|
|
virtual bool BreakWrite(WfAssembly* assembly, vint variable) = 0;
|
|
virtual bool BreakGet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo) = 0;
|
|
virtual bool BreakSet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo) = 0;
|
|
virtual bool BreakAttach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo) = 0;
|
|
virtual bool BreakDetach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo) = 0;
|
|
virtual bool BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo) = 0;
|
|
virtual bool BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo) = 0;
|
|
virtual bool BreakCreate(reflection::description::ITypeDescriptor* typeDescriptor) = 0;
|
|
virtual bool BreakException(Ptr<WfRuntimeExceptionInfo> info) = 0;
|
|
virtual bool WaitForContinue() = 0;
|
|
};
|
|
|
|
/// <summary>Workflow debugger.</summary>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// <see cref="SetDebuggerForCurrentThread"/> needs to be called to make a debugger works for any Workflow script that is running in the current thread.
|
|
/// </p>
|
|
/// <p>
|
|
/// <see cref="OnBlockExecution"/> needs to be overrided to make a debugger work properly.
|
|
/// When the target Workflow script stops,
|
|
/// this function will be called.
|
|
/// In this function,
|
|
/// one of <see cref="Run"/>, <see cref="Pause"/>, <see cref="Stop"/>, <see cref="StepOver"/> and <see cref="StepInto"/>
|
|
/// must be called to make the target Workflow script continues.
|
|
/// </p>
|
|
/// <p>
|
|
/// You are allowed to run the debugger logic in another thread,
|
|
/// for example,
|
|
/// an GUI application is debugging a Workflow script which is running in another thread.
|
|
/// In this case, <see cref="OnBlockExecution"/> needs to be blocked until it is ready to continue.
|
|
/// </p>
|
|
/// <p>
|
|
/// Locks are a good choice for this.
|
|
/// </p>
|
|
/// </remarks>
|
|
class WfDebugger : public Object, protected virtual IWfDebuggerCallback
|
|
{
|
|
friend IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger);
|
|
|
|
typedef collections::List<WfBreakPoint> BreakPointList;
|
|
typedef collections::List<WfRuntimeThreadContext*> ThreadContextList;
|
|
|
|
typedef Tuple<WfAssembly*, vint> AssemblyKey;
|
|
typedef Tuple<reflection::DescriptableObject*, reflection::description::IPropertyInfo*> PropertyKey;
|
|
typedef Tuple<reflection::DescriptableObject*, reflection::description::IEventInfo*> EventKey;
|
|
typedef Tuple<reflection::DescriptableObject*, reflection::description::IMethodInfo*> MethodKey;
|
|
typedef reflection::description::ITypeDescriptor* TypeKey;
|
|
|
|
typedef collections::Dictionary<AssemblyKey, vint> AssemblyBreakPointMap;
|
|
typedef collections::Dictionary<PropertyKey, vint> PropertyBreakPointMap;
|
|
typedef collections::Dictionary<EventKey, vint> EventBreakPointMap;
|
|
typedef collections::Dictionary<MethodKey, vint> MethodBreakPointMap;
|
|
typedef collections::Dictionary<TypeKey, vint> TypeBreakPointMap;
|
|
public:
|
|
/// <summary>The state of the debugger.</summary>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// The state is affected by break points and the following operations:
|
|
/// <ul>
|
|
/// <li><b><see cref="Run"/></b>: If the Workflow script is paused, it continues the script.</li>
|
|
/// <li><b><see cref="Pause"/></b>: If the Workflow script is running, it pauses the script, following by a call to <see cref="OnBlockExecution"/>.</li>
|
|
/// <li><b><see cref="Stop"/></b>: If the Workflow script is not stopped, it stops the script by throwing in exception in the script.</li>
|
|
/// <li><b><see cref="StepOver"/></b>: Stop over to the next code line and pause. It doesn't jump into the function to be called.</li>
|
|
/// <li><b><see cref="StepInto"/></b>: Stop into the new code line and pause.</li>
|
|
/// </ul>
|
|
/// Operations are expected to be called in <see cref="OnBlockExecution"/>.
|
|
/// </p>
|
|
/// </remarks>
|
|
enum State
|
|
{ // Run Pause Stop StepOver StepInto
|
|
/// <summary>The associated thread is running Workflow script.</summary>
|
|
Running, // R *RTP *RTS
|
|
/// <summary>The target Workflow script is paused by operations other than break points.</summary>
|
|
PauseByOperation, // PBO *C *RTS *C *C
|
|
/// <summary>The target Workflow script is paused by break points.</summary>
|
|
PauseByBreakPoint, // PBB *C *RTS *C *C
|
|
/// <summary>The associated thread has stopped running Workflow script.</summary>
|
|
Stopped, // S *RTP * *
|
|
/// <summary>The debugger allows the target Workflow script to continue.</summary>
|
|
Continue, // C soon becomes Running
|
|
/// <summary>The target Workflow script is required to pause. This value can be observed in <see cref="OnBlockExecution"/>. Operations to continue executing the Workflow script await to be called.</summary>
|
|
RequiredToPause, // RTP soon becomes PauseByOperation (should be triggered in OnBlockExecution)
|
|
/// <summary>The target Workflow script is required to stop. It caused to Workflow script to stop by throwing an exception saying this.</summary>
|
|
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<vint> 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;
|
|
|
|
/// <summary>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.</summary>
|
|
/// <remarks>This function must be overrided, or the Workflow script will hang when it is paused by any reason.</remarks>
|
|
virtual void OnBlockExecution();
|
|
/// <summary>Called when a new Workflow program is about to run.</summary>
|
|
virtual void OnStartExecution();
|
|
/// <summary>Called when a Workflow program is stopped by any reason.</summary>
|
|
virtual void OnStopExecution();
|
|
|
|
InstructionLocation MakeCurrentInstructionLocation();
|
|
template<typename TKey>
|
|
bool HandleBreakPoint(const TKey& key, collections::Dictionary<TKey, vint>& 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<WfRuntimeExceptionInfo> info)override;
|
|
bool WaitForContinue()override;
|
|
public:
|
|
/// <summary>Create a debugger.</summary>
|
|
WfDebugger();
|
|
~WfDebugger();
|
|
|
|
/// <summary>Add a new break point.</summary>
|
|
/// <returns>Returns the index of this break point. Returns -1 if failed.</returns>
|
|
/// <param name="breakPoint">The break point.</param>
|
|
vint AddBreakPoint(const WfBreakPoint& breakPoint);
|
|
/// <summary>Add a new source code break point.</summary>
|
|
/// <returns>Returns the index of this break point. Returns -1 if failed.</returns>
|
|
/// <param name="assembly">The assembly.</param>
|
|
/// <param name="codeIndex">The code index of a module.</param>
|
|
/// <param name="row">The row number, starts from 0.</param>
|
|
/// <param name="beforeCodegen">Set to true to apply source code information to original source code.</param>
|
|
vint AddCodeLineBreakPoint(WfAssembly* assembly, vint codeIndex, vint row, bool beforeCodegen = true);
|
|
/// <summary>Get the number of all break points.</summary>
|
|
/// <returns>The number of all break points.</returns>
|
|
vint GetBreakPointCount();
|
|
/// <summary>Test if an index is an available break point.</summary>
|
|
/// <returns>Returns true if an index is an available break point. This function returns true for all disabled break points.</returns>
|
|
/// <param name="index">The index of the break point.</param>
|
|
bool IsBreakPointAvailable(vint index);
|
|
/// <summary>Get a specified break point. For unavailable break points, <see cref="WfBreakPoint::available"/> is false.</summary>
|
|
/// <returns>The break point.</returns>
|
|
/// <param name="index">The index of the break point.</param>
|
|
const WfBreakPoint& GetBreakPoint(vint index);
|
|
/// <summary>Delete a specified break point.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
/// <param name="index">The index of the break point.</param>
|
|
/// <remarks>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.</remarks>
|
|
bool RemoveBreakPoint(vint index);
|
|
/// <summary>Enable or disable a specified break point.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
/// <param name="index">The index of the break point.</param>
|
|
/// <param name="enabled">Set to true to enable a break point.</param>
|
|
bool EnableBreakPoint(vint index, bool enabled);
|
|
/// <summary>Test if the exception break point is enabled or not.</summary>
|
|
/// <returns>Returns true if the exception break point is enabled.</returns>
|
|
bool GetBreakException();
|
|
/// <summary>Enable or disable the exception break point.</summary>
|
|
/// <param name="value">Set to true to enable the exception break point.</param>
|
|
void SetBreakException(bool value);
|
|
|
|
/// <summary>Continue to run the Workflow program.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
bool Run();
|
|
/// <summary>Pause the Workflow program.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
bool Pause();
|
|
/// <summary>Stop the Workflow program.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
bool Stop();
|
|
/// <summary>Run until reached the next row in the same function or outside of this function.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
/// <param name="beforeCodegen">Set to true to apply the source code information to original source code.</param>
|
|
bool StepOver(bool beforeCodegen = true);
|
|
/// <summary>Run until reached the next row.</summary>
|
|
/// <returns>Returns true if this operation is succeeded.</returns>
|
|
/// <param name="beforeCodegen">Set to true to apply the source code information to original source code.</param>
|
|
bool StepInto(bool beforeCodegen = true);
|
|
/// <summary>Get the current state of the debugger.</summary>
|
|
/// <returns>The state of the debugger.</returns>
|
|
State GetState();
|
|
/// <summary>Get the running type of the debugger.</summary>
|
|
/// <returns>The running type of the debugger.</returns>
|
|
RunningType GetRunningType();
|
|
/// <summary>Get the index of the last activated break point.</summary>
|
|
/// <returns>The index of the last activated break point.</returns>
|
|
vint GetLastActivatedBreakPoint();
|
|
|
|
const ThreadContextList& GetThreadContexts();
|
|
WfRuntimeThreadContext* GetCurrentThreadContext();
|
|
/// <summary>Get the current position of the executing instruction in the source code.</summary>
|
|
/// <returns>The current position in the source code.</returns>
|
|
/// <param name="beforeCodegen">Set to true to apply the source code information to original source code.</param>
|
|
/// <param name="context">Specify a thread context. Set to null to use the top thread context.</param>
|
|
/// <param name="callStackIndex">Specify a call stack index. Set to null to use the top call stack item of the specified thread context.</param>
|
|
const glr::ParsingTextRange& GetCurrentPosition(bool beforeCodegen = true, WfRuntimeThreadContext* context = nullptr, vint callStackIndex = -1);
|
|
/// <summary>Get the variable value by name in the current scope.</summary>
|
|
/// <returns>The value.</returns>
|
|
/// <param name="name">The name.</param>
|
|
/// <param name="context">Specify a thread context. Set to null to use the top thread context.</param>
|
|
/// <param name="callStackIndex">Specify a call stack index. Set to null to use the top call stack item of the specified thread context.</param>
|
|
reflection::description::Value GetValueByName(const WString& name, WfRuntimeThreadContext* context = nullptr, vint callStackIndex = -1);
|
|
};
|
|
|
|
extern IWfDebuggerCallback* GetDebuggerCallback();
|
|
extern IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger);
|
|
|
|
/// <summary>Get the debugger for the current thread.</summary>
|
|
/// <returns>The debugger.</returns>
|
|
extern Ptr<WfDebugger> GetDebuggerForCurrentThread();
|
|
/// <summary>Set the debugger for the current thread.</summary>
|
|
/// <param name="debugger">The debugger.</param>
|
|
extern void SetDebuggerForCurrentThread(Ptr<WfDebugger> debugger);
|
|
/// <summary>Reset the debugger for the current thread.</summary>
|
|
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
|
|
***********************************************************************/
|
|
|
|
/// <summary>Variable storage.</summary>
|
|
class WfRuntimeVariableContext : public Object, public reflection::Description<WfRuntimeVariableContext>
|
|
{
|
|
typedef collections::Array<reflection::description::Value> VariableArray;
|
|
|
|
public:
|
|
/// <summary>Values of variables in runtime.</summary>
|
|
VariableArray variables;
|
|
};
|
|
|
|
/// <summary>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 "<b><initialize></b>" should be the first to execute.</summary>
|
|
class WfRuntimeGlobalContext : public Object, public reflection::Description<WfRuntimeGlobalContext>
|
|
{
|
|
public:
|
|
/// <summary>The loaded assembly.</summary>
|
|
Ptr<WfAssembly> assembly;
|
|
/// <summary>Global variable storages.</summary>
|
|
Ptr<WfRuntimeVariableContext> globalVariables;
|
|
|
|
/// <summary>Create a global context for executing a Workflow program.</summary>
|
|
/// <param name="_assembly">The assembly.</param>
|
|
WfRuntimeGlobalContext(Ptr<WfAssembly> _assembly);
|
|
~WfRuntimeGlobalContext();
|
|
};
|
|
|
|
struct WfRuntimeStackFrame
|
|
{
|
|
Ptr<WfRuntimeVariableContext> 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
|
|
***********************************************************************/
|
|
|
|
/// <summary>Representing a call stack item.</summary>
|
|
class WfRuntimeCallStackInfo : public Object, public virtual reflection::description::IValueCallStack
|
|
{
|
|
using IValueReadonlyDictionary = reflection::description::IValueReadonlyDictionary;
|
|
protected:
|
|
Ptr<IValueReadonlyDictionary> cachedLocalVariables;
|
|
Ptr<IValueReadonlyDictionary> cachedLocalArguments;
|
|
Ptr<IValueReadonlyDictionary> cachedCapturedVariables;
|
|
Ptr<IValueReadonlyDictionary> cachedGlobalVariables;
|
|
|
|
Ptr<IValueReadonlyDictionary> GetVariables(collections::List<WString>& names, Ptr<WfRuntimeVariableContext> context, Ptr<IValueReadonlyDictionary>& cache);
|
|
public:
|
|
WfRuntimeCallStackInfo();
|
|
WfRuntimeCallStackInfo(WfRuntimeThreadContext* context, const WfRuntimeStackFrame& stackFrame);
|
|
~WfRuntimeCallStackInfo();
|
|
|
|
/// <summary>The executing assembly.</summary>
|
|
Ptr<WfAssembly> assembly;
|
|
/// <summary>Global variable values.</summary>
|
|
Ptr<WfRuntimeVariableContext> global;
|
|
/// <summary>Captured variable values.</summary>
|
|
Ptr<WfRuntimeVariableContext> captured;
|
|
/// <summary>Argument values.</summary>
|
|
Ptr<WfRuntimeVariableContext> arguments;
|
|
/// <summary>Local variable values.</summary>
|
|
Ptr<WfRuntimeVariableContext> localVariables;
|
|
/// <summary>The executing function.</summary>
|
|
vint functionIndex = -1;
|
|
/// <summary>The executing instruction.</summary>
|
|
vint instruction = -1;
|
|
|
|
Ptr<IValueReadonlyDictionary> GetLocalVariables()override;
|
|
Ptr<IValueReadonlyDictionary> GetLocalArguments()override;
|
|
Ptr<IValueReadonlyDictionary> GetCapturedVariables()override;
|
|
Ptr<IValueReadonlyDictionary> GetGlobalVariables()override;
|
|
|
|
/// <summary>Get the name of the executing function.</summary>
|
|
/// <returns>The name of the execution function.</returns>
|
|
WString GetFunctionName()override;
|
|
/// <summary>Get the source code of the executing module.</summary>
|
|
/// <returns>The source code.</returns>
|
|
WString GetSourceCodeBeforeCodegen()override;
|
|
/// <summary>Get the source code of the executing module from generated syntax trees from the final compiling pass.</summary>
|
|
/// <returns>The source code.</returns>
|
|
WString GetSourceCodeAfterCodegen()override;
|
|
/// <summary>Get the row number (starts at 0) of the source code of the executing module.</summary>
|
|
/// <returns>The row number.</returns>
|
|
vint GetRowBeforeCodegen()override;
|
|
/// <summary>Get the row number (starts at 0) of the source code of the executing module from generated syntax trees from the final compiling pass.</summary>
|
|
/// <returns>The row number.</returns>
|
|
vint GetRowAfterCodegen()override;
|
|
};
|
|
|
|
/// <summary>Representing an raised exception.</summary>
|
|
class WfRuntimeExceptionInfo : public Object, public virtual reflection::description::IValueException
|
|
{
|
|
typedef collections::List<Ptr<WfRuntimeCallStackInfo>> CallStackList;
|
|
using IValueReadonlyList = reflection::description::IValueReadonlyList;
|
|
protected:
|
|
Ptr<IValueReadonlyList> cachedCallStack;
|
|
|
|
public:
|
|
/// <summary>Exception message.</summary>
|
|
WString message;
|
|
/// <summary>Fatal error flag.</summary>
|
|
bool fatal = false;
|
|
/// <summary>All call stack items.</summary>
|
|
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<IValueReadonlyList> GetCallStack()override;
|
|
};
|
|
|
|
/// <summary>Representing an raised exception object for upper level C++ code.</summary>
|
|
class WfRuntimeException : public reflection::description::TypeDescriptorException
|
|
{
|
|
protected:
|
|
Ptr<WfRuntimeExceptionInfo> info;
|
|
bool fatal = false;
|
|
public:
|
|
WfRuntimeException(Ptr<WfRuntimeExceptionInfo> _info)
|
|
:reflection::description::TypeDescriptorException(_info->message)
|
|
, info(_info)
|
|
, fatal(_info->fatal)
|
|
{
|
|
}
|
|
|
|
WfRuntimeException(const WString& _message, bool _fatal)
|
|
:reflection::description::TypeDescriptorException(_message)
|
|
, fatal(_fatal)
|
|
{
|
|
}
|
|
|
|
/// <summary>Get the detailed information.</summary>
|
|
/// <returns>The detailed information.</returns>
|
|
Ptr<WfRuntimeExceptionInfo> GetInfo()const
|
|
{
|
|
return info;
|
|
}
|
|
|
|
/// <summary>Get the fatal error flag.</summary>
|
|
/// <returns>Returns true if this exception is a fatal error, which normally means state corruption in a Workflow runtime.</returns>
|
|
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,
|
|
};
|
|
|
|
/// <summary>A Workflow script call stack.</summary>
|
|
/// <remarks>
|
|
/// <p>
|
|
/// This object could be obtained by <see cref="WfDebugger::GetCurrentThreadContext"/>.
|
|
/// A thread could have multiple thread contexts,
|
|
/// a full list could be obtained by <see cref="WfDebugger::GetThreadContexts"/>.
|
|
/// </p>
|
|
/// <p>
|
|
/// You are not recommended to update the call stack using this object.
|
|
/// </p>
|
|
/// <p>
|
|
/// 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.
|
|
/// </p>
|
|
/// </remakrs>
|
|
class WfRuntimeThreadContext
|
|
{
|
|
typedef collections::List<reflection::description::Value> VariableList;
|
|
typedef collections::List<WfRuntimeStackFrame> StackFrameList;
|
|
typedef collections::List<WfRuntimeTrapFrame> TrapFrameList;
|
|
public:
|
|
|
|
Ptr<WfRuntimeGlobalContext> globalContext;
|
|
Ptr<WfRuntimeExceptionInfo> exceptionInfo;
|
|
VariableList stack;
|
|
StackFrameList stackFrames;
|
|
TrapFrameList trapFrames;
|
|
WfRuntimeExecutionStatus status = WfRuntimeExecutionStatus::Finished;
|
|
|
|
WfRuntimeThreadContext(Ptr<WfRuntimeGlobalContext> _context);
|
|
WfRuntimeThreadContext(Ptr<WfAssembly> _assembly);
|
|
|
|
WfRuntimeStackFrame& GetCurrentStackFrame();
|
|
WfRuntimeThreadContextError PushStackFrame(vint functionIndex, vint argumentCount, Ptr<WfRuntimeVariableContext> 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<WfRuntimeExceptionInfo> 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
|
|
***********************************************************************/
|
|
|
|
/// <summary>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.</summary>
|
|
/// <returns>The loaded function.</returns>
|
|
/// <param name="context">The context to the evaluation environment.</param>
|
|
/// <param name="name">The function name.</param>
|
|
/// <remarks>"<b><initialize></b>" must be the first function that is executed after an assembly is loaded. It has no argument or return value.</remarks>
|
|
extern Ptr<reflection::description::IValueFunctionProxy> LoadFunction(Ptr<WfRuntimeGlobalContext> context, const WString& name);
|
|
|
|
/// <summary>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.</summary>
|
|
/// <typeparam name="TFunction">Type of the function.</typeparam>
|
|
/// <returns>The loaded C++ friendly function.</returns>
|
|
/// <param name="context">The context to the evaluation environment.</param>
|
|
/// <param name="name">The function name.</param>
|
|
/// <remarks>"<b><initialize></b>" must be the first function that is executed after an assembly is loaded. Its type is <b>void()</b>.</remarks>
|
|
template<typename TFunction>
|
|
Func<TFunction> LoadFunction(Ptr<WfRuntimeGlobalContext> context, const WString& name)
|
|
{
|
|
auto proxy = LoadFunction(context, name);
|
|
return reflection::description::UnboxParameter<Func<TFunction>>(reflection::description::Value::From(proxy)).Ref();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|