mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-05 19:40:03 +08:00
5833 lines
173 KiB
C++
5833 lines
173 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
|
|
|
|
/***********************************************************************
|
|
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.Obj())
|
|
, capturedVariables(_capturedVariables)
|
|
, functionIndex(_functionIndex)
|
|
{
|
|
}
|
|
|
|
Value WfRuntimeLambda::Invoke(Ptr<reflection::description::IValueReadonlyList> arguments)
|
|
{
|
|
return Invoke(Ptr(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(Ptr(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()
|
|
{
|
|
auto debugger = GetDebuggerForCurrentThread();
|
|
return GetDebuggerCallback(debugger.Obj());
|
|
}
|
|
|
|
IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger)
|
|
{
|
|
return debugger;
|
|
}
|
|
|
|
Ptr<WfDebugger> GetDebuggerForCurrentThread()
|
|
{
|
|
if (threadDebugger.HasData())
|
|
{
|
|
return threadDebugger.Get();
|
|
}
|
|
else
|
|
{
|
|
return {};
|
|
}
|
|
}
|
|
|
|
void SetDebuggerForCurrentThread(Ptr<WfDebugger> debugger)
|
|
{
|
|
#define ERROR_PREFIX L"vl::workflow::runtime::SetDebuggerForCurrentThread(Ptr<WfDebugger>)#"
|
|
CHECK_ERROR(debugger, ERROR_PREFIX L"This function cannot be called with nullptr.");
|
|
threadDebugger.Set(debugger);
|
|
#undef ERROR_PREFIX
|
|
}
|
|
|
|
void ResetDebuggerForCurrentThread()
|
|
{
|
|
threadDebugger.Clear();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
WfRuntimeExecutionAction OPERATOR_OpCompareReference(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 result = false;
|
|
if (first.GetValueType() == Value::Null || second.GetValueType() == Value::Null)
|
|
{
|
|
result = first.GetValueType() == Value::Null && second.GetValueType() == Value::Null;
|
|
}
|
|
else if (first.GetValueType() == Value::BoxedValue || second.GetValueType() == Value::BoxedValue)
|
|
{
|
|
INTERNAL_ERROR(L"CompareReference instruction can only apply on null or pointers.");
|
|
}
|
|
else
|
|
{
|
|
result = first.GetRawPtr() == second.GetRawPtr();
|
|
}
|
|
CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
|
|
return WfRuntimeExecutionAction::ExecuteInstruction;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
WfRuntimeExecutionAction OPERATOR_OpCompareValue(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 result = first == second;
|
|
CONTEXT_ACTION(PushValue(BoxValue(result)), 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.Obj();
|
|
|
|
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:
|
|
{
|
|
return OPERATOR_OpCompareReference(*this);
|
|
}
|
|
case WfInsCode::CompareValue:
|
|
{
|
|
return OPERATOR_OpCompareValue(*this);
|
|
}
|
|
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<WfStructInstance>();
|
|
if (!structValue)
|
|
{
|
|
throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
|
|
}
|
|
vint index = structValue->fieldValues.Keys().IndexOf(this);
|
|
if (index == -1)
|
|
{
|
|
return returnInfo->GetTypeDescriptor()->GetValueType()->CreateDefault();
|
|
}
|
|
else
|
|
{
|
|
return structValue->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<WfStructInstance>();
|
|
if (!structValue)
|
|
{
|
|
throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
|
|
}
|
|
structValue->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 WfStructInstance(owner)), owner);
|
|
#else
|
|
CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
|
|
#endif
|
|
}
|
|
|
|
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 WfEnumInstance(owner));
|
|
boxedValue->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<WfEnumInstance>();
|
|
if (!enumValue)
|
|
{
|
|
throw ArgumentTypeMismtatchException(L"enumValue", owner, Value::BoxedValue, value);
|
|
}
|
|
return enumValue->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 WfEnumInstance(owner)), owner);
|
|
#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;
|
|
}
|
|
|
|
/***********************************************************************
|
|
WfStructInstance
|
|
***********************************************************************/
|
|
|
|
WfStructInstance::WfStructInstance(reflection::description::ITypeDescriptor* _typeDescriptor)
|
|
: typeDescriptor(_typeDescriptor)
|
|
{
|
|
}
|
|
|
|
PredefinedBoxableType WfStructInstance::GetBoxableType()
|
|
{
|
|
return PredefinedBoxableType::PBT_Unknown;
|
|
}
|
|
|
|
Ptr<IBoxedValue> WfStructInstance::Copy()
|
|
{
|
|
auto instance = Ptr(new WfStructInstance(typeDescriptor));
|
|
CopyFrom(instance->fieldValues, fieldValues);
|
|
return instance;
|
|
}
|
|
|
|
IBoxedValue::CompareResult WfStructInstance::ComparePrimitive(Ptr<IBoxedValue> boxedValue)
|
|
{
|
|
auto instance = boxedValue.Cast<WfStructInstance>();
|
|
if (!instance) return IBoxedValue::NotComparable;
|
|
if (typeDescriptor != instance->typeDescriptor) return IBoxedValue::NotComparable;
|
|
|
|
auto&& as = fieldValues;
|
|
auto&& bs = instance->fieldValues;
|
|
if (as.Count() == 0 && bs.Count() == 0) return IBoxedValue::Equal;
|
|
|
|
vint ai = 0;
|
|
vint bi = 0;
|
|
while (ai < as.Count() || bi < bs.Count())
|
|
{
|
|
Value af, bf;
|
|
auto ap = ai < as.Count() ? as.Keys()[ai] : nullptr;
|
|
auto bp = bi < bs.Count() ? bs.Keys()[bi] : nullptr;
|
|
auto p =
|
|
ap == nullptr ? bp :
|
|
bp == nullptr ? ap :
|
|
ap < bp ? ap : bp;
|
|
|
|
if (p == ap)
|
|
{
|
|
af = as.Values()[ai];
|
|
}
|
|
else if (p->GetReturn()->GetDecorator() == ITypeInfo::TypeDescriptor)
|
|
{
|
|
af = p->GetReturn()->GetTypeDescriptor()->GetValueType()->CreateDefault();
|
|
}
|
|
|
|
if (p == bp)
|
|
{
|
|
bf = bs.Values()[bi];
|
|
}
|
|
else if (p->GetReturn()->GetDecorator() == ITypeInfo::TypeDescriptor)
|
|
{
|
|
bf = p->GetReturn()->GetTypeDescriptor()->GetValueType()->CreateDefault();
|
|
}
|
|
|
|
auto result = af <=> bf;
|
|
if constexpr (std::is_same_v<decltype(result), std::partial_ordering>)
|
|
{
|
|
if (result == std::partial_ordering::unordered) return IBoxedValue::NotComparable;
|
|
}
|
|
if (result < 0) return IBoxedValue::Smaller;
|
|
if (result > 0) return IBoxedValue::Greater;
|
|
|
|
if (p == ap) ai++;
|
|
if (p == bp) bi++;
|
|
}
|
|
|
|
return IBoxedValue::Equal;
|
|
}
|
|
|
|
/***********************************************************************
|
|
WfEnumInstance
|
|
***********************************************************************/
|
|
|
|
WfEnumInstance::WfEnumInstance(reflection::description::ITypeDescriptor* _typeDescriptor)
|
|
: typeDescriptor(_typeDescriptor)
|
|
{
|
|
}
|
|
|
|
PredefinedBoxableType WfEnumInstance::GetBoxableType()
|
|
{
|
|
return PredefinedBoxableType::PBT_Unknown;
|
|
}
|
|
|
|
Ptr<IBoxedValue> WfEnumInstance::Copy()
|
|
{
|
|
auto instance = Ptr(new WfEnumInstance(typeDescriptor));
|
|
instance->value = value;
|
|
return instance;
|
|
}
|
|
|
|
IBoxedValue::CompareResult WfEnumInstance::ComparePrimitive(Ptr<IBoxedValue> boxedValue)
|
|
{
|
|
auto instance = boxedValue.Cast<WfEnumInstance>();
|
|
if (!instance) return IBoxedValue::NotComparable;
|
|
if (typeDescriptor != instance->typeDescriptor) return IBoxedValue::NotComparable;
|
|
|
|
auto result = value <=> instance->value;
|
|
if (result < 0) return IBoxedValue::Smaller;
|
|
if (result > 0) return IBoxedValue::Greater;
|
|
return IBoxedValue::Equal;
|
|
}
|
|
|
|
/***********************************************************************
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|