Files
GacUI/Import/VlppWorkflowRuntime.cpp
2023-04-09 03:49:54 -07:00

5711 lines
170 KiB
C++

/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppWorkflowRuntime.h"
/***********************************************************************
.\WFRUNTIME.CPP
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
namespace vl
{
using namespace reflection;
using namespace reflection::description;
using namespace workflow::runtime;
using namespace collections;
namespace workflow
{
namespace runtime
{
/***********************************************************************
WfRuntimeGlobalContext
***********************************************************************/
WfRuntimeGlobalContext::WfRuntimeGlobalContext(Ptr<WfAssembly> _assembly)
:assembly(_assembly)
{
globalVariables = Ptr(new WfRuntimeVariableContext);
globalVariables->variables.Resize(assembly->variableNames.Count());
if (assembly->typeImpl)
{
assembly->typeImpl->SetGlobalContext(this);
}
}
WfRuntimeGlobalContext::~WfRuntimeGlobalContext()
{
if (assembly->typeImpl)
{
assembly->typeImpl->SetGlobalContext(nullptr);
}
}
/***********************************************************************
WfRuntimeCallStackInfo
***********************************************************************/
Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetVariables(collections::List<WString>& names, Ptr<WfRuntimeVariableContext> context, Ptr<IValueReadonlyDictionary>& cache)
{
if (!cache)
{
if (!context)
{
Dictionary<WString, Value> map;
for (auto [name, index] : indexed(names))
{
map.Add(name, context->variables[index]);
}
cache = IValueDictionary::Create(
From(map)
.Select([](Pair<WString, Value> pair)
{
return Pair<Value, Value>(BoxValue(pair.key), pair.value);
})
);
}
else
{
cache = IValueDictionary::Create();
}
}
return cache;
}
WfRuntimeCallStackInfo::WfRuntimeCallStackInfo()
{
}
WfRuntimeCallStackInfo::WfRuntimeCallStackInfo(WfRuntimeThreadContext* context, const WfRuntimeStackFrame& stackFrame)
{
assembly = context->globalContext->assembly;
functionIndex = stackFrame.functionIndex;
instruction = stackFrame.nextInstructionIndex - 1;
auto function = assembly->functions[functionIndex];
if (context->globalContext->globalVariables->variables.Count() > 0)
{
global = context->globalContext->globalVariables;
}
captured = stackFrame.capturedVariables;
if (function->argumentNames.Count() > 0)
{
arguments = Ptr(new WfRuntimeVariableContext);
arguments->variables.Resize(function->argumentNames.Count());
for (vint i = 0; i < arguments->variables.Count(); i++)
{
arguments->variables[i] = context->stack[stackFrame.stackBase + i];
}
}
if (function->localVariableNames.Count()>0)
{
localVariables = Ptr(new WfRuntimeVariableContext);
localVariables->variables.Resize(function->localVariableNames.Count());
for (vint i = 0; i < localVariables->variables.Count(); i++)
{
localVariables->variables[i] = context->stack[stackFrame.stackBase + function->argumentNames.Count() + i];
}
}
}
WfRuntimeCallStackInfo::~WfRuntimeCallStackInfo()
{
}
Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetLocalVariables()
{
return GetVariables(assembly->functions[functionIndex]->localVariableNames, localVariables, cachedLocalVariables);
}
Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetLocalArguments()
{
return GetVariables(assembly->functions[functionIndex]->argumentNames, arguments, cachedLocalArguments);
}
Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetCapturedVariables()
{
return GetVariables(assembly->functions[functionIndex]->capturedVariableNames, captured, cachedCapturedVariables);
}
Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetGlobalVariables()
{
return GetVariables(assembly->variableNames, global, cachedGlobalVariables);
}
WString WfRuntimeCallStackInfo::GetFunctionName()
{
if (!assembly)
{
return L"<EXTERNAL CODE>";
}
return assembly->functions[functionIndex]->name;
}
WString WfRuntimeCallStackInfo::GetSourceCodeBeforeCodegen()
{
if (!assembly)
{
return L"";
}
const auto& range = assembly->insBeforeCodegen->instructionCodeMapping[instruction];
if (range.codeIndex == -1)
{
return L"";
}
return assembly->insBeforeCodegen->moduleCodes[range.codeIndex];
}
WString WfRuntimeCallStackInfo::GetSourceCodeAfterCodegen()
{
if (!assembly)
{
return L"";
}
const auto& range = assembly->insAfterCodegen->instructionCodeMapping[instruction];
if (range.codeIndex == -1)
{
return L"";
}
return assembly->insAfterCodegen->moduleCodes[range.codeIndex];
}
vint WfRuntimeCallStackInfo::GetRowBeforeCodegen()
{
if (!assembly)
{
return -1;
}
const auto& range = assembly->insBeforeCodegen->instructionCodeMapping[instruction];
return range.start.row;
}
vint WfRuntimeCallStackInfo::GetRowAfterCodegen()
{
if (!assembly)
{
return -1;
}
const auto& range = assembly->insAfterCodegen->instructionCodeMapping[instruction];
return range.start.row;
}
/***********************************************************************
WfRuntimeExceptionInfo
***********************************************************************/
WfRuntimeExceptionInfo::WfRuntimeExceptionInfo(const WString& _message, bool _fatal)
:message(_message)
, fatal(_fatal)
{
}
WfRuntimeExceptionInfo::~WfRuntimeExceptionInfo()
{
}
#pragma push_macro("GetMessage")
#if defined GetMessage
#undef GetMessage
#endif
WString WfRuntimeExceptionInfo::GetMessage()
{
return message;
}
#pragma pop_macro("GetMessage")
bool WfRuntimeExceptionInfo::GetFatal()
{
return fatal;
}
Ptr<IValueReadonlyList> WfRuntimeExceptionInfo::GetCallStack()
{
if (!cachedCallStack)
{
cachedCallStack = IValueList::Create(
From(callStack)
.Cast<IValueCallStack>()
.Select([](Ptr<IValueCallStack> callStack)
{
return BoxValue(callStack);
})
);
}
return cachedCallStack;
}
/***********************************************************************
WfRuntimeThreadContext
***********************************************************************/
WfRuntimeThreadContext::WfRuntimeThreadContext(Ptr<WfRuntimeGlobalContext> _context)
:globalContext(_context)
{
}
WfRuntimeThreadContext::WfRuntimeThreadContext(Ptr<WfAssembly> _assembly)
:globalContext(new WfRuntimeGlobalContext(_assembly))
{
}
WfRuntimeStackFrame& WfRuntimeThreadContext::GetCurrentStackFrame()
{
return stackFrames[stackFrames.Count() - 1];
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PushStackFrame(vint functionIndex, vint argumentCount, Ptr<WfRuntimeVariableContext> capturedVariables)
{
if (stackFrames.Count() == 0)
{
if (stack.Count() < argumentCount)
{
return WfRuntimeThreadContextError::StackCorrupted;
}
}
else
{
auto& frame = GetCurrentStackFrame();
if (stack.Count() - frame.freeStackBase < argumentCount)
{
return WfRuntimeThreadContextError::StackCorrupted;
}
}
if (functionIndex < 0 || functionIndex >= globalContext->assembly->functions.Count())
{
return WfRuntimeThreadContextError::WrongFunctionIndex;
}
auto meta = globalContext->assembly->functions[functionIndex];
if (meta->argumentNames.Count() != argumentCount)
{
return WfRuntimeThreadContextError::WrongArgumentCount;
}
if (meta->capturedVariableNames.Count() == 0)
{
if (capturedVariables)
{
return WfRuntimeThreadContextError::WrongCapturedVariableCount;
}
}
else
{
if (!capturedVariables || capturedVariables->variables.Count() != meta->capturedVariableNames.Count())
{
return WfRuntimeThreadContextError::WrongCapturedVariableCount;
}
}
WfRuntimeStackFrame frame;
frame.capturedVariables = capturedVariables;
frame.functionIndex = functionIndex;
frame.nextInstructionIndex = globalContext->assembly->functions[functionIndex]->firstInstruction;
frame.stackBase = stack.Count() - argumentCount;
frame.fixedVariableCount = meta->argumentNames.Count() + meta->localVariableNames.Count();
frame.freeStackBase = frame.stackBase + frame.fixedVariableCount;
stackFrames.Add(frame);
for (vint i = 0; i < meta->localVariableNames.Count(); i++)
{
stack.Add(Value());
}
if (status == WfRuntimeExecutionStatus::Finished || status == WfRuntimeExecutionStatus::FatalError)
{
status = WfRuntimeExecutionStatus::Ready;
}
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PopStackFrame()
{
if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
WfRuntimeStackFrame frame = GetCurrentStackFrame();
if (trapFrames.Count() > 0)
{
WfRuntimeTrapFrame& trapFrame = GetCurrentTrapFrame();
if (trapFrame.stackFrameIndex == stackFrames.Count() - 1)
{
return WfRuntimeThreadContextError::TrapFrameCorrupted;
}
}
stackFrames.RemoveAt(stackFrames.Count() - 1);
if (stack.Count() > frame.stackBase)
{
stack.RemoveRange(frame.stackBase, stack.Count() - frame.stackBase);
}
return WfRuntimeThreadContextError::Success;
}
WfRuntimeTrapFrame& WfRuntimeThreadContext::GetCurrentTrapFrame()
{
return trapFrames[trapFrames.Count() - 1];
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PushTrapFrame(vint instructionIndex)
{
WfRuntimeTrapFrame frame;
frame.stackFrameIndex = stackFrames.Count() - 1;
frame.instructionIndex = instructionIndex;
frame.stackPatternCount = stack.Count();
trapFrames.Add(frame);
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PopTrapFrame(vint saveStackPatternCount)
{
if (trapFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyTrapFrame;
WfRuntimeTrapFrame& frame = trapFrames[trapFrames.Count() - 1];
if (frame.stackFrameIndex != stackFrames.Count() - 1) return WfRuntimeThreadContextError::TrapFrameCorrupted;
vint stackPopCount = stack.Count() - frame.stackPatternCount - saveStackPatternCount;
if (stackPopCount < 0)
{
return WfRuntimeThreadContextError::StackCorrupted;
}
else if (stackPopCount>0)
{
stack.RemoveRange(stack.Count() - stackPopCount, stackPopCount);
}
trapFrames.RemoveAt(trapFrames.Count() - 1);
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PushRuntimeValue(const WfRuntimeValue& value)
{
if (value.typeDescriptor)
{
switch (value.type)
{
case WfInsType::Unknown:
return PushValue(BoxValue(value.typeDescriptor));
case WfInsType::U8:
CHECK_ERROR(value.typeDescriptor->GetEnumType(), L"WfRuntimeThreadContext::PushValue(const WfRuntimeValue&)#Missing typeDescriptor in WfRuntimeValue!");
return PushValue(value.typeDescriptor->GetEnumType()->ToEnum(value.u8Value));
default:
CHECK_FAIL(L"WfRuntimeThreadContext::PushValue(const WfRuntimeValue&)#Unexpected type in WfRuntimeValue with typeDescriptor!");
}
}
else
{
switch (value.type)
{
case WfInsType::Bool:
return PushValue(BoxValue(value.boolValue));
case WfInsType::I1:
return PushValue(BoxValue(value.i1Value));
case WfInsType::I2:
return PushValue(BoxValue(value.i2Value));
case WfInsType::I4:
return PushValue(BoxValue(value.i4Value));
case WfInsType::I8:
return PushValue(BoxValue(value.i8Value));
case WfInsType::U1:
return PushValue(BoxValue(value.u1Value));
case WfInsType::U2:
return PushValue(BoxValue(value.u2Value));
case WfInsType::U4:
return PushValue(BoxValue(value.u4Value));
case WfInsType::U8:
return PushValue(BoxValue(value.u8Value));
case WfInsType::F4:
return PushValue(BoxValue(value.f4Value));
case WfInsType::F8:
return PushValue(BoxValue(value.f8Value));
case WfInsType::String:
return PushValue(BoxValue(value.stringValue));
default:
return PushValue(Value());
}
}
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PushValue(const reflection::description::Value& value)
{
stack.Add(value);
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::PopValue(reflection::description::Value& value)
{
if (stackFrames.Count() == 0)
{
if (stack.Count() == 0) return WfRuntimeThreadContextError::EmptyStack;
}
else
{
WfRuntimeStackFrame& frame = GetCurrentStackFrame();
if (stack.Count() <= frame.freeStackBase) return WfRuntimeThreadContextError::StackCorrupted;
}
value = stack[stack.Count() - 1];
stack.RemoveAt(stack.Count() - 1);
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::RaiseException(const WString& exception, bool fatalError, bool skipDebugger)
{
auto info = Ptr(new WfRuntimeExceptionInfo(exception, fatalError));
return RaiseException(info, skipDebugger);
}
WfRuntimeThreadContextError WfRuntimeThreadContext::RaiseException(Ptr<WfRuntimeExceptionInfo> info, bool skipDebugger)
{
exceptionInfo = info;
status = info->fatal ? WfRuntimeExecutionStatus::FatalError : WfRuntimeExecutionStatus::RaisedException;
if (info->callStack.Count() == 0)
{
if (auto debugger = GetDebuggerForCurrentThread())
{
vint contextCount = debugger->GetThreadContexts().Count();
for (vint i = contextCount - 1; i >= 0; i--)
{
auto context = debugger->GetThreadContexts()[i];
vint stackCount = context->stackFrames.Count();
for (vint j = stackCount - 1; j >= 0; j--)
{
const auto& stackFrame = context->stackFrames[j];
info->callStack.Add(Ptr(new WfRuntimeCallStackInfo(context, stackFrame)));
}
if (i > 0)
{
info->callStack.Add(Ptr(new WfRuntimeCallStackInfo));
}
}
if (!skipDebugger)
{
if (auto callback = GetDebuggerCallback(debugger.Obj()))
{
if (callback->BreakException(info))
{
if (!callback->WaitForContinue())
{
RaiseException(L"Internal error: Debugger stopped the program.", true, true);
}
}
}
}
}
}
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::LoadStackValue(vint stackItemIndex, reflection::description::Value& value)
{
if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
auto frame = GetCurrentStackFrame();
if (stackItemIndex < frame.freeStackBase || stackItemIndex >= stack.Count())
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
value = stack[stackItemIndex];
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::LoadGlobalVariable(vint variableIndex, reflection::description::Value& value)
{
if (variableIndex < 0 || variableIndex >= globalContext->globalVariables->variables.Count())
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
value = globalContext->globalVariables->variables[variableIndex];
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::StoreGlobalVariable(vint variableIndex, const reflection::description::Value& value)
{
if (variableIndex < 0 || variableIndex >= globalContext->globalVariables->variables.Count())
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
globalContext->globalVariables->variables[variableIndex] = value;
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::LoadCapturedVariable(vint variableIndex, reflection::description::Value& value)
{
if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
auto frame = GetCurrentStackFrame();
if (variableIndex < 0 || variableIndex >= frame.capturedVariables->variables.Count())
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
value = frame.capturedVariables->variables[variableIndex];
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::StoreCapturedVariable(vint variableIndex, const reflection::description::Value& value)
{
if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
auto frame = GetCurrentStackFrame();
if (variableIndex < 0 || variableIndex >= frame.capturedVariables->variables.Count())
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
frame.capturedVariables->variables[variableIndex] = value;
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::LoadLocalVariable(vint variableIndex, reflection::description::Value& value)
{
if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
auto frame = GetCurrentStackFrame();
if (variableIndex < 0 || variableIndex >= frame.fixedVariableCount)
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
value = stack[frame.stackBase + variableIndex];
return WfRuntimeThreadContextError::Success;
}
WfRuntimeThreadContextError WfRuntimeThreadContext::StoreLocalVariable(vint variableIndex, const reflection::description::Value& value)
{
if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
auto frame = GetCurrentStackFrame();
if (variableIndex < 0 || variableIndex >= frame.fixedVariableCount)
{
return WfRuntimeThreadContextError::WrongVariableIndex;
}
stack[frame.stackBase + variableIndex] = value;
return WfRuntimeThreadContextError::Success;
}
void WfRuntimeThreadContext::ExecuteToEnd()
{
auto callback = GetDebuggerCallback();
if (callback)
{
callback->EnterThreadContext(this);
}
while (Execute(callback) != WfRuntimeExecutionAction::Nop);
if (callback)
{
callback->LeaveThreadContext(this);
}
}
}
}
}
#endif
/***********************************************************************
.\WFRUNTIMEASSEMBLY.CPP
***********************************************************************/
namespace vl
{
using namespace reflection::description;
using namespace workflow::runtime;
using namespace workflow::typeimpl;
using namespace collections;
namespace stream
{
namespace internal
{
struct WfDeserializationException
{
};
struct WfReaderContext
{
Dictionary<vint, ITypeDescriptor*> tdIndex;
Dictionary<vint, IMethodInfo*> miIndex;
Dictionary<vint, IPropertyInfo*> piIndex;
Dictionary<vint, IEventInfo*> eiIndex;
WfAssemblyLoadErrors& errors;
WfReaderContext(WfAssemblyLoadErrors& _errors)
:errors(_errors)
{
}
};
struct WfWriterContextPrepare
{
SortedList<ITypeDescriptor*> tds;
SortedList<IMethodInfo*> mis;
SortedList<IPropertyInfo*> pis;
SortedList<IEventInfo*> eis;
};
struct WfWriterContext
{
Dictionary<ITypeDescriptor*, vint> tdIndex;
Dictionary<IMethodInfo*, vint> miIndex;
Dictionary<IPropertyInfo*, vint> piIndex;
Dictionary<IEventInfo*, vint> eiIndex;
void Initialize(WfWriterContextPrepare& prepare)
{
for (auto [td, index] : indexed(prepare.tds))
{
tdIndex.Add(td, index);
}
for (auto [mi, index] : indexed(prepare.mis))
{
miIndex.Add(mi, index);
}
for (auto [pi, index] : indexed(prepare.pis))
{
piIndex.Add(pi, index);
}
for (auto [ei, index] : indexed(prepare.eis))
{
eiIndex.Add(ei, index);
}
}
};
using WfReader = Reader<Ptr<WfReaderContext>>;
using WfWriter = Writer<Ptr<WfWriterContext>>;
/***********************************************************************
Serialization (CollectMetadata)
***********************************************************************/
static void CollectTd(ITypeDescriptor* td, WfWriterContextPrepare& prepare)
{
if (!prepare.tds.Contains(td))
{
prepare.tds.Add(td);
}
}
static void CollectTd(ITypeInfo* typeInfo, WfWriterContextPrepare& prepare)
{
switch (typeInfo->GetDecorator())
{
case ITypeInfo::RawPtr:
case ITypeInfo::SharedPtr:
case ITypeInfo::Nullable:
CollectTd(typeInfo->GetElementType(), prepare);
break;
case ITypeInfo::Generic:
{
CollectTd(typeInfo->GetElementType(), prepare);
vint count = typeInfo->GetGenericArgumentCount();
for (vint i = 0; i < count; i++)
{
CollectTd(typeInfo->GetGenericArgument(i), prepare);
}
}
break;
case ITypeInfo::TypeDescriptor:
CollectTd(typeInfo->GetTypeDescriptor(), prepare);
break;
}
}
static void CollectTd(IMethodInfo* info, WfWriterContextPrepare& prepare)
{
CollectTd(info->GetOwnerTypeDescriptor(), prepare);
CollectTd(info->GetReturn(), prepare);
vint count = info->GetParameterCount();
for (vint i = 0; i < count; i++)
{
CollectTd(info->GetParameter(i)->GetType(), prepare);
}
}
static void CollectTd(IEventInfo* info, WfWriterContextPrepare& prepare)
{
CollectTd(info->GetOwnerTypeDescriptor(), prepare);
CollectTd(info->GetHandlerType(), prepare);
}
static void CollectTd(IPropertyInfo* info, WfWriterContextPrepare& prepare)
{
CollectTd(info->GetOwnerTypeDescriptor(), prepare);
CollectTd(info->GetReturn(), prepare);
}
static void CollectTd(WfCustomType* td, WfWriterContextPrepare& prepare)
{
CollectTd((ITypeDescriptor*)td, prepare);
vint baseCount = td->GetBaseTypeDescriptorCount();
for (vint i = 0; i < baseCount; i++)
{
auto baseType = td->GetBaseTypeDescriptor(i);
CollectTd(baseType, prepare);
}
if(auto group = td->GetConstructorGroup())
{
vint methodCount = group->GetMethodCount();
for (vint j = 0; j < methodCount; j++)
{
auto method = group->GetMethod(j);
CollectTd(method, prepare);
}
}
vint methodGroupCount = td->GetMethodGroupCount();
for (vint i = 0; i < methodGroupCount; i++)
{
auto group = td->GetMethodGroup(i);
vint methodCount = group->GetMethodCount();
for (vint j = 0; j < methodCount; j++)
{
auto method = group->GetMethod(j);
CollectTd(method, prepare);
}
}
vint propertyCount = td->GetPropertyCount();
for (vint i = 0; i < propertyCount; i++)
{
CollectTd(td->GetProperty(i), prepare);
}
vint eventCount = td->GetEventCount();
for (vint i = 0; i < eventCount; i++)
{
CollectTd(td->GetEvent(i), prepare);
}
}
static void CollectTd(WfStruct* td, WfWriterContextPrepare& prepare)
{
CollectTd((ITypeDescriptor*)td, prepare);
vint propertyCount = td->GetPropertyCount();
for (vint i = 0; i < propertyCount; i++)
{
CollectTd(td->GetProperty(i), prepare);
}
}
static void CollectTd(WfEnum* td, WfWriterContextPrepare& prepare)
{
CollectTd((ITypeDescriptor*)td, prepare);
}
static void CollectMetadata(WfTypeImpl* typeImpl, WfWriterContextPrepare& prepare)
{
for (auto td : typeImpl->classes)
{
CollectTd(td.Obj(), prepare);
}
for (auto td : typeImpl->interfaces)
{
CollectTd(td.Obj(), prepare);
}
for (auto td : typeImpl->structs)
{
CollectTd(td.Obj(), prepare);
}
for (auto td : typeImpl->enums)
{
CollectTd(td.Obj(), prepare);
}
}
static void CollectMetadata(collections::List<WfInstruction>& instructions, WfWriterContextPrepare& prepare)
{
#define TD(X) do{ if (!prepare.tds.Contains(X)) prepare.tds.Add(X); }while(0)
#define MI(X) do{ if (!prepare.mis.Contains(X)) prepare.mis.Add(X); }while(0)
#define PI(X) do{ if (!prepare.pis.Contains(X)) prepare.pis.Add(X); }while(0)
#define EI(X) do{ if (!prepare.eis.Contains(X)) prepare.eis.Add(X); }while(0)
#define COLLECTMETADATA(NAME) case WfInsCode::NAME: break;
#define COLLECTMETADATA_VALUE(NAME) case WfInsCode::NAME: if (auto td = ins.valueParameter.typeDescriptor) TD(td); break;
#define COLLECTMETADATA_FUNCTION(NAME) case WfInsCode::NAME: break;
#define COLLECTMETADATA_FUNCTION_COUNT(NAME) case WfInsCode::NAME: break;
#define COLLECTMETADATA_VARIABLE(NAME) case WfInsCode::NAME: break;
#define COLLECTMETADATA_COUNT(NAME) case WfInsCode::NAME: break;
#define COLLECTMETADATA_FLAG_TYPEDESCRIPTOR(NAME) case WfInsCode::NAME: TD(ins.typeDescriptorParameter); break;
#define COLLECTMETADATA_PROPERTY(NAME) case WfInsCode::NAME: PI(ins.propertyParameter); break;
#define COLLECTMETADATA_METHOD(NAME) case WfInsCode::NAME: MI(ins.methodParameter); break;
#define COLLECTMETADATA_METHOD_COUNT(NAME) case WfInsCode::NAME: MI(ins.methodParameter); break;
#define COLLECTMETADATA_EVENT(NAME) case WfInsCode::NAME: EI(ins.eventParameter); break;
#define COLLECTMETADATA_EVENT_COUNT(NAME) case WfInsCode::NAME: EI(ins.eventParameter); break;
#define COLLECTMETADATA_LABEL(NAME) case WfInsCode::NAME: break;
#define COLLECTMETADATA_TYPE(NAME) case WfInsCode::NAME: break;
for (vint i = 0; i < instructions.Count(); i++)
{
auto& ins = instructions[i];
switch (ins.code)
{
INSTRUCTION_CASES(
COLLECTMETADATA,
COLLECTMETADATA_VALUE,
COLLECTMETADATA_FUNCTION,
COLLECTMETADATA_FUNCTION_COUNT,
COLLECTMETADATA_VARIABLE,
COLLECTMETADATA_COUNT,
COLLECTMETADATA_FLAG_TYPEDESCRIPTOR,
COLLECTMETADATA_PROPERTY,
COLLECTMETADATA_METHOD,
COLLECTMETADATA_METHOD_COUNT,
COLLECTMETADATA_EVENT,
COLLECTMETADATA_EVENT_COUNT,
COLLECTMETADATA_LABEL,
COLLECTMETADATA_TYPE
)
}
}
for (auto mi : prepare.mis)
{
CollectTd(mi, prepare);
}
for (auto pi : prepare.pis)
{
CollectTd(pi, prepare);
}
for (auto ei : prepare.eis)
{
CollectTd(ei, prepare);
}
#undef COLLECTMETADATA
#undef COLLECTMETADATA_VALUE
#undef COLLECTMETADATA_FUNCTION
#undef COLLECTMETADATA_FUNCTION_COUNT
#undef COLLECTMETADATA_VARIABLE
#undef COLLECTMETADATA_COUNT
#undef COLLECTMETADATA_FLAG_TYPEDESCRIPTOR
#undef COLLECTMETADATA_PROPERTY
#undef COLLECTMETADATA_METHOD
#undef COLLECTMETADATA_METHOD_COUNT
#undef COLLECTMETADATA_EVENT
#undef COLLECTMETADATA_EVENT_COUNT
#undef COLLECTMETADATA_LABEL
#undef COLLECTMETADATA_TYPE
#undef MI
#undef TD
#undef PI
#undef EI
}
/***********************************************************************
Serizliation (Data Structures)
***********************************************************************/
BEGIN_SERIALIZATION(glr::ParsingTextPos)
SERIALIZE(index)
SERIALIZE(row)
SERIALIZE(column)
END_SERIALIZATION
BEGIN_SERIALIZATION(glr::ParsingTextRange)
SERIALIZE(start)
SERIALIZE(end)
SERIALIZE(codeIndex)
END_SERIALIZATION
BEGIN_SERIALIZATION(WfInstructionDebugInfo)
SERIALIZE(moduleCodes)
SERIALIZE(instructionCodeMapping)
END_SERIALIZATION
BEGIN_SERIALIZATION(WfAssemblyFunction)
SERIALIZE(name)
SERIALIZE(argumentNames)
SERIALIZE(capturedVariableNames)
SERIALIZE(localVariableNames)
SERIALIZE(firstInstruction)
SERIALIZE(lastInstruction)
END_SERIALIZATION
SERIALIZE_ENUM(WfInsCode)
SERIALIZE_ENUM(WfInsType)
SERIALIZE_ENUM(Value::ValueType)
/***********************************************************************
Serizliation (ITypeDescriptor)
***********************************************************************/
template<>
struct Serialization<ITypeDescriptor*>
{
static void IO(WfReader& reader, ITypeDescriptor*& value)
{
WString id;
reader << id;
value = GetTypeDescriptor(id);
if (!value)
{
reader.context->errors.unresolvedTypes.Add(id);
}
}
static void IO(WfWriter& writer, ITypeDescriptor*& value)
{
WString id = value->GetTypeName();
writer << id;
}
};
/***********************************************************************
Serizliation (ITypeInfo)
***********************************************************************/
template<>
struct Serialization<ITypeInfo>
{
static void IOType(WfReader& reader, Ptr<ITypeInfo>& typeInfo)
{
vint decorator = 0;
reader << decorator;
switch (static_cast<ITypeInfo::Decorator>(decorator))
{
case ITypeInfo::RawPtr:
{
Ptr<ITypeInfo> elementType;
IOType(reader, elementType);
typeInfo = Ptr(new RawPtrTypeInfo(elementType));
}
break;
case ITypeInfo::SharedPtr:
{
Ptr<ITypeInfo> elementType;
IOType(reader, elementType);
typeInfo = Ptr(new SharedPtrTypeInfo(elementType));
}
break;
case ITypeInfo::Nullable:
{
Ptr<ITypeInfo> elementType;
IOType(reader, elementType);
typeInfo = Ptr(new NullableTypeInfo(elementType));
}
break;
case ITypeInfo::Generic:
{
Ptr<ITypeInfo> elementType;
IOType(reader, elementType);
auto genericType = Ptr(new GenericTypeInfo(elementType));
typeInfo = genericType;
vint count = 0;
reader << count;
for (vint i = 0; i < count; i++)
{
Ptr<ITypeInfo> argumentType;
IOType(reader, argumentType);
genericType->AddGenericArgument(argumentType);
}
}
break;
case ITypeInfo::TypeDescriptor:
{
vint hint = 0;
reader << hint;
vint index;
reader << index;
typeInfo = Ptr(new TypeDescriptorTypeInfo(reader.context->tdIndex[index], static_cast<TypeInfoHint>(hint)));
}
break;
}
}
static void IOType(WfWriter& writer, ITypeInfo* typeInfo)
{
vint decorator = static_cast<vint>(typeInfo->GetDecorator());
writer << decorator;
switch (typeInfo->GetDecorator())
{
case ITypeInfo::RawPtr:
case ITypeInfo::SharedPtr:
case ITypeInfo::Nullable:
IOType(writer, typeInfo->GetElementType());
break;
case ITypeInfo::Generic:
{
IOType(writer, typeInfo->GetElementType());
vint count = typeInfo->GetGenericArgumentCount();
writer << count;
for (vint i = 0; i < count; i++)
{
IOType(writer, typeInfo->GetGenericArgument(i));
}
}
break;
case ITypeInfo::TypeDescriptor:
{
vint hint = static_cast<vint>(typeInfo->GetHint());
writer << hint;
vint index = writer.context->tdIndex[typeInfo->GetTypeDescriptor()];
writer << index;
}
break;
}
}
};
/***********************************************************************
Serizliation (Metadata)
***********************************************************************/
template<>
struct Serialization<IMethodInfo*>
{
static void IO(WfReader& reader, IMethodInfo*& value)
{
value = nullptr;
vint typeIndex = -1;
WString name;
reader << typeIndex << name;
auto type = reader.context->tdIndex[typeIndex];
auto group = name == L"#ctor"
? type->GetConstructorGroup()
: type->GetMethodGroupByName(name, false);
if (!group)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): *");
return;
}
vint methodFlag = -1;
reader << methodFlag;
if (0 > methodFlag || methodFlag > 3)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): *");
return;
}
vint methodCount = group->GetMethodCount();
switch (methodFlag)
{
case 0:
{
if (methodCount > 1)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): *; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings.");
return;
}
value = group->GetMethod(0);
}
break;
case 1:
{
vint count = -1;
reader << count;
WString parameters;
for (vint i = 0; i < count; i++)
{
if (i == 0)
{
parameters = L"*";
}
else
{
parameters += L", *";
}
}
for (vint i = 0; i < methodCount; i++)
{
auto method = group->GetMethod(i);
if (method->GetParameterCount() == count)
{
if (value)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings with the same amount of parameters.");
return;
}
value = method;
}
}
if (!value)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; A qualified method doesn't exist.");
return;
}
}
break;
case 2:
{
Ptr<ITypeInfo> returnType;
Serialization<ITypeInfo>::IOType(reader, returnType);
auto signature = returnType->GetTypeFriendlyName();
for (vint i = 0; i < methodCount; i++)
{
auto method = group->GetMethod(i);
if (method->GetReturn()->GetTypeFriendlyName() == signature)
{
if (value)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): " + signature + L"; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings with the same return type.");
return;
}
value = method;
}
}
if (!value)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): " + signature + L"; A qualified method doesn't exist.");
return;
}
}
break;
case 3:
{
vint count = -1;
reader << count;
List<WString> signatures;
for (vint i = 0; i < count; i++)
{
Ptr<ITypeInfo> type;
Serialization<ITypeInfo>::IOType(reader, type);
signatures.Add(type->GetTypeFriendlyName());
}
WString parameters;
for (vint i = 0; i < count; i++)
{
if (i == 0)
{
parameters = signatures[0];
}
else
{
parameters += L", " + signatures[i];
}
}
for (vint i = 0; i < methodCount; i++)
{
auto method = group->GetMethod(i);
if (method->GetParameterCount() == count)
{
bool found = true;
for (vint j = 0; j < count; j++)
{
if (method->GetParameter(j)->GetType()->GetTypeFriendlyName() != signatures[j])
{
found = false;
break;
}
}
if (found)
{
if (value)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings with the same parameter types.");
return;
}
value = method;
}
}
}
if (!value)
{
reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; A qualified method doesn't exist.");
return;
}
}
break;
}
}
static void IO(WfWriter& writer, IMethodInfo*& value)
{
auto type = value->GetOwnerTypeDescriptor();
vint typeIndex = writer.context->tdIndex[type];
auto group = value->GetOwnerMethodGroup();
WString name = group == type->GetConstructorGroup()
? L"#ctor"
: value->GetName();
writer << typeIndex << name;
vint methodFlag = 0;
if (group->GetMethodCount() == 1)
{
writer << methodFlag;
return;
}
vint count = value->GetParameterCount();
{
vint satisfied = 0;
for (vint i = 0; i < group->GetMethodCount(); i++)
{
if (group->GetMethod(i)->GetParameterCount() == count)
{
satisfied++;
}
}
if (satisfied == 1)
{
methodFlag = 1;
writer << methodFlag << count;
return;
}
}
auto returnType = value->GetReturn();
{
auto signature = returnType->GetTypeFriendlyName();
vint satisfied = 0;
for (vint i = 0; i < group->GetMethodCount(); i++)
{
if (group->GetMethod(i)->GetReturn()->GetTypeFriendlyName() == signature)
{
satisfied++;
}
}
if (satisfied == 1)
{
methodFlag = 2;
writer << methodFlag;
Serialization<ITypeInfo>::IOType(writer, returnType);
return;
}
}
methodFlag = 3;
writer << methodFlag << count;
for (vint i = 0; i < count; i++)
{
Serialization<ITypeInfo>::IOType(writer, value->GetParameter(i)->GetType());
}
}
};
template<>
struct Serialization<IPropertyInfo*>
{
static void IO(WfReader& reader, IPropertyInfo*& value)
{
vint typeIndex = -1;
WString name;
reader << typeIndex << name;
auto type = reader.context->tdIndex[typeIndex];
value = type->GetPropertyByName(name, false);
if (!value)
{
reader.context->errors.unresolvedMembers.Add(L"property: " + type->GetTypeName() + L"::" + name);
}
}
static void IO(WfWriter& writer, IPropertyInfo*& value)
{
auto type = value->GetOwnerTypeDescriptor();
vint typeIndex = writer.context->tdIndex[type];
WString name = value->GetName();
writer << typeIndex << name;
}
};
template<>
struct Serialization<IEventInfo*>
{
static void IO(WfReader& reader, IEventInfo*& value)
{
vint typeIndex = -1;
WString name;
reader << typeIndex << name;
auto type = reader.context->tdIndex[typeIndex];
value = type->GetEventByName(name, false);
if (!value)
{
reader.context->errors.unresolvedMembers.Add(L"event: " + type->GetTypeName() + L"::" + name);
}
}
static void IO(WfWriter& writer, IEventInfo*& value)
{
auto type = value->GetOwnerTypeDescriptor();
vint typeIndex = writer.context->tdIndex[type];
WString name = value->GetName();
writer << typeIndex << name;
}
};
template<>
struct Serialization<WfRuntimeValue>
{
static void IO(WfReader& reader, WfRuntimeValue& value)
{
vint typeIndex = -1;
reader << typeIndex;
value.typeDescriptor = typeIndex == -1 ? nullptr : reader.context->tdIndex[typeIndex];
reader << value.type;
value.stringValue = WString();
switch (value.type)
{
case WfInsType::Bool: reader << value.boolValue; break;
case WfInsType::I1: { vint64_t intValue = 0; reader << intValue; value.i1Value = (vint8_t)intValue; break; }
case WfInsType::I2: { vint64_t intValue = 0; reader << intValue; value.i2Value = (vint16_t)intValue; break; }
case WfInsType::I4: { vint64_t intValue = 0; reader << intValue; value.i4Value = (vint32_t)intValue; break; }
case WfInsType::I8: { vint64_t intValue = 0; reader << intValue; value.i8Value = (vint64_t)intValue; break; }
case WfInsType::U1: { vuint64_t intValue = 0; reader << intValue; value.u1Value = (vuint8_t)intValue; break; }
case WfInsType::U2: { vuint64_t intValue = 0; reader << intValue; value.u2Value = (vuint16_t)intValue; break; }
case WfInsType::U4: { vuint64_t intValue = 0; reader << intValue; value.u4Value = (vuint32_t)intValue; break; }
case WfInsType::U8: { vuint64_t intValue = 0; reader << intValue; value.u8Value = (vuint64_t)intValue; break; }
case WfInsType::F4: reader << value.f4Value; break;
case WfInsType::F8: reader << value.f8Value; break;
case WfInsType::String: reader << value.stringValue; break;
default:;
}
}
static void IO(WfWriter& writer, WfRuntimeValue& value)
{
vint typeIndex = -1;
if (value.typeDescriptor) typeIndex = writer.context->tdIndex[value.typeDescriptor];
writer << typeIndex;
writer << value.type;
switch (value.type)
{
case WfInsType::Bool: writer << value.boolValue; break;
case WfInsType::I1: { vint64_t intValue = value.i1Value; writer << intValue; break; }
case WfInsType::I2: { vint64_t intValue = value.i2Value; writer << intValue; break; }
case WfInsType::I4: { vint64_t intValue = value.i4Value; writer << intValue; break; }
case WfInsType::I8: { vint64_t intValue = value.i8Value; writer << intValue; break; }
case WfInsType::U1: { vuint64_t intValue = value.u1Value; writer << intValue; break; }
case WfInsType::U2: { vuint64_t intValue = value.u2Value; writer << intValue; break; }
case WfInsType::U4: { vuint64_t intValue = value.u4Value; writer << intValue; break; }
case WfInsType::U8: { vuint64_t intValue = value.u8Value; writer << intValue; break; }
case WfInsType::F4: writer << value.f4Value; break;
case WfInsType::F8: writer << value.f8Value; break;
case WfInsType::String: writer << value.stringValue; break;
default:;
}
}
};
/***********************************************************************
Serialization (TypeImpl)
***********************************************************************/
template<>
struct Serialization<WfTypeImpl>
{
static void IOType(WfReader& reader, Ptr<ITypeInfo>& typeInfo)
{
Serialization<ITypeInfo>::IOType(reader, typeInfo);
}
static void IOType(WfWriter& writer, ITypeInfo* typeInfo)
{
Serialization<ITypeInfo>::IOType(writer, typeInfo);
}
//----------------------------------------------------
static void IOMethodBase(WfReader& reader, WfMethodBase* info)
{
Ptr<ITypeInfo> type;
IOType(reader, type);
info->SetReturn(type);
vint count = 0;
reader << count;
for (vint i = 0; i < count; i++)
{
WString name;
IOType(reader, type);
reader << name;
info->AddParameter(Ptr(new ParameterInfoImpl(info, name, type)));
}
}
static void IOMethodBase(WfWriter& writer, WfMethodBase* info)
{
IOType(writer, info->GetReturn());
vint count = info->GetParameterCount();
writer << count;
for (vint i = 0; i < count; i++)
{
auto parameter = info->GetParameter(i);
IOType(writer, parameter->GetType());
WString name = parameter->GetName();
writer << name;
}
}
//----------------------------------------------------
static void IOStaticMethod(WfReader& reader, WfStaticMethod* info)
{
reader << info->functionIndex;
IOMethodBase(reader, info);
}
static void IOStaticMethod(WfWriter& writer, WfStaticMethod* info)
{
writer << info->functionIndex;
IOMethodBase(writer, info);
}
//----------------------------------------------------
static void IOClassMethod(WfReader& reader, WfClassMethod* info)
{
reader << info->functionIndex;
IOMethodBase(reader, info);
}
static void IOClassMethod(WfWriter& writer, WfClassMethod* info)
{
writer << info->functionIndex;
IOMethodBase(writer, info);
}
//----------------------------------------------------
static void IOClassConstructor(WfReader& reader, Ptr<WfClassConstructor>& info)
{
info = Ptr(new WfClassConstructor(nullptr));
reader << info->functionIndex;
IOMethodBase(reader, info.Obj());
}
static void IOClassConstructor(WfWriter& writer, WfClassConstructor* info)
{
writer << info->functionIndex;
IOMethodBase(writer, info);
}
//----------------------------------------------------
static void IOInterfaceConstructor(WfReader& reader, Ptr<WfInterfaceConstructor>& info)
{
Ptr<ITypeInfo> type;
IOType(reader, type);
info = Ptr(new WfInterfaceConstructor(type));
}
static void IOInterfaceConstructor(WfWriter& writer, WfInterfaceConstructor* info)
{
IOType(writer, info->GetReturn());
}
//----------------------------------------------------
static void IOInterfaceMethod(WfReader& reader, WfInterfaceMethod* info)
{
IOMethodBase(reader, info);
}
static void IOInterfaceMethod(WfWriter& writer, WfInterfaceMethod* info)
{
IOMethodBase(writer, info);
}
//----------------------------------------------------
static void IOCustomType(WfReader& reader, WfCustomType* td, bool isClass)
{
// constructors
{
vint methodCount = 0;
reader << methodCount;
for (vint i = 0; i < methodCount; i++)
{
if (isClass)
{
Ptr<WfClassConstructor> ctor;
IOClassConstructor(reader, ctor);
td->AddMember(ctor);
}
else
{
Ptr<WfInterfaceConstructor> ctor;
IOInterfaceConstructor(reader, ctor);
td->AddMember(ctor);
}
}
}
// base types
vint baseCount = 0;
reader << baseCount;
for (vint i = 0; i < baseCount; i++)
{
vint index = 0;
reader << index;
auto baseTd = reader.context->tdIndex[index];
td->AddBaseType(baseTd);
}
// methods
vint methodGroupCount = 0;
reader << methodGroupCount;
for (vint i = 0; i < methodGroupCount; i++)
{
vint methodCount = 0;
WString methodName;
reader << methodCount << methodName;
for (vint j = 0; j < methodCount; j++)
{
bool isStaticMethod = false;
reader << isStaticMethod;
if (isStaticMethod)
{
auto info = Ptr(new WfStaticMethod);
td->AddMember(methodName, info);
IOStaticMethod(reader, info.Obj());
}
else if (isClass)
{
auto info = Ptr(new WfClassMethod);
td->AddMember(methodName, info);
IOClassMethod(reader, info.Obj());
}
else
{
auto info = Ptr(new WfInterfaceMethod);
td->AddMember(methodName, info);
IOInterfaceMethod(reader, info.Obj());
}
}
}
// events
vint eventCount = 0;
reader << eventCount;
for (vint i = 0; i < eventCount; i++)
{
WString eventName;
reader << eventName;
Ptr<ITypeInfo> eventType;
IOType(reader, eventType);
auto info = Ptr(new WfEvent(td, eventName));
info->SetHandlerType(eventType);
td->AddMember(info);
}
// properties
vint propertyCount = 0;
reader << propertyCount;
for (vint i = 0; i < propertyCount; i++)
{
bool isProperty = false;
WString propName;
reader << isProperty << propName;
if (isProperty)
{
auto info = Ptr(new WfProperty(td, propName));
WString getterName, setterName, eventName;
reader << getterName << setterName << eventName;
if (getterName != L"")
{
info->SetGetter(dynamic_cast<MethodInfoImpl*>(td->GetMethodGroupByName(getterName, false)->GetMethod(0)));
}
if (setterName != L"")
{
info->SetSetter(dynamic_cast<MethodInfoImpl*>(td->GetMethodGroupByName(setterName, false)->GetMethod(0)));
}
if (eventName != L"")
{
info->SetValueChangedEvent(dynamic_cast<EventInfoImpl*>(td->GetEventByName(eventName, false)));
}
td->AddMember(info);
}
else
{
Ptr<ITypeInfo> fieldType;
IOType(reader, fieldType);
auto info = Ptr(new WfField(td, propName));
info->SetReturn(fieldType);
td->AddMember(info);
}
}
}
static void IOCustomType(WfWriter& writer, WfCustomType* td, bool isClass)
{
// constructors
{
vint methodCount = 0;
if (auto group = td->GetConstructorGroup())
{
vint methodCount = group->GetMethodCount();
writer << methodCount;
for (vint i = 0; i < methodCount; i++)
{
if (isClass)
{
auto ctor = dynamic_cast<WfClassConstructor*>(group->GetMethod(i));
IOClassConstructor(writer, ctor);
}
else
{
auto ctor = dynamic_cast<WfInterfaceConstructor*>(group->GetMethod(i));
IOInterfaceConstructor(writer, ctor);
}
}
}
else
{
writer << methodCount;
}
}
// base types
vint baseCount = td->GetBaseTypeDescriptorCount();
writer << baseCount;
for (vint i = 0; i < baseCount; i++)
{
auto baseTd = td->GetBaseTypeDescriptor(i);
vint index = writer.context->tdIndex[baseTd];
writer << index;
}
// methods
vint methodGroupCount = td->GetMethodGroupCount();
writer << methodGroupCount;
for (vint i = 0; i < methodGroupCount; i++)
{
auto group = td->GetMethodGroup(i);
vint methodCount = group->GetMethodCount();
WString methodName = group->GetName();
writer << methodCount << methodName;
for (vint j = 0; j < methodCount; j++)
{
auto method = group->GetMethod(j);
bool isStaticMethod = false;
if (auto staticMethod = dynamic_cast<WfStaticMethod*>(method))
{
isStaticMethod = true;
writer << isStaticMethod;
IOStaticMethod(writer, staticMethod);
}
else if (isClass)
{
writer << isStaticMethod;
IOClassMethod(writer, dynamic_cast<WfClassMethod*>(method));
}
else
{
auto interfaceMethod = dynamic_cast<WfInterfaceMethod*>(method);
writer << isStaticMethod;
IOInterfaceMethod(writer, interfaceMethod);
}
}
}
// events
vint eventCount = td->GetEventCount();
writer << eventCount;
for (vint i = 0; i < eventCount; i++)
{
auto info = td->GetEvent(i);
WString eventName = info->GetName();
writer << eventName;
IOType(writer, info->GetHandlerType());
}
// properties
vint propertyCount = td->GetPropertyCount();
writer << propertyCount;
for (vint i = 0; i < propertyCount; i++)
{
auto propInfo = td->GetProperty(i);
bool isProperty = false;
if (dynamic_cast<WfProperty*>(propInfo))
{
isProperty = true;
WString propName = propInfo->GetName();
writer << isProperty << propName;
auto getterName = propInfo->GetGetter() ? propInfo->GetGetter()->GetName() : L"";
auto setterName = propInfo->GetSetter() ? propInfo->GetSetter()->GetName() : L"";
auto eventName = propInfo->GetValueChangedEvent() ? propInfo->GetValueChangedEvent()->GetName() : L"";
writer << getterName << setterName << eventName;
}
else
{
isProperty = false;
WString propName = propInfo->GetName();
writer << isProperty << propName;
IOType(writer, propInfo->GetReturn());
}
}
}
//----------------------------------------------------
static void IOClass(WfReader& reader, WfClass* td)
{
reader << td->destructorFunctionIndex;
IOCustomType(reader, td, true);
}
static void IOClass(WfWriter& writer, WfClass* td)
{
writer << td->destructorFunctionIndex;
IOCustomType(writer, td, true);
}
//----------------------------------------------------
static void IOInterface(WfReader& reader, WfInterface* td)
{
IOCustomType(reader, td, false);
}
static void IOInterface(WfWriter& writer, WfInterface* td)
{
IOCustomType(writer, td, false);
}
//----------------------------------------------------
static void IOStruct(WfReader& reader, WfStruct* td)
{
vint count;
reader << count;
for (vint i = 0; i < count; i++)
{
WString name;
reader << name;
Ptr<ITypeInfo> typeInfo;
IOType(reader, typeInfo);
auto field = Ptr(new WfStructField(td, name));
field->SetReturn(typeInfo);
td->AddMember(field);
}
}
static void IOStruct(WfWriter& writer, WfStruct* td)
{
vint count = td->GetPropertyCount();
writer << count;
for (vint i = 0; i < count; i++)
{
auto prop = td->GetProperty(i);
WString name = prop->GetName();
writer << name;
ITypeInfo* typeInfo = prop->GetReturn();
IOType(writer, typeInfo);
}
}
//----------------------------------------------------
static void IOEnum(WfReader& reader, WfEnum* td)
{
vint count;
reader << count;
auto et = td->GetEnumType();
for (vint i = 0; i < count; i++)
{
WString name;
vint64_t value;
reader << name << value;
td->AddEnumItem(name, (vuint64_t)value);
}
}
static void IOEnum(WfWriter& writer, WfEnum* td)
{
auto et = td->GetEnumType();
vint count = et->GetItemCount();
writer << count;
for (vint i = 0; i < count; i++)
{
WString name = et->GetItemName(i);
vint64_t value = (vint64_t)et->GetItemValue(i);
writer << name << value;
}
}
//----------------------------------------------------
static void IO(WfReader& reader, WfTypeImpl& value)
{
// fill types
for (auto td : value.classes)
{
IOClass(reader, td.Obj());
}
for (auto td : value.interfaces)
{
IOInterface(reader, td.Obj());
}
for (auto td : value.structs)
{
IOStruct(reader, td.Obj());
}
for (auto td : value.enums)
{
IOEnum(reader, td.Obj());
}
}
static void IO(WfWriter& writer, WfTypeImpl& value)
{
// fill types
for (auto td : value.classes)
{
IOClass(writer, td.Obj());
}
for (auto td : value.interfaces)
{
IOInterface(writer, td.Obj());
}
for (auto td : value.structs)
{
IOStruct(writer, td.Obj());
}
for (auto td : value.enums)
{
IOEnum(writer, td.Obj());
}
}
};
/***********************************************************************
Serialization (Instruction)
***********************************************************************/
template<>
struct Serialization<WfInstruction>
{
static void IO(WfReader& reader, WfInstruction& value)
{
reader << value.code;
#define IO(X) do{ reader << (X); }while(0)
#define TD(X) do{ vint index = -1; reader << index; X = reader.context->tdIndex[index]; }while(0)
#define MI(X) do{ vint index = -1; reader << index; X = reader.context->miIndex[index]; }while(0)
#define PI(X) do{ vint index = -1; reader << index; X = reader.context->piIndex[index]; }while(0)
#define EI(X) do{ vint index = -1; reader << index; X = reader.context->eiIndex[index]; }while(0)
#define STREAMIO(NAME) case WfInsCode::NAME: break;
#define STREAMIO_VALUE(NAME) case WfInsCode::NAME: IO(value.valueParameter); break;
#define STREAMIO_FUNCTION(NAME) case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_FUNCTION_COUNT(NAME) case WfInsCode::NAME: IO(value.indexParameter); IO(value.countParameter); break;
#define STREAMIO_VARIABLE(NAME) case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_COUNT(NAME) case WfInsCode::NAME: IO(value.countParameter); break;
#define STREAMIO_FLAG_TYPEDESCRIPTOR(NAME) case WfInsCode::NAME: IO(value.flagParameter); TD(value.typeDescriptorParameter); break;
#define STREAMIO_PROPERTY(NAME) case WfInsCode::NAME: PI(value.propertyParameter); break;
#define STREAMIO_METHOD(NAME) case WfInsCode::NAME: MI(value.methodParameter); break;
#define STREAMIO_METHOD_COUNT(NAME) case WfInsCode::NAME: MI(value.methodParameter); IO(value.countParameter); break;
#define STREAMIO_EVENT(NAME) case WfInsCode::NAME: EI(value.eventParameter); break;
#define STREAMIO_EVENT_COUNT(NAME) case WfInsCode::NAME: EI(value.eventParameter); IO(value.countParameter); break;
#define STREAMIO_LABEL(NAME) case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_TYPE(NAME) case WfInsCode::NAME: IO(value.typeParameter); break;
switch (value.code)
{
INSTRUCTION_CASES(
STREAMIO,
STREAMIO_VALUE,
STREAMIO_FUNCTION,
STREAMIO_FUNCTION_COUNT,
STREAMIO_VARIABLE,
STREAMIO_COUNT,
STREAMIO_FLAG_TYPEDESCRIPTOR,
STREAMIO_PROPERTY,
STREAMIO_METHOD,
STREAMIO_METHOD_COUNT,
STREAMIO_EVENT,
STREAMIO_EVENT_COUNT,
STREAMIO_LABEL,
STREAMIO_TYPE)
}
#undef STREAMIO
#undef STREAMIO_VALUE
#undef STREAMIO_FUNCTION
#undef STREAMIO_FUNCTION_COUNT
#undef STREAMIO_VARIABLE
#undef STREAMIO_COUNT
#undef STREAMIO_FLAG_TYPEDESCRIPTOR
#undef STREAMIO_PROPERTY
#undef STREAMIO_METHOD
#undef STREAMIO_METHOD_COUNT
#undef STREAMIO_EVENT
#undef STREAMIO_EVENT_COUNT
#undef STREAMIO_LABEL
#undef STREAMIO_TYPE
#undef MI
#undef TD
#undef PI
#undef EI
#undef IO
}
static void IO(WfWriter& writer, WfInstruction& value)
{
writer << value.code;
#define IO(X) do{ writer << (X); }while(0)
#define TD(X) do{ vint index = writer.context->tdIndex[X]; writer << index; }while(0)
#define MI(X) do{ vint index = writer.context->miIndex[X]; writer << index; }while(0)
#define PI(X) do{ vint index = writer.context->piIndex[X]; writer << index; }while(0)
#define EI(X) do{ vint index = writer.context->eiIndex[X]; writer << index; }while(0)
#define STREAMIO(NAME) case WfInsCode::NAME: break;
#define STREAMIO_VALUE(NAME) case WfInsCode::NAME: IO(value.valueParameter); break;
#define STREAMIO_FUNCTION(NAME) case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_FUNCTION_COUNT(NAME) case WfInsCode::NAME: IO(value.indexParameter); IO(value.countParameter); break;
#define STREAMIO_VARIABLE(NAME) case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_COUNT(NAME) case WfInsCode::NAME: IO(value.countParameter); break;
#define STREAMIO_FLAG_TYPEDESCRIPTOR(NAME) case WfInsCode::NAME: IO(value.flagParameter); TD(value.typeDescriptorParameter); break;
#define STREAMIO_PROPERTY(NAME) case WfInsCode::NAME: PI(value.propertyParameter); break;
#define STREAMIO_METHOD(NAME) case WfInsCode::NAME: MI(value.methodParameter); break;
#define STREAMIO_METHOD_COUNT(NAME) case WfInsCode::NAME: MI(value.methodParameter); IO(value.countParameter); break;
#define STREAMIO_EVENT(NAME) case WfInsCode::NAME: EI(value.eventParameter); break;
#define STREAMIO_EVENT_COUNT(NAME) case WfInsCode::NAME: EI(value.eventParameter); IO(value.countParameter); break;
#define STREAMIO_LABEL(NAME) case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_TYPE(NAME) case WfInsCode::NAME: IO(value.typeParameter); break;
switch (value.code)
{
INSTRUCTION_CASES(
STREAMIO,
STREAMIO_VALUE,
STREAMIO_FUNCTION,
STREAMIO_FUNCTION_COUNT,
STREAMIO_VARIABLE,
STREAMIO_COUNT,
STREAMIO_FLAG_TYPEDESCRIPTOR,
STREAMIO_PROPERTY,
STREAMIO_METHOD,
STREAMIO_METHOD_COUNT,
STREAMIO_EVENT,
STREAMIO_EVENT_COUNT,
STREAMIO_LABEL,
STREAMIO_TYPE)
}
#undef STREAMIO
#undef STREAMIO_VALUE
#undef STREAMIO_FUNCTION
#undef STREAMIO_FUNCTION_COUNT
#undef STREAMIO_VARIABLE
#undef STREAMIO_COUNT
#undef STREAMIO_FLAG_TYPEDESCRIPTOR
#undef STREAMIO_PROPERTY
#undef STREAMIO_METHOD
#undef STREAMIO_METHOD_COUNT
#undef STREAMIO_EVENT
#undef STREAMIO_EVENT_COUNT
#undef STREAMIO_LABEL
#undef STREAMIO_TYPE
#undef MI
#undef TD
#undef PI
#undef EI
#undef IO
}
};
/***********************************************************************
Serialization (Assembly)
***********************************************************************/
template<>
struct Serialization<WfAssembly>
{
//----------------------------------------------------
static void IOCustomType(WfReader& reader, Ptr<WfEnum>& type)
{
bool isFlags;
WString typeName;
if (GetTypeDescriptor(typeName))
{
reader.context->errors.duplicatedTypes.Add(typeName);
}
reader << isFlags << typeName;
type = Ptr(new WfEnum(isFlags, typeName));
}
static void IOCustomType(WfWriter& writer, Ptr<WfEnum>& type)
{
bool isFlags = type->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum;
WString typeName = type->GetTypeName();
writer << isFlags << typeName;
}
template<typename TType>
static void IOCustomType(WfReader& reader, Ptr<TType>& type)
{
WString typeName;
reader << typeName;
if (GetTypeDescriptor(typeName))
{
reader.context->errors.duplicatedTypes.Add(typeName);
}
type = Ptr(new TType(typeName));
}
template<typename TType>
static void IOCustomType(WfWriter& writer, Ptr<TType>& type)
{
WString typeName = type->GetTypeName();
writer << typeName;
}
//----------------------------------------------------
template<typename TType>
static void IOCustomTypeList(WfReader& reader, List<Ptr<TType>>& types)
{
vint typeCount = 0;
reader << typeCount;
for (vint i = 0; i < typeCount; i++)
{
Ptr<TType> type;
IOCustomType(reader, type);
types.Add(type);
}
for (vint i = 0; i < typeCount; i++)
{
vint index = -reader.context->tdIndex.Count() - 1;
reader.context->tdIndex.Add(index, types[i].Obj());
}
}
template<typename TType>
static void IOCustomTypeList(WfWriter& writer, List<Ptr<TType>>& types)
{
vint typeCount = types.Count();
writer << typeCount;
for (vint i = 0; i < typeCount; i++)
{
auto type = types[i];
IOCustomType(writer, type);
}
for (vint i = 0; i < typeCount; i++)
{
vint index = -writer.context->tdIndex.Count() - 1;
writer.context->tdIndex.Add(types[i].Obj(), index);
}
}
//----------------------------------------------------
static void IOPrepare(WfReader& reader, WfAssembly& value, WfAssemblyLoadErrors& errors)
{
reader.context = Ptr(new WfReaderContext(errors));
bool hasTypeImpl = false;
reader << hasTypeImpl;
if (hasTypeImpl)
{
value.typeImpl = Ptr(new WfTypeImpl);
IOCustomTypeList(reader, value.typeImpl->classes);
IOCustomTypeList(reader, value.typeImpl->interfaces);
IOCustomTypeList(reader, value.typeImpl->structs);
IOCustomTypeList(reader, value.typeImpl->enums);
}
vint tdCount = -1;
vint miCount = -1;
vint piCount = -1;
vint eiCount = -1;
reader << tdCount << miCount << piCount << eiCount;
for (vint i = 0; i < tdCount; i++)
{
ITypeDescriptor* td = nullptr;
reader << td;
reader.context->tdIndex.Add(i, td);
}
if (errors.unresolvedTypes.Count() + errors.duplicatedTypes.Count() > 0)
{
throw WfDeserializationException();
}
if (hasTypeImpl)
{
Serialization<WfTypeImpl>::IO(reader, *value.typeImpl.Obj());
GetGlobalTypeManager()->AddTypeLoader(value.typeImpl);
}
for (vint i = 0; i < miCount; i++)
{
IMethodInfo* mi = nullptr;
reader << mi;
reader.context->miIndex.Add(i, mi);
}
for (vint i = 0; i < piCount; i++)
{
IPropertyInfo* pi = nullptr;
reader << pi;
reader.context->piIndex.Add(i, pi);
}
for (vint i = 0; i < eiCount; i++)
{
IEventInfo* ei = nullptr;
reader << ei;
reader.context->eiIndex.Add(i, ei);
}
if (errors.unresolvedMembers.Count() > 0)
{
throw WfDeserializationException();
}
}
static void IOPrepare(WfWriter& writer, WfAssembly& value, WfAssemblyLoadErrors&)
{
writer.context = Ptr(new WfWriterContext);
bool hasTypeImpl = value.typeImpl != nullptr;
writer << hasTypeImpl;
if (hasTypeImpl)
{
IOCustomTypeList(writer, value.typeImpl->classes);
IOCustomTypeList(writer, value.typeImpl->interfaces);
IOCustomTypeList(writer, value.typeImpl->structs);
IOCustomTypeList(writer, value.typeImpl->enums);
}
WfWriterContextPrepare prepare;
if (hasTypeImpl)
{
CollectMetadata(value.typeImpl.Obj(), prepare);
}
CollectMetadata(value.instructions, prepare);
for (vint i = prepare.tds.Count() - 1; i >= 0; i--)
{
if (writer.context->tdIndex.Keys().Contains(prepare.tds[i]))
{
prepare.tds.RemoveAt(i);
}
}
writer.context->Initialize(prepare);
vint tdCount = prepare.tds.Count();
vint miCount = prepare.mis.Count();
vint piCount = prepare.pis.Count();
vint eiCount = prepare.eis.Count();
writer << tdCount << miCount << piCount << eiCount;
for (auto td : prepare.tds)
{
writer << td;
}
if (hasTypeImpl)
{
Serialization<WfTypeImpl>::IO(writer, *value.typeImpl.Obj());
GetGlobalTypeManager()->AddTypeLoader(value.typeImpl);
}
for (auto mi : prepare.mis)
{
writer << mi;
}
for (auto pi : prepare.pis)
{
writer << pi;
}
for (auto ei : prepare.eis)
{
writer << ei;
}
}
//----------------------------------------------------
template<typename TIO>
static void IO(TIO& io, WfAssembly& value, WfAssemblyLoadErrors& errors)
{
IOPrepare(io, value, errors);
io << value.insBeforeCodegen
<< value.insAfterCodegen
<< value.variableNames
<< value.functionByName
<< value.functions
<< value.instructions
;
if (value.typeImpl)
{
GetGlobalTypeManager()->RemoveTypeLoader(value.typeImpl);
}
}
};
}
}
namespace workflow
{
namespace runtime
{
/***********************************************************************
WfInstructionDebugInfo
***********************************************************************/
void WfInstructionDebugInfo::Initialize()
{
for (vint i = 0; i < instructionCodeMapping.Count(); i++)
{
const auto& range = instructionCodeMapping[i];
if (range.codeIndex != -1)
{
codeInstructionMapping.Add(Tuple<vint, vint>(range.codeIndex, range.start.row), i);
}
}
}
/***********************************************************************
WfAssembly
***********************************************************************/
WfAssembly::WfAssembly()
{
}
void WfAssembly::Initialize()
{
insBeforeCodegen->Initialize();
insAfterCodegen->Initialize();
}
Ptr<WfAssembly> WfAssembly::Deserialize(stream::IStream& input, WfAssemblyLoadErrors& errors)
{
try
{
auto assembly = Ptr(new WfAssembly);
stream::internal::WfReader reader(input);
stream::internal::Serialization<WfAssembly>::IO(reader, *assembly.Obj(), errors);
assembly->Initialize();
return assembly;
}
catch (stream::internal::WfDeserializationException)
{
return {};
}
}
void WfAssembly::Serialize(stream::IStream& output)
{
WfAssemblyLoadErrors dummy;
stream::internal::WfWriter writer(output);
stream::internal::Serialization<WfAssembly>::IO(writer, *this, dummy);
}
}
}
}
/***********************************************************************
.\WFRUNTIMECONSTRUCTIONS.CPP
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
namespace vl
{
namespace workflow
{
namespace runtime
{
using namespace reflection::description;
/***********************************************************************
WfRuntimeLambda
***********************************************************************/
WfRuntimeLambda::WfRuntimeLambda(Ptr<WfRuntimeGlobalContext> _globalContext, Ptr<WfRuntimeVariableContext> _capturedVariables, vint _functionIndex)
:globalContext(_globalContext)
, capturedVariables(_capturedVariables)
, functionIndex(_functionIndex)
{
}
Value WfRuntimeLambda::Invoke(Ptr<reflection::description::IValueReadonlyList> arguments)
{
return Invoke(globalContext, capturedVariables, functionIndex, arguments);
}
Value WfRuntimeLambda::Invoke(Ptr<WfRuntimeGlobalContext> globalContext, Ptr<WfRuntimeVariableContext> capturedVariables, vint functionIndex, Ptr<reflection::description::IValueReadonlyList> arguments)
{
WfRuntimeThreadContext context(globalContext);
vint count = arguments->GetCount();
for (vint i = 0; i < count; i++)
{
context.PushValue(arguments->Get(i));
}
WString message;
if (context.PushStackFrame(functionIndex, count, capturedVariables) != WfRuntimeThreadContextError::Success)
{
throw WfRuntimeException(L"Internal error: failed to invoke a function.", true);
}
context.ExecuteToEnd();
if (context.status != WfRuntimeExecutionStatus::Finished)
{
throw WfRuntimeException(context.exceptionInfo);
}
Value result;
if (context.PopValue(result) != WfRuntimeThreadContextError::Success)
{
throw WfRuntimeException(L"Internal error: failed to pop the function result.", true);
}
return result;
}
/***********************************************************************
WfRuntimeInterfaceInstance
***********************************************************************/
Value WfRuntimeInterfaceInstance::Invoke(IMethodInfo* methodInfo, Ptr<IValueReadonlyList> arguments)
{
vint index = functions.Keys().IndexOf(methodInfo);
if (index == -1)
{
throw WfRuntimeException(
L"Internal error: failed to invoke the interface method \"" +
methodInfo->GetName() +
L"\" of type \"" +
methodInfo->GetOwnerTypeDescriptor()->GetTypeName() +
L"\"", true);
}
else
{
vint functionIndex = functions.Values()[index];
return WfRuntimeLambda::Invoke(globalContext, capturedVariables, functionIndex, arguments);
}
}
}
}
}
#endif
/***********************************************************************
.\WFRUNTIMEDEBUGGER.CPP
***********************************************************************/
#include <math.h>
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
namespace vl
{
namespace workflow
{
namespace runtime
{
using namespace collections;
using namespace reflection;
using namespace reflection::description;
/***********************************************************************
IWfDebuggerCallback
***********************************************************************/
WfBreakPoint WfBreakPoint::Ins(WfAssembly* assembly, vint instruction)
{
WfBreakPoint breakPoint;
breakPoint.type = Instruction;
breakPoint.assembly = assembly;
breakPoint.instruction = instruction;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Read(WfAssembly* assembly, vint variable)
{
WfBreakPoint breakPoint;
breakPoint.type = ReadGlobalVar;
breakPoint.assembly = assembly;
breakPoint.variable = variable;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Write(WfAssembly* assembly, vint variable)
{
WfBreakPoint breakPoint;
breakPoint.type = WriteGlobalVar;
breakPoint.assembly = assembly;
breakPoint.variable = variable;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Get(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
{
WfBreakPoint breakPoint;
breakPoint.type = GetProperty;
breakPoint.thisObject = thisObject;
breakPoint.propertyInfo = propertyInfo;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Set(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
{
WfBreakPoint breakPoint;
breakPoint.type = SetProperty;
breakPoint.thisObject = thisObject;
breakPoint.propertyInfo = propertyInfo;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Attach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
{
WfBreakPoint breakPoint;
breakPoint.type = AttachEvent;
breakPoint.thisObject = thisObject;
breakPoint.eventInfo = eventInfo;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Detach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
{
WfBreakPoint breakPoint;
breakPoint.type = DetachEvent;
breakPoint.thisObject = thisObject;
breakPoint.eventInfo = eventInfo;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Invoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
{
WfBreakPoint breakPoint;
breakPoint.type = InvokeEvent;
breakPoint.thisObject = thisObject;
breakPoint.eventInfo = eventInfo;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Invoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo)
{
WfBreakPoint breakPoint;
breakPoint.type = InvokeMethod;
breakPoint.thisObject = thisObject;
breakPoint.methodInfo = methodInfo;
return breakPoint;
}
WfBreakPoint WfBreakPoint::Create(reflection::description::ITypeDescriptor* typeDescriptor)
{
WfBreakPoint breakPoint;
breakPoint.type = CreateObject;
breakPoint.typeDescriptor = typeDescriptor;
return breakPoint;
}
/***********************************************************************
InstructionLocation
***********************************************************************/
bool WfDebugger::InstructionLocation::BreakStepOver(const InstructionLocation& il, bool beforeCodegen)
{
if (contextIndex != il.contextIndex) return contextIndex > il.contextIndex;
if (assembly != il.assembly) return true;
if (stackFrameIndex != il.stackFrameIndex) return stackFrameIndex > il.stackFrameIndex;
auto debugInfo = (beforeCodegen ? assembly->insBeforeCodegen : assembly->insAfterCodegen);
auto& range1 = debugInfo->instructionCodeMapping[instruction];
auto& range2 = debugInfo->instructionCodeMapping[il.instruction];
if (range1.codeIndex != range2.codeIndex) return true;
if (range1.start.row != range2.start.row) return true;
return false;
}
bool WfDebugger::InstructionLocation::BreakStepInto(const InstructionLocation& il, bool beforeCodegen)
{
if (contextIndex != il.contextIndex) return true;
if (assembly != il.assembly) return true;
if (stackFrameIndex != il.stackFrameIndex) return true;
auto debugInfo = (beforeCodegen ? assembly->insBeforeCodegen : assembly->insAfterCodegen);
auto& range1 = debugInfo->instructionCodeMapping[instruction];
auto& range2 = debugInfo->instructionCodeMapping[il.instruction];
if (range1.codeIndex != range2.codeIndex) return true;
if (range1.start.row != range2.start.row) return true;
return false;
}
/***********************************************************************
WfDebugger Callback Handlers
***********************************************************************/
void WfDebugger::OnBlockExecution()
{
}
void WfDebugger::OnStartExecution()
{
}
void WfDebugger::OnStopExecution()
{
}
WfDebugger::InstructionLocation WfDebugger::MakeCurrentInstructionLocation()
{
auto context = threadContexts[threadContexts.Count() - 1];
InstructionLocation il;
il.contextIndex = threadContexts.Count() - 1;
il.assembly = context->globalContext->assembly.Obj();
il.stackFrameIndex = context->stackFrames.Count() - 1;
il.instruction = context->stackFrames[context->stackFrames.Count() - 1].nextInstructionIndex;
return il;
}
template<typename TKey>
bool WfDebugger::HandleBreakPoint(const TKey& key, collections::Dictionary<TKey, vint>& breakPointMap)
{
if (evaluatingBreakPoint)
{
return false;
}
evaluatingBreakPoint = true;
bool activated = false;
vint index = breakPointMap.Keys().IndexOf(key);
if (index != -1)
{
index = breakPointMap.Values()[index];
const auto& breakPoint = breakPoints[index];
if (breakPoint.available && breakPoint.enabled)
{
if (breakPoint.action)
{
activated = breakPoint.action->EvaluateCondition(this);
breakPoint.action->PostAction(this, activated);
}
else
{
activated = true;
}
}
if (activated)
{
lastActivatedBreakPoint = index;
}
}
evaluatingBreakPoint = false;
return activated;
}
void WfDebugger::EnterThreadContext(WfRuntimeThreadContext* context)
{
if (threadContexts.Count() == 0)
{
lastActivatedBreakPoint = InvalidBreakPoint;
instructionLocation = InstructionLocation();
OnStartExecution();
if (state == Stopped)
{
state = Running;
}
}
threadContexts.Add(context);
}
void WfDebugger::LeaveThreadContext(WfRuntimeThreadContext* context)
{
auto oldContext = threadContexts[threadContexts.Count() - 1];
threadContexts.RemoveAt(threadContexts.Count() - 1);
CHECK_ERROR(context == oldContext, L"vl::workflow::runtime::WfDebugger::LeaveThreadContext(WfRuntimeThreadContext*)#EnterThreadContext and LeaveThreadContext should be called in pairs.");
if (threadContexts.Count() == 0)
{
state = Stopped;
OnStopExecution();
}
}
bool WfDebugger::BreakIns(WfAssembly* assembly, vint instruction)
{
if (runningType != RunUntilBreakPoint)
{
auto il = MakeCurrentInstructionLocation();
bool needToBreak = false;
switch (runningType)
{
case RunStepOver:
needToBreak = instructionLocation.BreakStepOver(il, stepBeforeCodegen);
break;
case RunStepInto:
needToBreak = instructionLocation.BreakStepInto(il, stepBeforeCodegen);
break;
default:;
}
if (needToBreak)
{
instructionLocation = il;
lastActivatedBreakPoint = WfDebugger::PauseBreakPoint;
return true;
}
}
switch (state)
{
case RequiredToPause:
case RequiredToStop:
lastActivatedBreakPoint = WfDebugger::PauseBreakPoint;
return true;
default:;
}
AssemblyKey key(assembly, instruction);
return HandleBreakPoint(key, insBreakPoints);
}
bool WfDebugger::BreakRead(WfAssembly* assembly, vint variable)
{
AssemblyKey key(assembly, variable);
return HandleBreakPoint(key, getGlobalVarBreakPoints);
}
bool WfDebugger::BreakWrite(WfAssembly* assembly, vint variable)
{
AssemblyKey key(assembly, variable);
return HandleBreakPoint(key, setGlobalVarBreakPoints);
}
bool WfDebugger::BreakGet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
{
PropertyKey key1(thisObject, propertyInfo);
PropertyKey key2(nullptr, propertyInfo);
return HandleBreakPoint(key1, getPropertyBreakPoints) || HandleBreakPoint(key2, getPropertyBreakPoints);
}
bool WfDebugger::BreakSet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
{
PropertyKey key1(thisObject, propertyInfo);
PropertyKey key2(nullptr, propertyInfo);
return HandleBreakPoint(key1, setPropertyBreakPoints) || HandleBreakPoint(key2, setPropertyBreakPoints);
}
bool WfDebugger::BreakAttach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
{
EventKey key1(thisObject, eventInfo);
EventKey key2(nullptr, eventInfo);
return HandleBreakPoint(key1, attachEventBreakPoints) || HandleBreakPoint(key2, attachEventBreakPoints);
}
bool WfDebugger::BreakDetach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
{
EventKey key1(thisObject, eventInfo);
EventKey key2(nullptr, eventInfo);
return HandleBreakPoint(key1, detachEventBreakPoints) || HandleBreakPoint(key2, detachEventBreakPoints);
}
bool WfDebugger::BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
{
EventKey key1(thisObject, eventInfo);
EventKey key2(nullptr, eventInfo);
return HandleBreakPoint(key1, invokeEventBreakPoints) || HandleBreakPoint(key2, invokeEventBreakPoints);
}
bool WfDebugger::BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo)
{
MethodKey key1(thisObject, methodInfo);
MethodKey key2(nullptr, methodInfo);
return HandleBreakPoint(key1, invokeMethodBreakPoints) || HandleBreakPoint(key2, invokeMethodBreakPoints);
}
bool WfDebugger::BreakCreate(reflection::description::ITypeDescriptor* typeDescriptor)
{
return HandleBreakPoint(typeDescriptor, createObjectBreakPoints);
}
bool WfDebugger::BreakException(Ptr<WfRuntimeExceptionInfo> info)
{
if (breakException)
{
lastActivatedBreakPoint = PauseBreakPoint;
return true;
}
else
{
return false;
}
}
bool WfDebugger::WaitForContinue()
{
if (state == RequiredToStop)
{
return false;
}
state = lastActivatedBreakPoint >= 0 ? PauseByBreakPoint : PauseByOperation;
while (state == PauseByBreakPoint || state == PauseByOperation)
{
OnBlockExecution();
}
if (state == Continue)
{
state = Running;
}
return true;
}
/***********************************************************************
WfDebugger BreakPoints
***********************************************************************/
#define TEST(AVAILABLE, KEY, MAP) if (AVAILABLE && available == MAP.Keys().Contains(KEY)) return false;
#define SET(KEY, MAP) if (available) MAP.Add(KEY, index); else MAP.Remove(KEY);
#define SETC(AVAILABLE, KEY, MAP) if (AVAILABLE) {if (available) MAP.Add(KEY, index); else MAP.Remove(KEY);}
bool WfDebugger::SetBreakPoint(const WfBreakPoint& breakPoint, bool available, vint index)
{
switch (breakPoint.type)
{
case WfBreakPoint::Instruction:
{
AssemblyKey key(breakPoint.assembly, breakPoint.instruction);
TEST(true, key, insBreakPoints);
SET(key, insBreakPoints);
}
break;
case WfBreakPoint::ReadGlobalVar:
{
AssemblyKey key(breakPoint.assembly, breakPoint.variable);
TEST(true, key, getGlobalVarBreakPoints);
SET(key, getGlobalVarBreakPoints);
}
break;
case WfBreakPoint::WriteGlobalVar:
{
AssemblyKey key(breakPoint.assembly, breakPoint.instruction);
TEST(true, key, setGlobalVarBreakPoints);
SET(key, setGlobalVarBreakPoints);
}
break;
case WfBreakPoint::GetProperty:
{
PropertyKey key1(breakPoint.thisObject, breakPoint.propertyInfo);
MethodKey key2(breakPoint.thisObject, breakPoint.propertyInfo->GetGetter());
TEST(true, key1, getPropertyBreakPoints);
TEST(key2.get<1>(), key2, invokeMethodBreakPoints);
SET(key1, getPropertyBreakPoints);
SETC(key2.get<1>(), key2, invokeMethodBreakPoints);
}
break;
case WfBreakPoint::SetProperty:
{
PropertyKey key1(breakPoint.thisObject, breakPoint.propertyInfo);
MethodKey key2(breakPoint.thisObject, breakPoint.propertyInfo->GetSetter());
TEST(true, key1, setPropertyBreakPoints);
TEST(key2.get<1>(), key2, invokeMethodBreakPoints);
SET(key1, setPropertyBreakPoints);
SETC(key2.get<1>(), key2, invokeMethodBreakPoints);
}
break;
case WfBreakPoint::AttachEvent:
{
EventKey key(breakPoint.thisObject, breakPoint.eventInfo);
TEST(true, key, attachEventBreakPoints);
SET(key, attachEventBreakPoints);
}
break;
case WfBreakPoint::DetachEvent:
{
EventKey key(breakPoint.thisObject, breakPoint.eventInfo);
TEST(true, key, detachEventBreakPoints);
SET(key, detachEventBreakPoints);
}
break;
case WfBreakPoint::InvokeEvent:
{
EventKey key(breakPoint.thisObject, breakPoint.eventInfo);
TEST(true, key, invokeEventBreakPoints);
SET(key, invokeEventBreakPoints);
}
break;
case WfBreakPoint::InvokeMethod:
{
// get property, set property and new object are all compiled to invoke method
// so here it is not noecessary to generate other keys
MethodKey key(breakPoint.thisObject, breakPoint.methodInfo);
TEST(true, key, invokeMethodBreakPoints);
SET(key, invokeMethodBreakPoints);
}
break;
case WfBreakPoint::CreateObject:
{
auto group = breakPoint.typeDescriptor->GetConstructorGroup();
vint count = group ? group->GetMethodCount() : 0;
TEST(true, breakPoint.typeDescriptor, createObjectBreakPoints);
for (vint i = 0; i < count; i++)
{
MethodKey key(nullptr, group->GetMethod(i));
TEST(true, key, invokeMethodBreakPoints);
}
SET(breakPoint.typeDescriptor, createObjectBreakPoints);
for (vint i = 0; i < count; i++)
{
MethodKey key(nullptr, group->GetMethod(i));
SET(key, invokeMethodBreakPoints);
}
}
break;
default:
return false;
}
return true;
}
#undef TEST
#undef SET
#undef SETC
WfDebugger::WfDebugger()
{
}
WfDebugger::~WfDebugger()
{
}
vint WfDebugger::AddBreakPoint(const WfBreakPoint& breakPoint)
{
vint index = breakPoints.Count();
if (freeBreakPointIndices.Count() > 0)
{
index = freeBreakPointIndices[freeBreakPointIndices.Count() - 1];
}
if (!SetBreakPoint(breakPoint, true, index))
{
return -1;
}
if (index == breakPoints.Count())
{
breakPoints.Add(breakPoint);
}
else
{
freeBreakPointIndices.RemoveAt(freeBreakPointIndices.Count() - 1);
breakPoints[index] = breakPoint;
}
breakPoints[index].id = index;
breakPoints[index].available = true;
breakPoints[index].enabled = true;
breakPoints[index].action = nullptr;
return index;
}
vint WfDebugger::AddCodeLineBreakPoint(WfAssembly* assembly, vint codeIndex, vint row, bool beforeCodegen)
{
auto& codeInsMap = (beforeCodegen ? assembly->insBeforeCodegen : assembly->insAfterCodegen)->codeInstructionMapping;
Tuple<vint, vint> key(codeIndex, row);
vint index = codeInsMap.Keys().IndexOf(key);
if (index == -1)
{
return -1;
}
vint ins = codeInsMap.GetByIndex(index)[0];
return AddBreakPoint(WfBreakPoint::Ins(assembly, ins));
}
bool WfDebugger::IsBreakPointAvailable(vint index)
{
return 0 <= index && index < breakPoints.Count() && !freeBreakPointIndices.Contains(index);
}
vint WfDebugger::GetBreakPointCount()
{
return breakPoints.Count();
}
const WfBreakPoint& WfDebugger::GetBreakPoint(vint index)
{
return breakPoints[index];
}
bool WfDebugger::RemoveBreakPoint(vint index)
{
if (index < 0 || index >= breakPoints.Count())
{
return false;
}
auto& breakPoint = breakPoints[index];
if (!breakPoint.available || !SetBreakPoint(breakPoint, false, -1))
{
return false;
}
breakPoint.available = false;
freeBreakPointIndices.Add(index);
return true;
}
bool WfDebugger::EnableBreakPoint(vint index, bool enabled)
{
if (0 <= index && index <= breakPoints.Count())
{
auto& breakPoint = breakPoints[index];
if (breakPoint.available)
{
breakPoint.enabled = enabled;
return true;
}
}
return false;
}
bool WfDebugger::GetBreakException()
{
return breakException;
}
void WfDebugger::SetBreakException(bool value)
{
breakException = value;
}
/***********************************************************************
WfDebugger Operations
***********************************************************************/
bool WfDebugger::Run()
{
if (state != PauseByOperation && state != PauseByBreakPoint)
{
return false;
}
state = Continue;
runningType = RunUntilBreakPoint;
return true;
}
bool WfDebugger::Pause()
{
if (state != Running && state != Stopped)
{
return false;
}
state = RequiredToPause;
return true;
}
bool WfDebugger::Stop()
{
if (state != PauseByOperation && state != PauseByBreakPoint && state != Running)
{
return false;
}
state = RequiredToStop;
return true;
}
bool WfDebugger::StepOver(bool beforeCodegen)
{
if (state != PauseByOperation && state != PauseByBreakPoint && state != Stopped)
{
return false;
}
if (state != Stopped)
{
state = Continue;
instructionLocation = MakeCurrentInstructionLocation();
}
runningType = RunStepOver;
stepBeforeCodegen = beforeCodegen;
return true;
}
bool WfDebugger::StepInto(bool beforeCodegen)
{
if (state != PauseByOperation && state != PauseByBreakPoint && state != Stopped)
{
return false;
}
if (state != Stopped)
{
state = Continue;
instructionLocation = MakeCurrentInstructionLocation();
}
state = Continue;
runningType = RunStepInto;
stepBeforeCodegen = beforeCodegen;
return true;
}
/***********************************************************************
WfDebugger
***********************************************************************/
WfDebugger::State WfDebugger::GetState()
{
return state;
}
WfDebugger::RunningType WfDebugger::GetRunningType()
{
return runningType;
}
vint WfDebugger::GetLastActivatedBreakPoint()
{
return lastActivatedBreakPoint;
}
const WfDebugger::ThreadContextList& WfDebugger::GetThreadContexts()
{
return threadContexts;
}
WfRuntimeThreadContext* WfDebugger::GetCurrentThreadContext()
{
if (threadContexts.Count() == 0)
{
return nullptr;
}
return threadContexts[threadContexts.Count() - 1];
}
const glr::ParsingTextRange& WfDebugger::GetCurrentPosition(bool beforeCodegen, WfRuntimeThreadContext* context, vint callStackIndex)
{
if (!context)
{
context = GetCurrentThreadContext();
}
if (callStackIndex == -1)
{
callStackIndex = context->stackFrames.Count() - 1;
}
auto& stackFrame = context->stackFrames[callStackIndex];
auto ins = stackFrame.nextInstructionIndex;
auto debugInfo = (beforeCodegen ? context->globalContext->assembly->insBeforeCodegen : context->globalContext->assembly->insAfterCodegen);
return debugInfo->instructionCodeMapping[ins];
}
reflection::description::Value WfDebugger::GetValueByName(const WString& name, WfRuntimeThreadContext* context, vint callStackIndex)
{
if (!context)
{
context = GetCurrentThreadContext();
}
if (callStackIndex == -1)
{
callStackIndex = context->stackFrames.Count() - 1;
}
auto& stackFrame = context->stackFrames[callStackIndex];
auto function = context->globalContext->assembly->functions[stackFrame.functionIndex];
vint index = function->argumentNames.IndexOf(name);
if (index != -1)
{
return context->stack[stackFrame.stackBase + index];
}
index = function->localVariableNames.IndexOf(name);
if (index != -1)
{
return context->stack[stackFrame.stackBase + function->argumentNames.Count() + index];
}
index = function->capturedVariableNames.IndexOf(name);
if (index != -1)
{
return stackFrame.capturedVariables->variables[index];
}
index = context->globalContext->assembly->variableNames.IndexOf(name);
if (index != -1)
{
return context->globalContext->globalVariables->variables[index];
}
return Value();
}
/***********************************************************************
Helper Functions
***********************************************************************/
ThreadVariable<Ptr<WfDebugger>> threadDebugger;
IWfDebuggerCallback* GetDebuggerCallback()
{
return GetDebuggerCallback(GetDebuggerForCurrentThread().Obj());
}
IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger)
{
return debugger;
}
Ptr<WfDebugger> GetDebuggerForCurrentThread()
{
return threadDebugger.HasData() ? threadDebugger.Get() : nullptr;
}
void SetDebuggerForCurrentThread(Ptr<WfDebugger> debugger)
{
threadDebugger.Set(debugger);
}
}
}
}
#endif
/***********************************************************************
.\WFRUNTIMEEXECUTION.CPP
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
namespace vl
{
namespace workflow
{
namespace runtime
{
using namespace collections;
using namespace reflection;
using namespace reflection::description;
using namespace typeimpl;
/***********************************************************************
WfRuntimeThreadContext (Operators)
***********************************************************************/
#define INTERNAL_ERROR(MESSAGE)\
do{\
context.RaiseException(WString(L"Internal error: " MESSAGE), true);\
return WfRuntimeExecutionAction::Nop; \
} while (0)\
#define CONTEXT_ACTION(ACTION, MESSAGE)\
do{\
if ((context.ACTION) != WfRuntimeThreadContextError::Success)\
{\
INTERNAL_ERROR(MESSAGE);\
}\
} while (0)\
//-------------------------------------------------------------------------------
#define UNARY_OPERATOR(NAME, OPERATOR)\
template<typename T>\
WfRuntimeExecutionAction OPERATOR_##NAME(WfRuntimeThreadContext& context)\
{\
Value operand;\
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");\
T value = OPERATOR UnboxValue<T>(operand);\
CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");\
return WfRuntimeExecutionAction::ExecuteInstruction;\
}\
#define BINARY_OPERATOR(NAME, OPERATOR)\
template<typename T>\
WfRuntimeExecutionAction OPERATOR_##NAME(WfRuntimeThreadContext& context)\
{\
Value first, second;\
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");\
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");\
T value = UnboxValue<T>(first) OPERATOR UnboxValue<T>(second);\
CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");\
return WfRuntimeExecutionAction::ExecuteInstruction;\
}\
//-------------------------------------------------------------------------------
UNARY_OPERATOR(OpNot, ~)
UNARY_OPERATOR(OpNot_Bool, !)
UNARY_OPERATOR(OpPositive, +)
UNARY_OPERATOR(OpNegative, -)
BINARY_OPERATOR(OpAdd, +)
BINARY_OPERATOR(OpSub, -)
BINARY_OPERATOR(OpMul, *)
BINARY_OPERATOR(OpDiv, /)
BINARY_OPERATOR(OpMod, %)
BINARY_OPERATOR(OpShl, <<)
BINARY_OPERATOR(OpShr, >>)
BINARY_OPERATOR(OpAnd, &)
BINARY_OPERATOR(OpAnd_Bool, &&)
BINARY_OPERATOR(OpOr, |)
BINARY_OPERATOR(OpOr_Bool, ||)
BINARY_OPERATOR(OpXor, ^)
template<typename T>
WfRuntimeExecutionAction OPERATOR_OpExp(WfRuntimeThreadContext& context)
{
Value first, second;
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
T firstValue = UnboxValue<T>(first);
T secondValue = UnboxValue<T>(second);
T value = (T)exp(secondValue * log(firstValue));
CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
template<typename T>
WfRuntimeExecutionAction OPERATOR_OpCompare(WfRuntimeThreadContext& context)
{
Value first, second;
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
bool firstNull = first.GetValueType() == Value::Null;
bool secondNull = second.GetValueType() == Value::Null;
if (firstNull)
{
if (secondNull)
{
CONTEXT_ACTION(PushValue(BoxValue((vint)0)), L"failed to push a value to the stack.");
}
else
{
CONTEXT_ACTION(PushValue(BoxValue((vint)-1)), L"failed to push a value to the stack.");
}
}
else
{
if (secondNull)
{
CONTEXT_ACTION(PushValue(BoxValue((vint)1)), L"failed to push a value to the stack.");
}
else
{
T firstValue = UnboxValue<T>(first);
T secondValue = UnboxValue<T>(second);
if (firstValue < secondValue)
{
CONTEXT_ACTION(PushValue(BoxValue((vint)-1)), L"failed to push a value to the stack.");
}
else if (firstValue > secondValue)
{
CONTEXT_ACTION(PushValue(BoxValue((vint)1)), L"failed to push a value to the stack.");
}
else
{
CONTEXT_ACTION(PushValue(BoxValue((vint)0)), L"failed to push a value to the stack.");
}
}
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
/***********************************************************************
WfRuntimeThreadContext (TypeConversion)
***********************************************************************/
bool OPERATOR_OpConvertToType(const Value& result, Value& converted, const WfInstruction& ins)
{
switch (ins.flagParameter)
{
case Value::Null:
return false;
case Value::RawPtr:
if (result.GetValueType() == Value::BoxedValue)
{
return false;
}
else if (result.GetRawPtr())
{
if (result.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter))
{
converted = Value::From(result.GetRawPtr());
}
else
{
return false;
}
}
break;
case Value::SharedPtr:
if (result.GetValueType() == Value::BoxedValue)
{
return false;
}
else if (result.GetRawPtr())
{
if (result.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter))
{
converted = Value::From(Ptr<DescriptableObject>(result.GetRawPtr()));
}
else
{
return false;
}
}
break;
case Value::BoxedValue:
if (result.GetValueType() != Value::BoxedValue)
{
return false;
}
if (result.GetTypeDescriptor() == ins.typeDescriptorParameter)
{
converted = result;
return true;
}
if (auto stFrom = result.GetTypeDescriptor()->GetSerializableType())
{
if (auto stTo = ins.typeDescriptorParameter->GetSerializableType())
{
WString text;
return stFrom->Serialize(result, text) && stTo->Deserialize(text, converted);
}
else
{
switch (ins.typeDescriptorParameter->GetTypeDescriptorFlags())
{
case TypeDescriptorFlags::FlagEnum:
case TypeDescriptorFlags::NormalEnum:
if (result.GetTypeDescriptor() != GetTypeDescriptor<vuint64_t>())
{
return false;
}
else
{
auto intValue = result.GetBoxedValue().Cast<IValueType::TypedBox<vuint64_t>>()->value;
converted = ins.typeDescriptorParameter->GetEnumType()->ToEnum(intValue);
}
break;
default:
return false;
}
}
}
else
{
switch (result.GetTypeDescriptor()->GetTypeDescriptorFlags())
{
case TypeDescriptorFlags::FlagEnum:
case TypeDescriptorFlags::NormalEnum:
if (ins.typeDescriptorParameter != GetTypeDescriptor<vuint64_t>())
{
return false;
}
else
{
auto intValue = result.GetTypeDescriptor()->GetEnumType()->FromEnum(result);
converted = BoxValue<vuint64_t>(intValue);
}
break;
default:
return false;
}
}
}
return true;
}
/***********************************************************************
WfRuntimeThreadContext (Range)
***********************************************************************/
template<typename T>
WfRuntimeExecutionAction OPERATOR_OpCreateRange(WfRuntimeThreadContext& context)
{
Value first, second;
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
T firstValue = UnboxValue<T>(first);
T secondValue = UnboxValue<T>(second);
auto enumerable = Ptr(new WfRuntimeRange<T>(firstValue, secondValue));
CONTEXT_ACTION(PushValue(Value::From(enumerable)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
#undef INTERNAL_ERROR
#undef CONTEXT_ACTION
#undef UNARY_OPERATOR
#undef BINARY_OPERATOR
/***********************************************************************
Helper Functions
***********************************************************************/
Ptr<reflection::description::IValueFunctionProxy> LoadFunction(Ptr<WfRuntimeGlobalContext> context, const WString& name)
{
const auto& names = context->assembly->functionByName[name];
CHECK_ERROR(names.Count() == 1, L"vl::workflow::runtime::LoadFunction(Ptr<WfRUntimeGlobalContext>, const WString&)#Multiple functions are found.");
vint functionIndex = names[0];
auto lambda = Ptr(new WfRuntimeLambda(context, nullptr, functionIndex));
return lambda;
}
/***********************************************************************
WfRuntimeThreadContext
***********************************************************************/
#define INTERNAL_ERROR(MESSAGE)\
do{\
RaiseException(WString(L"Internal error: " MESSAGE), true);\
return WfRuntimeExecutionAction::Nop; \
} while (0)\
#define CONTEXT_ACTION(ACTION, MESSAGE)\
do{\
if ((ACTION) != WfRuntimeThreadContextError::Success)\
{\
INTERNAL_ERROR(MESSAGE);\
}\
} while (0)\
#define CALL_DEBUGGER(ACTION)\
do {\
if (callback)\
{\
if (ACTION)\
{\
if (!callback->WaitForContinue())\
{\
INTERNAL_ERROR(L"Debugger stopped the program.");\
}\
}\
}\
} while (0)\
#define TYPE_OF_Bool bool
#define TYPE_OF_I1 vint8_t
#define TYPE_OF_I2 vint16_t
#define TYPE_OF_I4 vint32_t
#define TYPE_OF_I8 vint64_t
#define TYPE_OF_U1 vuint8_t
#define TYPE_OF_U2 vuint16_t
#define TYPE_OF_U4 vuint32_t
#define TYPE_OF_U8 vuint64_t
#define TYPE_OF_F4 float
#define TYPE_OF_F8 double
#define TYPE_OF_String WString
#define EXECUTE(OPERATION, TYPE) case WfInsType::TYPE: return OPERATOR_##OPERATION<TYPE_OF_##TYPE>(*this);
#define BEGIN_TYPE switch(ins.typeParameter) {
#define END_TYPE default: INTERNAL_ERROR(L"unexpected type argument."); }
WfRuntimeExecutionAction WfRuntimeThreadContext::ExecuteInternal(WfInstruction& ins, WfRuntimeStackFrame& stackFrame, IWfDebuggerCallback* callback)
{
switch (ins.code)
{
case WfInsCode::LoadValue:
CONTEXT_ACTION(PushRuntimeValue(ins.valueParameter), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
case WfInsCode::LoadFunction:
{
CONTEXT_ACTION(PushValue(BoxValue(ins.indexParameter)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadException:
{
CONTEXT_ACTION(PushValue(BoxValue(exceptionInfo)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadLocalVar:
{
Value operand;
CONTEXT_ACTION(LoadLocalVariable(ins.indexParameter, operand), L"illegal local variable index.");
CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadCapturedVar:
{
Value operand;
CONTEXT_ACTION(LoadCapturedVariable(ins.indexParameter, operand), L"illegal captured variable index.");
CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadGlobalVar:
{
CALL_DEBUGGER(callback->BreakRead(globalContext->assembly.Obj(), ins.indexParameter));
Value operand;
CONTEXT_ACTION(LoadGlobalVariable(ins.indexParameter, operand), L"illegal global variable index.");
CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadMethodInfo:
{
CONTEXT_ACTION(PushValue(Value::From(ins.methodParameter)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadMethodClosure:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
auto closure = ins.methodParameter->CreateFunctionProxy(operand);
CONTEXT_ACTION(PushValue(closure), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::LoadClosureContext:
{
auto capturedVariables = GetCurrentStackFrame().capturedVariables;
CONTEXT_ACTION(PushValue(Value::From(capturedVariables)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::StoreLocalVar:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CONTEXT_ACTION(StoreLocalVariable(ins.indexParameter, operand), L"illegal local variable index.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::StoreCapturedVar:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CONTEXT_ACTION(StoreCapturedVariable(ins.indexParameter, operand), L"illegal global variable index.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::StoreGlobalVar:
{
CALL_DEBUGGER(callback->BreakWrite(globalContext->assembly.Obj(), ins.indexParameter));
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CONTEXT_ACTION(StoreGlobalVariable(ins.indexParameter, operand), L"illegal global variable index.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::Duplicate:
{
vint index = stack.Count() - 1 - ins.countParameter;
Value operand;
CONTEXT_ACTION(LoadStackValue(index, operand), L"failed to duplicate a value from the stack.");
CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::Pop:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::Return:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop the function result.");
CONTEXT_ACTION(PopStackFrame(), L"failed to pop the stack frame.");
CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
if (stackFrames.Count() == 0)
{
status = WfRuntimeExecutionStatus::Finished;
}
return WfRuntimeExecutionAction::ExitStackFrame;
}
case WfInsCode::NewArray:
{
auto list = IValueArray::Create();
if (ins.countParameter > 0)
{
list->Resize(ins.countParameter);
Value operand;
for (vint i = 0; i < ins.countParameter; i++)
{
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
list->Set(i, operand);
}
}
CONTEXT_ACTION(PushValue(Value::From(list)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::NewList:
{
auto list = IValueList::Create();
Value operand;
for (vint i = 0; i < ins.countParameter; i++)
{
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
list->Add(operand);
}
CONTEXT_ACTION(PushValue(Value::From(list)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::NewObservableList:
{
auto list = IValueObservableList::Create();
Value operand;
for (vint i = 0; i < ins.countParameter; i++)
{
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
list->Add(operand);
}
CONTEXT_ACTION(PushValue(Value::From(list)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::NewDictionary:
{
auto map = IValueDictionary::Create();
Value key, value;
for (vint i = 0; i < ins.countParameter; i+=2)
{
CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(key), L"failed to pop a value from the stack.");
map->Set(key, value);
}
CONTEXT_ACTION(PushValue(Value::From(map)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::CreateClosureContext:
{
Ptr<WfRuntimeVariableContext> capturedVariables;
if (ins.countParameter > 0)
{
capturedVariables = Ptr(new WfRuntimeVariableContext);
capturedVariables->variables.Resize(ins.countParameter);
Value operand;
for (vint i = 0; i < ins.countParameter; i++)
{
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
capturedVariables->variables[ins.countParameter - 1 - i] = operand;
}
}
CONTEXT_ACTION(PushValue(Value::From(capturedVariables)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::CreateClosure:
{
Value context, function;
CONTEXT_ACTION(PopValue(function), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(context), L"failed to pop a value from the stack.");
auto capturedVariables = context.GetSharedPtr().Cast<WfRuntimeVariableContext>();
auto functionIndex = UnboxValue<vint>(function);
auto lambda = Ptr(new WfRuntimeLambda(globalContext, capturedVariables, functionIndex));
CONTEXT_ACTION(PushValue(Value::From(lambda)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::CreateInterface:
{
auto proxy = Ptr(new WfRuntimeInterfaceInstance);
Value key, value, operand;
for (vint i = 0; i < ins.countParameter; i+=2)
{
CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(key), L"failed to pop a value from the stack.");
auto name = UnboxValue<IMethodInfo*>(key);
auto func = UnboxValue<vint>(value);
proxy->functions.Add(name, func);
}
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
auto capturedVariables = operand.GetSharedPtr().Cast<WfRuntimeVariableContext>();
proxy->capturedVariables = capturedVariables;
proxy->globalContext = globalContext;
Array<Value> arguments(1);
arguments[0] = Value::From(proxy);
auto obj = ins.methodParameter->Invoke(Value(), arguments);
capturedVariables->variables[capturedVariables->variables.Count() - 1] = Value::From(obj.GetRawPtr());
CONTEXT_ACTION(PushValue(obj), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::CreateRange:
BEGIN_TYPE
EXECUTE(OpCreateRange, I1)
EXECUTE(OpCreateRange, I2)
EXECUTE(OpCreateRange, I4)
EXECUTE(OpCreateRange, I8)
EXECUTE(OpCreateRange, U1)
EXECUTE(OpCreateRange, U2)
EXECUTE(OpCreateRange, U4)
EXECUTE(OpCreateRange, U8)
END_TYPE
case WfInsCode::CreateStruct:
{
if (ins.typeDescriptorParameter->GetTypeDescriptorFlags() != TypeDescriptorFlags::Struct)
{
INTERNAL_ERROR(L"Type \"" + ins.typeDescriptorParameter->GetTypeName() + L"\" is not a struct.");
}
Value result = ins.typeDescriptorParameter->GetValueType()->CreateDefault();
CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::DeleteRawPtr:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
operand.DeleteRawPtr();
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::ConvertToType:
{
Value result, converted;
CONTEXT_ACTION(PopValue(result), L"failed to pop a value from the stack.");
if (OPERATOR_OpConvertToType(result, converted, ins))
{
CONTEXT_ACTION(PushValue(converted), L"failed to push a value to the stack.");
}
else
{
WString from;
if (result.IsNull())
{
from = L"<null>";
}
else
{
if (auto st = result.GetTypeDescriptor()->GetSerializableType())
{
WString text;
st->Serialize(result, text);
from = L"<" + text + L"> of " + result.GetTypeDescriptor()->GetTypeName();
}
else
{
from = result.GetTypeDescriptor()->GetTypeName();
}
}
WString to = ins.typeDescriptorParameter->GetTypeName();
RaiseException(L"Failed to convert from \"" + from + L"\" to \"" + to + L"\".", false);
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::TryConvertToType:
{
Value result, converted;
CONTEXT_ACTION(PopValue(result), L"failed to pop a value from the stack.");
if (OPERATOR_OpConvertToType(result, converted, ins))
{
CONTEXT_ACTION(PushValue(converted), L"failed to push a value to the stack.");
}
else
{
CONTEXT_ACTION(PushValue(Value()), L"failed to push a value to the stack.");
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::TestType:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
if (operand.GetTypeDescriptor() && operand.GetValueType() == ins.flagParameter && operand.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter))
{
CONTEXT_ACTION(PushValue(BoxValue(true)), L"failed to push a value to the stack.");
}
else
{
CONTEXT_ACTION(PushValue(BoxValue(false)), L"failed to push a value to the stack.");
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::GetType:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PushValue(Value::From(operand.GetTypeDescriptor())), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::Jump:
{
stackFrame.nextInstructionIndex = ins.indexParameter;
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::JumpIf:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
if (UnboxValue<bool>(operand))
{
stackFrame.nextInstructionIndex = ins.indexParameter;
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::Invoke:
{
CONTEXT_ACTION(PushStackFrame(ins.indexParameter, ins.countParameter), L"failed to invoke a function.");
return WfRuntimeExecutionAction::EnterStackFrame;
}
case WfInsCode::InvokeWithContext:
{
CONTEXT_ACTION(PushStackFrame(ins.indexParameter, ins.countParameter, GetCurrentStackFrame().capturedVariables), L"failed to invoke a function.");
return WfRuntimeExecutionAction::EnterStackFrame;
}
case WfInsCode::GetProperty:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakGet(operand.GetRawPtr(), ins.propertyParameter));
Value result = ins.propertyParameter->GetValue(operand);
CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::SetProperty:
{
Value operand, value;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakSet(operand.GetRawPtr(), ins.propertyParameter));
ins.propertyParameter->SetValue(operand, value);
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::UpdateProperty:
{
Value operand, value;
CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakSet(operand.GetRawPtr(), ins.propertyParameter));
ins.propertyParameter->SetValue(operand, value);
CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::InvokeProxy:
{
Value thisValue;
CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
auto proxy = UnboxValue<Ptr<IValueFunctionProxy>>(thisValue);
if (!proxy)
{
INTERNAL_ERROR(L"failed to invoke a null function proxy.");
return WfRuntimeExecutionAction::Nop;
}
if (auto lambda = proxy.Cast<WfRuntimeLambda>())
{
if (lambda->globalContext == globalContext)
{
CONTEXT_ACTION(PushStackFrame(lambda->functionIndex, ins.countParameter, lambda->capturedVariables), L"failed to invoke a function.");
return WfRuntimeExecutionAction::EnterStackFrame;
}
}
List<Value> arguments;
for (vint i = 0; i < ins.countParameter; i++)
{
Value argument;
CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
arguments.Insert(0, argument);
}
Ptr<IValueList> list = Ptr(new ValueListWrapper<List<Value>*>(&arguments));
Value result = proxy->Invoke(list);
CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::InvokeMethod:
{
Value thisValue;
CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.methodParameter));
if (auto staticMethod = dynamic_cast<WfStaticMethod*>(ins.methodParameter))
{
if (staticMethod->GetGlobalContext() == globalContext.Obj())
{
CONTEXT_ACTION(PushStackFrame(staticMethod->functionIndex, ins.countParameter, nullptr), L"failed to invoke a function.");
return WfRuntimeExecutionAction::EnterStackFrame;
}
}
if (auto classMethod = dynamic_cast<WfClassMethod*>(ins.methodParameter))
{
if (classMethod->GetGlobalContext() == globalContext.Obj())
{
auto capturedVariable = Ptr(new WfRuntimeVariableContext);
capturedVariable->variables.Resize(1);
capturedVariable->variables[0] = Value::From(thisValue.GetRawPtr());
CONTEXT_ACTION(PushStackFrame(classMethod->functionIndex, ins.countParameter, capturedVariable), L"failed to invoke a function.");
return WfRuntimeExecutionAction::EnterStackFrame;
}
}
Array<Value> arguments(ins.countParameter);
for (vint i = 0; i < ins.countParameter; i++)
{
Value argument;
CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
arguments[ins.countParameter - i - 1] = argument;
}
Value result = ins.methodParameter->Invoke(thisValue, arguments);
CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::InvokeEvent:
{
Value thisValue;
CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.eventParameter));
auto arguments = IValueList::Create();
for (vint i = 0; i < ins.countParameter; i++)
{
Value argument;
CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
arguments->Insert(0, argument);
}
ins.eventParameter->Invoke(thisValue, arguments);
CONTEXT_ACTION(PushValue(Value()), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::InvokeBaseCtor:
{
Value thisValue;
CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.eventParameter));
if (auto ctor = dynamic_cast<WfClassConstructor*>(ins.methodParameter))
{
if (ctor->GetGlobalContext() == globalContext.Obj())
{
auto capturedVariable = Ptr(new WfRuntimeVariableContext);
capturedVariable->variables.Resize(1);
capturedVariable->variables[0] = Value::From(thisValue.GetRawPtr());
CONTEXT_ACTION(PushStackFrame(ctor->functionIndex, ins.countParameter, capturedVariable), L"failed to invoke a function.");
return WfRuntimeExecutionAction::EnterStackFrame;
}
}
Array<Value> arguments(ins.countParameter);
for (vint i = 0; i < ins.countParameter; i++)
{
Value argument;
CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
arguments[ins.countParameter - i - 1] = argument;
}
if (auto ctor = dynamic_cast<WfClassConstructor*>(ins.methodParameter))
{
ctor->InvokeBaseCtor(thisValue, arguments);
}
else
{
auto instance = dynamic_cast<WfClassInstance*>(thisValue.GetRawPtr());
if (!instance)
{
INTERNAL_ERROR(L"Wrong class instance for invoking base constructor.");
}
Value baseValue = ins.methodParameter->Invoke(Value(), arguments);
instance->InstallBaseObject(ins.methodParameter->GetOwnerTypeDescriptor(), baseValue);
}
CONTEXT_ACTION(PushValue(Value()), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::AttachEvent:
{
Value thisValue, function;
CONTEXT_ACTION(PopValue(function), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakAttach(thisValue.GetRawPtr(), ins.eventParameter));
auto proxy = UnboxValue<Ptr<IValueFunctionProxy>>(function);
auto handler = ins.eventParameter->Attach(thisValue, proxy);
CONTEXT_ACTION(PushValue(Value::From(handler)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::DetachEvent:
{
Value thisValue, operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
CALL_DEBUGGER(callback->BreakDetach(thisValue.GetRawPtr(), ins.eventParameter));
auto handler = UnboxValue<Ptr<IEventHandler>>(operand);
auto result = ins.eventParameter->Detach(thisValue, handler);
CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::InstallTry:
CONTEXT_ACTION(PushTrapFrame(ins.indexParameter), L"failed to push a trap frame");
return WfRuntimeExecutionAction::ExecuteInstruction;
case WfInsCode::UninstallTry:
{
if (trapFrames.Count() == 0)
{
INTERNAL_ERROR(L"failed to pop the trap frame.");
}
auto frame = GetCurrentTrapFrame();
CONTEXT_ACTION(PopTrapFrame(ins.countParameter), L"failed to pop the trap frame.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::RaiseException:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
if (operand.GetValueType() == Value::BoxedValue)
{
WString text;
operand.GetTypeDescriptor()->GetSerializableType()->Serialize(operand, text);
RaiseException(text, false);
}
else if (auto info = operand.GetSharedPtr().Cast<WfRuntimeExceptionInfo>())
{
RaiseException(info);
}
else if (auto ex = operand.GetSharedPtr().Cast<IValueException>())
{
RaiseException(ex->GetMessage(), false);
}
else
{
INTERNAL_ERROR(L"failed to raise an exception which is neither a string nor a WfRuntimeExceptionInfo.");
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::TestElementInSet:
{
Value element, set;
CONTEXT_ACTION(PopValue(set), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(element), L"failed to pop a value from the stack.");
auto enumerable = UnboxValue<Ptr<IValueEnumerable>>(set);
auto enumerator = enumerable->CreateEnumerator();
while (enumerator->Next())
{
if (enumerator->GetCurrent() == element)
{
CONTEXT_ACTION(PushValue(BoxValue(true)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
}
CONTEXT_ACTION(PushValue(BoxValue(false)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::CompareLiteral:
BEGIN_TYPE
EXECUTE(OpCompare, Bool)
EXECUTE(OpCompare, I1)
EXECUTE(OpCompare, I2)
EXECUTE(OpCompare, I4)
EXECUTE(OpCompare, I8)
EXECUTE(OpCompare, U1)
EXECUTE(OpCompare, U2)
EXECUTE(OpCompare, U4)
EXECUTE(OpCompare, U8)
EXECUTE(OpCompare, F4)
EXECUTE(OpCompare, F8)
EXECUTE(OpCompare, String)
END_TYPE
case WfInsCode::CompareReference:
{
Value first, second;
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
bool result = first.GetValueType() != Value::BoxedValue && second.GetValueType() != Value::BoxedValue && first.GetRawPtr() == second.GetRawPtr();
CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::CompareValue:
{
Value first, second;
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
bool result = first == second;
CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::OpNot:
BEGIN_TYPE
EXECUTE(OpNot_Bool, Bool)
EXECUTE(OpNot, I1)
EXECUTE(OpNot, I2)
EXECUTE(OpNot, I4)
EXECUTE(OpNot, I8)
EXECUTE(OpNot, U1)
EXECUTE(OpNot, U2)
EXECUTE(OpNot, U4)
EXECUTE(OpNot, U8)
END_TYPE
case WfInsCode::OpPositive:
BEGIN_TYPE
EXECUTE(OpPositive, I1)
EXECUTE(OpPositive, I2)
EXECUTE(OpPositive, I4)
EXECUTE(OpPositive, I8)
EXECUTE(OpPositive, U1)
EXECUTE(OpPositive, U2)
EXECUTE(OpPositive, U4)
EXECUTE(OpPositive, U8)
EXECUTE(OpPositive, F4)
EXECUTE(OpPositive, F8)
END_TYPE
case WfInsCode::OpNegative:
BEGIN_TYPE
EXECUTE(OpNegative, I1)
EXECUTE(OpNegative, I2)
EXECUTE(OpNegative, I4)
EXECUTE(OpNegative, I8)
EXECUTE(OpNegative, F4)
EXECUTE(OpNegative, F8)
END_TYPE
case WfInsCode::OpConcat:
{
Value first, second;
CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
WString firstText, secondText;
first.GetTypeDescriptor()->GetSerializableType()->Serialize(first, firstText);
first.GetTypeDescriptor()->GetSerializableType()->Serialize(second, secondText);
CONTEXT_ACTION(PushValue(BoxValue(firstText + secondText)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
case WfInsCode::OpExp:
BEGIN_TYPE
EXECUTE(OpExp, F4)
EXECUTE(OpExp, F8)
END_TYPE
case WfInsCode::OpAdd:
BEGIN_TYPE
EXECUTE(OpAdd, I1)
EXECUTE(OpAdd, I2)
EXECUTE(OpAdd, I4)
EXECUTE(OpAdd, I8)
EXECUTE(OpAdd, U1)
EXECUTE(OpAdd, U2)
EXECUTE(OpAdd, U4)
EXECUTE(OpAdd, U8)
EXECUTE(OpAdd, F4)
EXECUTE(OpAdd, F8)
END_TYPE
case WfInsCode::OpSub:
BEGIN_TYPE
EXECUTE(OpSub, I1)
EXECUTE(OpSub, I2)
EXECUTE(OpSub, I4)
EXECUTE(OpSub, I8)
EXECUTE(OpSub, U1)
EXECUTE(OpSub, U2)
EXECUTE(OpSub, U4)
EXECUTE(OpSub, U8)
EXECUTE(OpSub, F4)
EXECUTE(OpSub, F8)
END_TYPE
case WfInsCode::OpMul:
BEGIN_TYPE
EXECUTE(OpMul, I1)
EXECUTE(OpMul, I2)
EXECUTE(OpMul, I4)
EXECUTE(OpMul, I8)
EXECUTE(OpMul, U1)
EXECUTE(OpMul, U2)
EXECUTE(OpMul, U4)
EXECUTE(OpMul, U8)
EXECUTE(OpMul, F4)
EXECUTE(OpMul, F8)
END_TYPE
case WfInsCode::OpDiv:
BEGIN_TYPE
EXECUTE(OpDiv, I1)
EXECUTE(OpDiv, I2)
EXECUTE(OpDiv, I4)
EXECUTE(OpDiv, I8)
EXECUTE(OpDiv, U1)
EXECUTE(OpDiv, U2)
EXECUTE(OpDiv, U4)
EXECUTE(OpDiv, U8)
EXECUTE(OpDiv, F4)
EXECUTE(OpDiv, F8)
END_TYPE
case WfInsCode::OpMod:
BEGIN_TYPE
EXECUTE(OpMod, I1)
EXECUTE(OpMod, I2)
EXECUTE(OpMod, I4)
EXECUTE(OpMod, I8)
EXECUTE(OpMod, U1)
EXECUTE(OpMod, U2)
EXECUTE(OpMod, U4)
EXECUTE(OpMod, U8)
END_TYPE
case WfInsCode::OpShl:
BEGIN_TYPE
EXECUTE(OpShl, I1)
EXECUTE(OpShl, I2)
EXECUTE(OpShl, I4)
EXECUTE(OpShl, I8)
EXECUTE(OpShl, U1)
EXECUTE(OpShl, U2)
EXECUTE(OpShl, U4)
EXECUTE(OpShl, U8)
END_TYPE
case WfInsCode::OpShr:
BEGIN_TYPE
EXECUTE(OpShr, I1)
EXECUTE(OpShr, I2)
EXECUTE(OpShr, I4)
EXECUTE(OpShr, I8)
EXECUTE(OpShr, U1)
EXECUTE(OpShr, U2)
EXECUTE(OpShr, U4)
EXECUTE(OpShr, U8)
END_TYPE
case WfInsCode::OpXor:
BEGIN_TYPE
EXECUTE(OpXor, Bool)
EXECUTE(OpXor, I1)
EXECUTE(OpXor, I2)
EXECUTE(OpXor, I4)
EXECUTE(OpXor, I8)
EXECUTE(OpXor, U1)
EXECUTE(OpXor, U2)
EXECUTE(OpXor, U4)
EXECUTE(OpXor, U8)
END_TYPE
case WfInsCode::OpAnd:
BEGIN_TYPE
EXECUTE(OpAnd_Bool, Bool)
EXECUTE(OpAnd, I1)
EXECUTE(OpAnd, I2)
EXECUTE(OpAnd, I4)
EXECUTE(OpAnd, I8)
EXECUTE(OpAnd, U1)
EXECUTE(OpAnd, U2)
EXECUTE(OpAnd, U4)
EXECUTE(OpAnd, U8)
END_TYPE
case WfInsCode::OpOr:
BEGIN_TYPE
EXECUTE(OpOr_Bool, Bool)
EXECUTE(OpOr, I1)
EXECUTE(OpOr, I2)
EXECUTE(OpOr, I4)
EXECUTE(OpOr, I8)
EXECUTE(OpOr, U1)
EXECUTE(OpOr, U2)
EXECUTE(OpOr, U4)
EXECUTE(OpOr, U8)
END_TYPE
case WfInsCode::OpLT:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
vint value = UnboxValue<vint>(operand);
CONTEXT_ACTION(PushValue(BoxValue(value < 0)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
break;
case WfInsCode::OpGT:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
vint value = UnboxValue<vint>(operand);
CONTEXT_ACTION(PushValue(BoxValue(value > 0)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
break;
case WfInsCode::OpLE:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
vint value = UnboxValue<vint>(operand);
CONTEXT_ACTION(PushValue(BoxValue(value <= 0)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
break;
case WfInsCode::OpGE:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
vint value = UnboxValue<vint>(operand);
CONTEXT_ACTION(PushValue(BoxValue(value >= 0)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
break;
case WfInsCode::OpEQ:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
vint value = UnboxValue<vint>(operand);
CONTEXT_ACTION(PushValue(BoxValue(value == 0)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
break;
case WfInsCode::OpNE:
{
Value operand;
CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
vint value = UnboxValue<vint>(operand);
CONTEXT_ACTION(PushValue(BoxValue(value != 0)), L"failed to push a value to the stack.");
return WfRuntimeExecutionAction::ExecuteInstruction;
}
break;
default:
return WfRuntimeExecutionAction::Nop;
}
}
WfRuntimeExecutionAction WfRuntimeThreadContext::Execute(IWfDebuggerCallback* callback)
{
try
{
switch (status)
{
case WfRuntimeExecutionStatus::Ready:
case WfRuntimeExecutionStatus::Executing:
{
if (stackFrames.Count() == 0)
{
INTERNAL_ERROR(L"empty stack frame.");
}
auto& stackFrame = GetCurrentStackFrame();
if (stackFrame.nextInstructionIndex < 0 || stackFrame.nextInstructionIndex >= globalContext->assembly->instructions.Count())
{
INTERNAL_ERROR(L"illegal instruction index.");
}
auto insIndex = stackFrame.nextInstructionIndex;
CALL_DEBUGGER(callback->BreakIns(globalContext->assembly.Obj(), insIndex));
stackFrame.nextInstructionIndex++;
auto& ins = globalContext->assembly->instructions[insIndex];
return ExecuteInternal(ins, stackFrame, callback);
}
break;
case WfRuntimeExecutionStatus::RaisedException:
if (trapFrames.Count() > 0)
{
auto trapFrame = GetCurrentTrapFrame();
if (trapFrame.stackFrameIndex == stackFrames.Count() - 1)
{
CONTEXT_ACTION(PopTrapFrame(0), L"failed to pop the trap frame");
GetCurrentStackFrame().nextInstructionIndex = trapFrame.instructionIndex;
status = WfRuntimeExecutionStatus::Executing;
return WfRuntimeExecutionAction::UnwrapStack;
}
else if (stackFrames.Count() > 0)
{
CONTEXT_ACTION(PopStackFrame(), L"failed to pop the stack frame.");
return WfRuntimeExecutionAction::UnwrapStack;
}
}
break;
default:;
}
return WfRuntimeExecutionAction::Nop;
}
catch (const WfRuntimeException& ex)
{
if (ex.GetInfo())
{
RaiseException(ex.GetInfo());
}
else
{
RaiseException(ex.Message(), ex.IsFatal());
}
return WfRuntimeExecutionAction::ExecuteInstruction;
}
catch (const Exception& ex)
{
RaiseException(ex.Message(), false);
return WfRuntimeExecutionAction::ExecuteInstruction;
}
}
#undef INTERNAL_ERROR
#undef CONTEXT_ACTION
#undef CALL_DEBUGGER
#undef TYPE_OF_Bool
#undef TYPE_OF_I1
#undef TYPE_OF_I2
#undef TYPE_OF_I4
#undef TYPE_OF_I8
#undef TYPE_OF_U1
#undef TYPE_OF_U2
#undef TYPE_OF_U4
#undef TYPE_OF_U8
#undef TYPE_OF_F4
#undef TYPE_OF_F8
#undef TYPE_OF_String
#undef EXECUTE
#undef BEGIN_TYPE
#undef END_TYPE
}
}
}
#endif
/***********************************************************************
.\WFRUNTIMEINSTRUCTION.CPP
***********************************************************************/
namespace vl
{
namespace workflow
{
namespace runtime
{
using namespace reflection::description;
/***********************************************************************
WfInstruction
***********************************************************************/
WfInstruction::WfInstruction()
:flagParameter(Value::Null)
, typeDescriptorParameter(0)
{
}
#define CTOR(NAME)\
WfInstruction WfInstruction::NAME()\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
return ins; \
}\
#define CTOR_VALUE(NAME)\
WfInstruction WfInstruction::NAME(const WfRuntimeValue& value)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.valueParameter = value; \
return ins; \
}\
#define CTOR_FUNCTION(NAME)\
WfInstruction WfInstruction::NAME(vint function)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.indexParameter = function; \
return ins; \
}\
#define CTOR_FUNCTION_COUNT(NAME)\
WfInstruction WfInstruction::NAME(vint function, vint count)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.indexParameter = function; \
ins.countParameter = count; \
return ins; \
}\
#define CTOR_VARIABLE(NAME)\
WfInstruction WfInstruction::NAME(vint variable)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.indexParameter = variable; \
return ins; \
}\
#define CTOR_COUNT(NAME)\
WfInstruction WfInstruction::NAME(vint count)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.countParameter = count; \
return ins; \
}\
#define CTOR_FLAG_TYPEDESCRIPTOR(NAME)\
WfInstruction WfInstruction::NAME(reflection::description::Value::ValueType flag, reflection::description::ITypeDescriptor* typeDescriptor)\
{\
CHECK_ERROR(typeDescriptor != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(Value::ValueType, ITypeDescriptor*)#Internal error, argument null.");\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.flagParameter = flag; \
ins.typeDescriptorParameter = typeDescriptor; \
return ins; \
}\
#define CTOR_PROPERTY(NAME)\
WfInstruction WfInstruction::NAME(reflection::description::IPropertyInfo* propertyInfo)\
{\
CHECK_ERROR(propertyInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(propertyInfo*)#Internal error, argument null.");\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.propertyParameter = propertyInfo; \
return ins; \
}\
#define CTOR_METHOD(NAME)\
WfInstruction WfInstruction::NAME(reflection::description::IMethodInfo* methodInfo)\
{\
CHECK_ERROR(methodInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(methodInfo*)#Internal error, argument null.");\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.methodParameter = methodInfo; \
return ins; \
}\
#define CTOR_METHOD_COUNT(NAME)\
WfInstruction WfInstruction::NAME(reflection::description::IMethodInfo* methodInfo, vint count)\
{\
CHECK_ERROR(methodInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(methodInfo*, vint)#Internal error, argument null.");\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.methodParameter = methodInfo; \
ins.countParameter = count; \
return ins; \
}\
#define CTOR_EVENT(NAME)\
WfInstruction WfInstruction::NAME(reflection::description::IEventInfo* eventInfo)\
{\
CHECK_ERROR(eventInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(IEventInfo*)#Internal error, argument null.");\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.eventParameter = eventInfo; \
return ins; \
}\
#define CTOR_EVENT_COUNT(NAME)\
WfInstruction WfInstruction::NAME(reflection::description::IEventInfo* eventInfo, vint count)\
{\
CHECK_ERROR(eventInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(IEventInfo*, vint)#Internal error, argument null.");\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.eventParameter = eventInfo; \
ins.countParameter = count; \
return ins; \
}\
#define CTOR_LABEL(NAME)\
WfInstruction WfInstruction::NAME(vint label)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.indexParameter = label; \
return ins; \
}\
#define CTOR_TYPE(NAME)\
WfInstruction WfInstruction::NAME(WfInsType type)\
{\
WfInstruction ins; \
ins.code = WfInsCode::NAME; \
ins.typeParameter = type; \
return ins; \
}\
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
}
}
}
/***********************************************************************
.\WFRUNTIMETYPEDESCRIPTOR.CPP
***********************************************************************/
namespace vl
{
namespace workflow
{
namespace typeimpl
{
using namespace reflection;
using namespace reflection::description;
using namespace collections;
using namespace runtime;
/***********************************************************************
WfMethodProxy
***********************************************************************/
WfMethodProxy::WfMethodProxy(const Value& _thisObject, IMethodInfo* _methodInfo)
:thisObject(_thisObject)
, methodInfo(_methodInfo)
{
}
WfMethodProxy::~WfMethodProxy()
{
}
Value WfMethodProxy::Invoke(Ptr<IValueReadonlyList> arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
return methodInfo->Invoke(thisObject, UnboxParameter<Array<Value>>(Value::From(arguments)).Ref());
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
/***********************************************************************
WfMethodBase
***********************************************************************/
Value WfMethodBase::CreateFunctionProxyInternal(const Value& thisObject)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
return Value::From(Ptr(new WfMethodProxy(thisObject, this)));
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
void WfMethodBase::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext)
{
globalContext = _globalContext;
}
WfMethodBase::WfMethodBase(bool isStatic)
:MethodInfoImpl(nullptr, nullptr, isStatic)
{
}
WfMethodBase::~WfMethodBase()
{
}
IMethodInfo::ICpp* WfMethodBase::GetCpp()
{
return nullptr;
}
runtime::WfRuntimeGlobalContext* WfMethodBase::GetGlobalContext()
{
return globalContext;
}
void WfMethodBase::SetReturn(Ptr<ITypeInfo> type)
{
returnInfo = type;
}
/***********************************************************************
WfStaticMethod
***********************************************************************/
Value WfStaticMethod::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto argumentArray = IValueList::Create(arguments);
return WfRuntimeLambda::Invoke(Ptr(globalContext), nullptr, functionIndex, argumentArray);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfStaticMethod::WfStaticMethod()
:WfMethodBase(true)
{
}
/***********************************************************************
WfClassConstructor
***********************************************************************/
Value WfClassConstructor::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto instance = Ptr(new WfClassInstance(GetOwnerTypeDescriptor()));
{
InvokeBaseCtor(Value::From(instance.Obj()), arguments);
}
if (returnInfo->GetDecorator() == ITypeInfo::SharedPtr)
{
return Value::From(instance);
}
else
{
return Value::From(instance.Detach());
}
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfClassConstructor::WfClassConstructor(Ptr<ITypeInfo> type)
:WfMethodBase(true)
{
SetReturn(type);
}
void WfClassConstructor::InvokeBaseCtor(const Value& thisObject, collections::Array<Value>& arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto capturedVariables = Ptr(new WfRuntimeVariableContext);
capturedVariables->variables.Resize(1);
capturedVariables->variables[0] = Value::From(thisObject.GetRawPtr());
auto argumentArray = IValueList::Create(arguments);
WfRuntimeLambda::Invoke(Ptr(globalContext), capturedVariables, functionIndex, argumentArray);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
/***********************************************************************
WfClassMethod
***********************************************************************/
Value WfClassMethod::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto capturedVariables = Ptr(new WfRuntimeVariableContext);
capturedVariables->variables.Resize(1);
capturedVariables->variables[0] = Value::From(thisObject.GetRawPtr());
auto argumentArray = IValueList::Create(arguments);
return WfRuntimeLambda::Invoke(Ptr(globalContext), capturedVariables, functionIndex, argumentArray);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfClassMethod::WfClassMethod()
:WfMethodBase(false)
{
}
/***********************************************************************
WfInterfaceConstructor
***********************************************************************/
Value WfInterfaceConstructor::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if (arguments.Count() != 1)
{
throw ArgumentCountMismtatchException(GetOwnerMethodGroup());
}
auto proxy = UnboxValue<Ptr<IValueInterfaceProxy>>(arguments[0]);
List<IMethodInfo*> baseCtors;
{
const auto& baseTypes = dynamic_cast<WfCustomType*>(GetOwnerTypeDescriptor())->GetExpandedBaseTypes();
for (vint i = 0; i < baseTypes.Count(); i++)
{
auto td = baseTypes[i];
if (td != description::GetTypeDescriptor<IDescriptable>())
{
if (auto group = td->GetConstructorGroup())
{
vint count = group->GetMethodCount();
IMethodInfo* selectedCtor = nullptr;
for (vint j = 0; j < count; j++)
{
auto ctor = group->GetMethod(j);
if (ctor->GetParameterCount() == 1)
{
auto type = ctor->GetParameter(0)->GetType();
if (type->GetDecorator() == ITypeInfo::SharedPtr && type->GetTypeDescriptor() == description::GetTypeDescriptor<IValueInterfaceProxy>())
{
selectedCtor = ctor;
break;
}
}
}
if (selectedCtor)
{
baseCtors.Add(selectedCtor);
}
else
{
throw ArgumentCountMismtatchException(group);
}
}
else
{
throw ConstructorNotExistsException(td);
}
}
}
}
auto instance = Ptr(new WfInterfaceInstance(GetOwnerTypeDescriptor(), proxy, baseCtors));
if (returnInfo->GetDecorator() == ITypeInfo::SharedPtr)
{
return Value::From(instance);
}
else
{
return Value::From(instance.Detach());
}
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfInterfaceConstructor::WfInterfaceConstructor(Ptr<ITypeInfo> type)
:WfMethodBase(true)
{
auto argumentType = TypeInfoRetriver<Ptr<IValueInterfaceProxy>>::CreateTypeInfo();
auto parameter = Ptr(new ParameterInfoImpl(this, L"proxy", argumentType));
AddParameter(parameter);
SetReturn(type);
}
/***********************************************************************
WfInterfaceMethod
***********************************************************************/
Value WfInterfaceMethod::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto instance = thisObject.GetRawPtr()->SafeAggregationCast<WfInterfaceInstance>();
return instance->GetProxy()->Invoke(this, IValueList::Create(From(arguments)));
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfInterfaceMethod::WfInterfaceMethod()
:WfMethodBase(false)
{
}
/***********************************************************************
GetInfoRecord
***********************************************************************/
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
template<typename TRecord, typename TInfo>
Ptr<TRecord> GetInfoRecord(TInfo* target, DescriptableObject* thisObject, const WString& key, bool createIfNotExist)
{
if (!thisObject)
{
throw ArgumentNullException(L"thisObject", target);
}
auto untypedValue = thisObject->GetInternalProperty(key);
auto typedValue = untypedValue.Cast<TRecord>();
if (untypedValue)
{
if (!typedValue)
{
throw ArgumentException(L"Key mismatches with the record type.", L"vl::workflow::typeimpl::GetFieldRecord", L"key");
}
}
else if(createIfNotExist)
{
typedValue = Ptr(new TRecord);
thisObject->SetInternalProperty(key, typedValue);
}
return typedValue;
}
#endif
/***********************************************************************
WfEvent
***********************************************************************/
const wchar_t* WfEvent::EventRecordInternalPropertyName = L"WfEvent::EventRecord";
Ptr<WfEvent::EventRecord> WfEvent::GetEventRecord(DescriptableObject* thisObject, bool createIfNotExist)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
return GetInfoRecord<EventRecord>(this, thisObject, EventRecordInternalPropertyName, createIfNotExist);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
Ptr<IEventHandler> WfEvent::AttachInternal(DescriptableObject* thisObject, Ptr<IValueFunctionProxy> handler)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto record = GetEventRecord(thisObject, true);
auto result = Ptr(new EventHandlerImpl(handler));
record->handlers.Add(this, result);
return result;
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
bool WfEvent::DetachInternal(DescriptableObject* thisObject, Ptr<IEventHandler> handler)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto impl = handler.Cast<EventHandlerImpl>();
if (!impl)return false;
auto record = GetEventRecord(thisObject, true);
if (record->handlers.Remove(this, impl.Obj()))
{
impl->isAttached = false;
return true;
}
return false;
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
void WfEvent::InvokeInternal(DescriptableObject* thisObject, Ptr<IValueReadonlyList> arguments)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto record = GetEventRecord(thisObject, false);
if (record)
{
vint index = record->handlers.Keys().IndexOf(this);
if (index != -1)
{
auto& values = record->handlers.GetByIndex(index);
for (auto handler : values)
{
handler->proxy->Invoke(arguments);
}
}
}
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
Ptr<ITypeInfo> WfEvent::GetHandlerTypeInternal()
{
return handlerType;
}
WfEvent::WfEvent(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
:EventInfoImpl(ownerTypeDescriptor, name)
{
}
WfEvent::~WfEvent()
{
}
IEventInfo::ICpp* WfEvent::GetCpp()
{
return nullptr;
}
void WfEvent::SetHandlerType(Ptr<ITypeInfo> typeInfo)
{
handlerType = typeInfo;
}
/***********************************************************************
WfField
***********************************************************************/
const wchar_t* WfField::FieldRecordInternalPropertyName = L"WfField::FieldRecord";
Ptr<WfField::FieldRecord> WfField::GetFieldRecord(DescriptableObject* thisObject, bool createIfNotExist)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
return GetInfoRecord<FieldRecord>(this, thisObject, FieldRecordInternalPropertyName, createIfNotExist);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
Value WfField::GetValueInternal(const Value& thisObject)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto record = GetFieldRecord(thisObject.GetRawPtr(), true);
return record->values.Get(this);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
void WfField::SetValueInternal(Value& thisObject, const Value& newValue)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto record = GetFieldRecord(thisObject.GetRawPtr(), true);
record->values.Set(this, newValue);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfField::WfField(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
:FieldInfoImpl(ownerTypeDescriptor, name, nullptr)
{
}
WfField::~WfField()
{
}
IPropertyInfo::ICpp* WfField::GetCpp()
{
return nullptr;
}
void WfField::SetReturn(Ptr<ITypeInfo> typeInfo)
{
returnInfo = typeInfo;
}
/***********************************************************************
WfStructField
***********************************************************************/
Value WfStructField::GetValueInternal(const Value& thisObject)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto structValue = thisObject.GetBoxedValue().Cast<IValueType::TypedBox<WfStructInstance>>();
if (!structValue)
{
throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
}
vint index = structValue->value.fieldValues.Keys().IndexOf(this);
if (index == -1)
{
return returnInfo->GetTypeDescriptor()->GetValueType()->CreateDefault();
}
else
{
return structValue->value.fieldValues.Values()[index];
}
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
void WfStructField::SetValueInternal(Value& thisObject, const Value& newValue)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto structValue = thisObject.GetBoxedValue().Cast<IValueType::TypedBox<WfStructInstance>>();
if (!structValue)
{
throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
}
structValue->value.fieldValues.Set(this, newValue);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfStructField::WfStructField(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
:FieldInfoImpl(ownerTypeDescriptor, name, nullptr)
{
}
WfStructField::~WfStructField()
{
}
IPropertyInfo::ICpp* WfStructField::GetCpp()
{
return nullptr;
}
void WfStructField::SetReturn(Ptr<ITypeInfo> typeInfo)
{
returnInfo = typeInfo;
}
/***********************************************************************
WfProperty
***********************************************************************/
WfProperty::WfProperty(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
:PropertyInfoImpl(ownerTypeDescriptor, name, nullptr, nullptr, nullptr)
{
}
WfProperty::~WfProperty()
{
}
void WfProperty::SetGetter(MethodInfoImpl* value)
{
getter = value;
}
void WfProperty::SetSetter(MethodInfoImpl* value)
{
setter = value;
}
void WfProperty::SetValueChangedEvent(EventInfoImpl* value)
{
valueChangedEvent = value;
}
/***********************************************************************
WfTypeInfoContent
***********************************************************************/
WfTypeInfoContent::WfTypeInfoContent(const WString& _workflowTypeName)
:workflowTypeName(_workflowTypeName)
{
typeName = workflowTypeName.Buffer();
cppFullTypeName = nullptr;
cppName = TypeInfoContent::CppType;
}
/***********************************************************************
WfCustomType
***********************************************************************/
void WfCustomType::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext, IMethodGroupInfo* group)
{
vint methodCount = group->GetMethodCount();
for (vint j = 0; j < methodCount; j++)
{
auto method = group->GetMethod(j);
if (auto methodInfo = dynamic_cast<WfMethodBase*>(method))
{
methodInfo->SetGlobalContext(globalContext);
}
}
}
void WfCustomType::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext)
{
globalContext = _globalContext;
if (auto group = GetConstructorGroup())
{
SetGlobalContext(globalContext, group);
}
vint methodGroupCount = GetMethodGroupCount();
for (vint i = 0; i < methodGroupCount; i++)
{
auto group = GetMethodGroup(i);
SetGlobalContext(globalContext, group);
}
}
void WfCustomType::LoadInternal()
{
}
WfCustomType::WfCustomType(reflection::description::TypeDescriptorFlags typeDescriptorFlags, const WString& typeName)
:WfCustomTypeBase<reflection::description::TypeDescriptorImpl>(typeDescriptorFlags, typeName)
{
}
WfCustomType::~WfCustomType()
{
}
runtime::WfRuntimeGlobalContext* WfCustomType::GetGlobalContext()
{
return globalContext;
}
const WfCustomType::TypeDescriptorList& WfCustomType::GetExpandedBaseTypes()
{
if (!baseTypeExpanded)
{
baseTypeExpanded = true;
TypeDescriptorList customTypes;
customTypes.Add(this);
for (vint i = 0; i < customTypes.Count(); i++)
{
auto td = customTypes[i];
vint count = td->GetBaseTypeDescriptorCount();
for (vint j = 0; j < count; j++)
{
auto baseTd = td->GetBaseTypeDescriptor(j);
if (dynamic_cast<WfCustomType*>(baseTd))
{
customTypes.Add(baseTd);
}
else
{
expandedBaseTypes.Add(baseTd);
}
}
}
}
return expandedBaseTypes;
}
void WfCustomType::AddBaseType(ITypeDescriptor* type)
{
TypeDescriptorImpl::AddBaseType(type);
}
void WfCustomType::AddMember(const WString& name, Ptr<WfMethodBase> value)
{
AddMethod(name, value);
}
void WfCustomType::AddMember(Ptr<WfClassConstructor> value)
{
AddConstructor(value);
}
void WfCustomType::AddMember(Ptr<WfInterfaceConstructor> value)
{
AddConstructor(value);
}
void WfCustomType::AddMember(Ptr<WfField> value)
{
AddProperty(value);
}
void WfCustomType::AddMember(Ptr<WfProperty> value)
{
AddProperty(value);
}
void WfCustomType::AddMember(Ptr<WfEvent> value)
{
AddEvent(value);
}
/***********************************************************************
WfClass
***********************************************************************/
WfClass::WfClass(const WString& typeName)
:WfCustomType(TypeDescriptorFlags::Class, typeName)
{
}
WfClass::~WfClass()
{
}
/***********************************************************************
WfInterface
***********************************************************************/
WfInterface::WfInterface(const WString& typeName)
:WfCustomType(TypeDescriptorFlags::Interface, typeName)
{
}
WfInterface::~WfInterface()
{
}
/***********************************************************************
WfStruct
***********************************************************************/
WfStruct::WfValueType::WfValueType(WfStruct* _owner)
:owner(_owner)
{
}
Value WfStruct::WfValueType::CreateDefault()
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
return Value::From(Ptr(new IValueType::TypedBox<WfStructInstance>), owner);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
IBoxedValue::CompareResult WfStruct::WfValueType::Compare(const Value& a, const Value& b)
{
return IBoxedValue::NotComparable;
}
WfStruct::WfStruct(const WString& typeName)
:WfCustomTypeBase<reflection::description::ValueTypeDescriptorBase>(TypeDescriptorFlags::Struct, typeName)
{
this->valueType = Ptr(new WfValueType(this));
}
WfStruct::~WfStruct()
{
}
vint WfStruct::GetPropertyCount()
{
this->Load();
return fields.Count();
}
IPropertyInfo* WfStruct::GetProperty(vint index)
{
this->Load();
if (index < 0 || index >= fields.Count())
{
return nullptr;
}
return fields.Values()[index].Obj();
}
bool WfStruct::IsPropertyExists(const WString& name, bool inheritable)
{
this->Load();
return fields.Keys().Contains(name);
}
IPropertyInfo* WfStruct::GetPropertyByName(const WString& name, bool inheritable)
{
this->Load();
vint index = fields.Keys().IndexOf(name);
if (index == -1) return nullptr;
return fields.Values()[index].Obj();
}
void WfStruct::AddMember(Ptr<WfStructField> value)
{
fields.Add(value->GetName(), value);
}
/***********************************************************************
WfEnum::WfEnumType
***********************************************************************/
WfEnum::WfEnumType::WfEnumType(WfEnum* _owner)
:owner(_owner)
{
}
bool WfEnum::WfEnumType::IsFlagEnum()
{
return owner->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum;
}
vint WfEnum::WfEnumType::GetItemCount()
{
return owner->enumItems.Count();
}
WString WfEnum::WfEnumType::GetItemName(vint index)
{
if (index < 0 || index >= owner->enumItems.Count())
{
return L"";
}
return owner->enumItems.Keys()[index];
}
vuint64_t WfEnum::WfEnumType::GetItemValue(vint index)
{
if (index < 0 || index >= owner->enumItems.Count())
{
return 0;
}
return owner->enumItems.Values()[index];
}
vint WfEnum::WfEnumType::IndexOfItem(WString name)
{
return owner->enumItems.Keys().IndexOf(name);
}
Value WfEnum::WfEnumType::ToEnum(vuint64_t value)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto boxedValue = Ptr(new IValueType::TypedBox<WfEnumInstance>);
boxedValue->value.value = value;
return Value::From(boxedValue, owner);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
vuint64_t WfEnum::WfEnumType::FromEnum(const Value& value)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto enumValue = value.GetBoxedValue().Cast<IValueType::TypedBox<WfEnumInstance>>();
if (!enumValue)
{
throw ArgumentTypeMismtatchException(L"enumValue", owner, Value::BoxedValue, value);
}
return enumValue->value.value;
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
/***********************************************************************
WfEnum
***********************************************************************/
WfEnum::WfValueType::WfValueType(WfEnum* _owner)
:owner(_owner)
{
}
Value WfEnum::WfValueType::CreateDefault()
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
return Value::From(Ptr(new IValueType::TypedBox<WfEnumInstance>), owner);
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
IBoxedValue::CompareResult WfEnum::WfValueType::Compare(const Value& a, const Value& b)
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
auto ea = a.GetBoxedValue().Cast<IValueType::TypedBox<WfEnumInstance>>();
if (!ea)
{
throw ArgumentTypeMismtatchException(L"ea", owner, Value::BoxedValue, a);
}
auto eb = b.GetBoxedValue().Cast<IValueType::TypedBox<WfEnumInstance>>();
if (!eb)
{
throw ArgumentTypeMismtatchException(L"eb", owner, Value::BoxedValue, b);
}
if (ea->value.value < eb->value.value) return IBoxedValue::Smaller;
if (ea->value.value > eb->value.value)return IBoxedValue::Greater;
return IBoxedValue::Equal;
#else
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
}
WfEnum::WfEnum(bool isFlags, const WString& typeName)
:WfCustomTypeBase<reflection::description::ValueTypeDescriptorBase>((isFlags ? TypeDescriptorFlags::FlagEnum : TypeDescriptorFlags::NormalEnum), typeName)
{
this->valueType = Ptr(new WfValueType(this));
this->enumType = Ptr(new WfEnumType(this));
}
WfEnum::~WfEnum()
{
}
void WfEnum::AddEnumItem(const WString& name, vuint64_t value)
{
enumItems.Add(name, value);
}
/***********************************************************************
WfClassInstance
***********************************************************************/
WfClassInstance::WfClassInstance(ITypeDescriptor* _typeDescriptor)
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
:Description<WfClassInstance>(_typeDescriptor)
#endif
{
classType = dynamic_cast<WfClass*>(_typeDescriptor);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
InitializeAggregation(classType->GetExpandedBaseTypes().Count());
#endif
}
WfClassInstance::~WfClassInstance()
{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
if (classType->destructorFunctionIndex != -1)
{
auto capturedVariables = Ptr(new WfRuntimeVariableContext);
capturedVariables->variables.Resize(1);
capturedVariables->variables[0] = Value::From(this);
auto argumentArray = IValueList::Create();
WfRuntimeLambda::Invoke(Ptr(classType->GetGlobalContext()), capturedVariables, classType->destructorFunctionIndex, argumentArray);
}
#endif
}
void WfClassInstance::InstallBaseObject(ITypeDescriptor* td, Value& value)
{
Ptr<DescriptableObject> ptr;
{
if (!(ptr = value.GetSharedPtr()))
{
ptr = Ptr(value.GetRawPtr());
}
value = Value();
}
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
vint index = classType->GetExpandedBaseTypes().IndexOf(td);
SetAggregationParent(index, ptr);
#endif
}
/***********************************************************************
WfInterfaceInstance
***********************************************************************/
WfInterfaceInstance::WfInterfaceInstance(ITypeDescriptor* _typeDescriptor, Ptr<IValueInterfaceProxy> _proxy, collections::List<IMethodInfo*>& baseCtors)
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
:Description<WfInterfaceInstance>(_typeDescriptor)
, proxy(_proxy)
#endif
{
Array<Value> arguments(1);
arguments[0] = Value::From(_proxy);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
InitializeAggregation(baseCtors.Count());
for (auto [ctor, index] : indexed(baseCtors))
{
Ptr<DescriptableObject> ptr;
{
auto value = ctor->Invoke(Value(), arguments);
if (!(ptr = value.GetSharedPtr()))
{
ptr = Ptr(value.GetRawPtr());
}
}
SetAggregationParent(index, ptr);
}
#endif
}
WfInterfaceInstance::~WfInterfaceInstance()
{
}
Ptr<IValueInterfaceProxy> WfInterfaceInstance::GetProxy()
{
return proxy;
}
/***********************************************************************
WfTypeImpl
***********************************************************************/
runtime::WfRuntimeGlobalContext* WfTypeImpl::GetGlobalContext()
{
return globalContext;
}
void WfTypeImpl::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext)
{
if (globalContext)
{
CHECK_ERROR(!_globalContext, L"vl::workflow::typeimpl::WfTypeImpl::SetGlobalContext(WfRuntimeGlobalContext*)#Only one global context is allowed to create from an assembly at the same time.");
}
else
{
CHECK_ERROR(_globalContext, L"vl::workflow::typeimpl::WfTypeImpl::SetGlobalContext(WfRuntimeGlobalContext*)#Only one global context is allowed to create from an assembly at the same time.");
}
globalContext = _globalContext;
for (auto td : classes)
{
td->SetGlobalContext(globalContext);
}
for (auto td : interfaces)
{
td->SetGlobalContext(globalContext);
}
if (globalContext)
{
GetGlobalTypeManager()->AddTypeLoader(Ptr<WfTypeImpl>(this));
}
else
{
GetGlobalTypeManager()->RemoveTypeLoader(Ptr<WfTypeImpl>(this));
}
}
void WfTypeImpl::Load(reflection::description::ITypeManager* manager)
{
for (auto td : classes)
{
if (td->GetBaseTypeDescriptorCount() == 0)
{
td->AddBaseType(description::GetTypeDescriptor<DescriptableObject>());
}
manager->SetTypeDescriptor(td->GetTypeName(), td);
}
for (auto td : interfaces)
{
if (td->GetBaseTypeDescriptorCount() == 0)
{
td->AddBaseType(description::GetTypeDescriptor<IDescriptable>());
}
manager->SetTypeDescriptor(td->GetTypeName(), td);
}
for (auto td : structs)
{
manager->SetTypeDescriptor(td->GetTypeName(), td);
}
for (auto td : enums)
{
manager->SetTypeDescriptor(td->GetTypeName(), td);
}
}
void WfTypeImpl::Unload(reflection::description::ITypeManager* manager)
{
for (auto td : classes)
{
manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
}
for (auto td : interfaces)
{
manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
}
for (auto td : structs)
{
manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
}
for (auto td : enums)
{
manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
}
}
}
}
}