Files
GacUI/Import/VlppWorkflowRuntime.h
2023-04-23 00:30:01 -07:00

1832 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);
}
}
}
#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>&lt;initialize&gt;</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 "&lt;initialize&gt;" 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>&lt;initialize&gt;</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 "&lt;initialize&gt;" 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>&lt;initialize&gt;</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