/*********************************************************************** 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 _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 WfRuntimeCallStackInfo::GetVariables(collections::List& names, Ptr context, Ptr& cache) { if (!cache) { if (!context) { Dictionary map; for (auto [name, index] : indexed(names)) { map.Add(name, context->variables[index]); } cache = IValueDictionary::Create( From(map) .Select([](Pair pair) { return Pair(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 WfRuntimeCallStackInfo::GetLocalVariables() { return GetVariables(assembly->functions[functionIndex]->localVariableNames, localVariables, cachedLocalVariables); } Ptr WfRuntimeCallStackInfo::GetLocalArguments() { return GetVariables(assembly->functions[functionIndex]->argumentNames, arguments, cachedLocalArguments); } Ptr WfRuntimeCallStackInfo::GetCapturedVariables() { return GetVariables(assembly->functions[functionIndex]->capturedVariableNames, captured, cachedCapturedVariables); } Ptr WfRuntimeCallStackInfo::GetGlobalVariables() { return GetVariables(assembly->variableNames, global, cachedGlobalVariables); } WString WfRuntimeCallStackInfo::GetFunctionName() { if (!assembly) { return L""; } 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 WfRuntimeExceptionInfo::GetCallStack() { if (!cachedCallStack) { cachedCallStack = IValueList::Create( From(callStack) .Cast() .Select([](Ptr callStack) { return BoxValue(callStack); }) ); } return cachedCallStack; } /*********************************************************************** WfRuntimeThreadContext ***********************************************************************/ WfRuntimeThreadContext::WfRuntimeThreadContext(Ptr _context) :globalContext(_context) { } WfRuntimeThreadContext::WfRuntimeThreadContext(Ptr _assembly) :globalContext(new WfRuntimeGlobalContext(_assembly)) { } WfRuntimeStackFrame& WfRuntimeThreadContext::GetCurrentStackFrame() { return stackFrames[stackFrames.Count() - 1]; } WfRuntimeThreadContextError WfRuntimeThreadContext::PushStackFrame(vint functionIndex, vint argumentCount, Ptr 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 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 tdIndex; Dictionary miIndex; Dictionary piIndex; Dictionary eiIndex; WfAssemblyLoadErrors& errors; WfReaderContext(WfAssemblyLoadErrors& _errors) :errors(_errors) { } }; struct WfWriterContextPrepare { SortedList tds; SortedList mis; SortedList pis; SortedList eis; }; struct WfWriterContext { Dictionary tdIndex; Dictionary miIndex; Dictionary piIndex; Dictionary 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>; using WfWriter = Writer>; /*********************************************************************** 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& instructions, WfWriterContextPrepare& prepare) { #define TD(X) do{ if (!prepare.tds.Contains(X)) prepare.tds.Add(X); }while(0) #define MI(X) do{ if (!prepare.mis.Contains(X)) prepare.mis.Add(X); }while(0) #define PI(X) do{ if (!prepare.pis.Contains(X)) prepare.pis.Add(X); }while(0) #define EI(X) do{ if (!prepare.eis.Contains(X)) prepare.eis.Add(X); }while(0) #define COLLECTMETADATA(NAME) case WfInsCode::NAME: break; #define COLLECTMETADATA_VALUE(NAME) case WfInsCode::NAME: if (auto td = ins.valueParameter.typeDescriptor) TD(td); break; #define COLLECTMETADATA_FUNCTION(NAME) case WfInsCode::NAME: break; #define COLLECTMETADATA_FUNCTION_COUNT(NAME) case WfInsCode::NAME: break; #define COLLECTMETADATA_VARIABLE(NAME) case WfInsCode::NAME: break; #define COLLECTMETADATA_COUNT(NAME) case WfInsCode::NAME: break; #define COLLECTMETADATA_FLAG_TYPEDESCRIPTOR(NAME) case WfInsCode::NAME: TD(ins.typeDescriptorParameter); break; #define COLLECTMETADATA_PROPERTY(NAME) case WfInsCode::NAME: PI(ins.propertyParameter); break; #define COLLECTMETADATA_METHOD(NAME) case WfInsCode::NAME: MI(ins.methodParameter); break; #define COLLECTMETADATA_METHOD_COUNT(NAME) case WfInsCode::NAME: MI(ins.methodParameter); break; #define COLLECTMETADATA_EVENT(NAME) case WfInsCode::NAME: EI(ins.eventParameter); break; #define COLLECTMETADATA_EVENT_COUNT(NAME) case WfInsCode::NAME: EI(ins.eventParameter); break; #define COLLECTMETADATA_LABEL(NAME) case WfInsCode::NAME: break; #define COLLECTMETADATA_TYPE(NAME) case WfInsCode::NAME: break; for (vint i = 0; i < instructions.Count(); i++) { auto& ins = instructions[i]; switch (ins.code) { INSTRUCTION_CASES( COLLECTMETADATA, COLLECTMETADATA_VALUE, COLLECTMETADATA_FUNCTION, COLLECTMETADATA_FUNCTION_COUNT, COLLECTMETADATA_VARIABLE, COLLECTMETADATA_COUNT, COLLECTMETADATA_FLAG_TYPEDESCRIPTOR, COLLECTMETADATA_PROPERTY, COLLECTMETADATA_METHOD, COLLECTMETADATA_METHOD_COUNT, COLLECTMETADATA_EVENT, COLLECTMETADATA_EVENT_COUNT, COLLECTMETADATA_LABEL, COLLECTMETADATA_TYPE ) } } for (auto mi : prepare.mis) { CollectTd(mi, prepare); } for (auto pi : prepare.pis) { CollectTd(pi, prepare); } for (auto ei : prepare.eis) { CollectTd(ei, prepare); } #undef COLLECTMETADATA #undef COLLECTMETADATA_VALUE #undef COLLECTMETADATA_FUNCTION #undef COLLECTMETADATA_FUNCTION_COUNT #undef COLLECTMETADATA_VARIABLE #undef COLLECTMETADATA_COUNT #undef COLLECTMETADATA_FLAG_TYPEDESCRIPTOR #undef COLLECTMETADATA_PROPERTY #undef COLLECTMETADATA_METHOD #undef COLLECTMETADATA_METHOD_COUNT #undef COLLECTMETADATA_EVENT #undef COLLECTMETADATA_EVENT_COUNT #undef COLLECTMETADATA_LABEL #undef COLLECTMETADATA_TYPE #undef MI #undef TD #undef PI #undef EI } /*********************************************************************** Serizliation (Data Structures) ***********************************************************************/ BEGIN_SERIALIZATION(glr::ParsingTextPos) SERIALIZE(index) SERIALIZE(row) SERIALIZE(column) END_SERIALIZATION BEGIN_SERIALIZATION(glr::ParsingTextRange) SERIALIZE(start) SERIALIZE(end) SERIALIZE(codeIndex) END_SERIALIZATION BEGIN_SERIALIZATION(WfInstructionDebugInfo) SERIALIZE(moduleCodes) SERIALIZE(instructionCodeMapping) END_SERIALIZATION BEGIN_SERIALIZATION(WfAssemblyFunction) SERIALIZE(name) SERIALIZE(argumentNames) SERIALIZE(capturedVariableNames) SERIALIZE(localVariableNames) SERIALIZE(firstInstruction) SERIALIZE(lastInstruction) END_SERIALIZATION SERIALIZE_ENUM(WfInsCode) SERIALIZE_ENUM(WfInsType) SERIALIZE_ENUM(Value::ValueType) /*********************************************************************** Serizliation (ITypeDescriptor) ***********************************************************************/ template<> struct Serialization { 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 { static void IOType(WfReader& reader, Ptr& typeInfo) { vint decorator = 0; reader << decorator; switch (static_cast(decorator)) { case ITypeInfo::RawPtr: { Ptr elementType; IOType(reader, elementType); typeInfo = Ptr(new RawPtrTypeInfo(elementType)); } break; case ITypeInfo::SharedPtr: { Ptr elementType; IOType(reader, elementType); typeInfo = Ptr(new SharedPtrTypeInfo(elementType)); } break; case ITypeInfo::Nullable: { Ptr elementType; IOType(reader, elementType); typeInfo = Ptr(new NullableTypeInfo(elementType)); } break; case ITypeInfo::Generic: { Ptr 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 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(hint))); } break; } } static void IOType(WfWriter& writer, ITypeInfo* typeInfo) { vint decorator = static_cast(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(typeInfo->GetHint()); writer << hint; vint index = writer.context->tdIndex[typeInfo->GetTypeDescriptor()]; writer << index; } break; } } }; /*********************************************************************** Serizliation (Metadata) ***********************************************************************/ template<> struct Serialization { 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 returnType; Serialization::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 signatures; for (vint i = 0; i < count; i++) { Ptr type; Serialization::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::IOType(writer, returnType); return; } } methodFlag = 3; writer << methodFlag << count; for (vint i = 0; i < count; i++) { Serialization::IOType(writer, value->GetParameter(i)->GetType()); } } }; template<> struct Serialization { 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 { 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 { 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 { static void IOType(WfReader& reader, Ptr& typeInfo) { Serialization::IOType(reader, typeInfo); } static void IOType(WfWriter& writer, ITypeInfo* typeInfo) { Serialization::IOType(writer, typeInfo); } //---------------------------------------------------- static void IOMethodBase(WfReader& reader, WfMethodBase* info) { Ptr 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& 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& info) { Ptr 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 ctor; IOClassConstructor(reader, ctor); td->AddMember(ctor); } else { Ptr 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 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(td->GetMethodGroupByName(getterName, false)->GetMethod(0))); } if (setterName != L"") { info->SetSetter(dynamic_cast(td->GetMethodGroupByName(setterName, false)->GetMethod(0))); } if (eventName != L"") { info->SetValueChangedEvent(dynamic_cast(td->GetEventByName(eventName, false))); } td->AddMember(info); } else { Ptr 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(group->GetMethod(i)); IOClassConstructor(writer, ctor); } else { auto ctor = dynamic_cast(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(method)) { isStaticMethod = true; writer << isStaticMethod; IOStaticMethod(writer, staticMethod); } else if (isClass) { writer << isStaticMethod; IOClassMethod(writer, dynamic_cast(method)); } else { auto interfaceMethod = dynamic_cast(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(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 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 { 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 { //---------------------------------------------------- static void IOCustomType(WfReader& reader, Ptr& 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& type) { bool isFlags = type->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum; WString typeName = type->GetTypeName(); writer << isFlags << typeName; } template static void IOCustomType(WfReader& reader, Ptr& type) { WString typeName; reader << typeName; if (GetTypeDescriptor(typeName)) { reader.context->errors.duplicatedTypes.Add(typeName); } type = Ptr(new TType(typeName)); } template static void IOCustomType(WfWriter& writer, Ptr& type) { WString typeName = type->GetTypeName(); writer << typeName; } //---------------------------------------------------- template static void IOCustomTypeList(WfReader& reader, List>& types) { vint typeCount = 0; reader << typeCount; for (vint i = 0; i < typeCount; i++) { Ptr 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 static void IOCustomTypeList(WfWriter& writer, List>& 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::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::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 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(range.codeIndex, range.start.row), i); } } } /*********************************************************************** WfAssembly ***********************************************************************/ WfAssembly::WfAssembly() { } void WfAssembly::Initialize() { insBeforeCodegen->Initialize(); insAfterCodegen->Initialize(); } Ptr WfAssembly::Deserialize(stream::IStream& input, WfAssemblyLoadErrors& errors) { try { auto assembly = Ptr(new WfAssembly); stream::internal::WfReader reader(input); stream::internal::Serialization::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::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 _globalContext, Ptr _capturedVariables, vint _functionIndex) :globalContext(_globalContext) , capturedVariables(_capturedVariables) , functionIndex(_functionIndex) { } Value WfRuntimeLambda::Invoke(Ptr arguments) { return Invoke(globalContext, capturedVariables, functionIndex, arguments); } Value WfRuntimeLambda::Invoke(Ptr globalContext, Ptr capturedVariables, vint functionIndex, Ptr 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 arguments) { vint index = functions.Keys().IndexOf(methodInfo); if (index == -1) { throw WfRuntimeException( L"Internal error: failed to invoke the interface method \"" + methodInfo->GetName() + L"\" of type \"" + methodInfo->GetOwnerTypeDescriptor()->GetTypeName() + L"\"", true); } else { vint functionIndex = functions.Values()[index]; return WfRuntimeLambda::Invoke(globalContext, capturedVariables, functionIndex, arguments); } } } } } #endif /*********************************************************************** .\WFRUNTIMEDEBUGGER.CPP ***********************************************************************/ #include #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 bool WfDebugger::HandleBreakPoint(const TKey& key, collections::Dictionary& 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 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 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> threadDebugger; IWfDebuggerCallback* GetDebuggerCallback() { return GetDebuggerCallback(GetDebuggerForCurrentThread().Obj()); } IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger) { return debugger; } Ptr GetDebuggerForCurrentThread() { return threadDebugger.HasData() ? threadDebugger.Get() : nullptr; } void SetDebuggerForCurrentThread(Ptr debugger) { threadDebugger.Set(debugger); } } } } #endif /*********************************************************************** .\WFRUNTIMEEXECUTION.CPP ***********************************************************************/ #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA namespace vl { namespace workflow { namespace runtime { using namespace collections; using namespace reflection; using namespace reflection::description; using namespace typeimpl; /*********************************************************************** WfRuntimeThreadContext (Operators) ***********************************************************************/ #define INTERNAL_ERROR(MESSAGE)\ do{\ context.RaiseException(WString(L"Internal error: " MESSAGE), true);\ return WfRuntimeExecutionAction::Nop; \ } while (0)\ #define CONTEXT_ACTION(ACTION, MESSAGE)\ do{\ if ((context.ACTION) != WfRuntimeThreadContextError::Success)\ {\ INTERNAL_ERROR(MESSAGE);\ }\ } while (0)\ //------------------------------------------------------------------------------- #define UNARY_OPERATOR(NAME, OPERATOR)\ template\ WfRuntimeExecutionAction OPERATOR_##NAME(WfRuntimeThreadContext& context)\ {\ Value operand;\ CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");\ T value = OPERATOR UnboxValue(operand);\ CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");\ return WfRuntimeExecutionAction::ExecuteInstruction;\ }\ #define BINARY_OPERATOR(NAME, OPERATOR)\ template\ 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(first) OPERATOR UnboxValue(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 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(first); T secondValue = UnboxValue(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 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(first); T secondValue = UnboxValue(second); if (firstValue < secondValue) { CONTEXT_ACTION(PushValue(BoxValue((vint)-1)), L"failed to push a value to the stack."); } else if (firstValue > secondValue) { CONTEXT_ACTION(PushValue(BoxValue((vint)1)), L"failed to push a value to the stack."); } else { CONTEXT_ACTION(PushValue(BoxValue((vint)0)), L"failed to push a value to the stack."); } } } return WfRuntimeExecutionAction::ExecuteInstruction; } /*********************************************************************** WfRuntimeThreadContext (TypeConversion) ***********************************************************************/ bool OPERATOR_OpConvertToType(const Value& result, Value& converted, const WfInstruction& ins) { switch (ins.flagParameter) { case Value::Null: return false; case Value::RawPtr: if (result.GetValueType() == Value::BoxedValue) { return false; } else if (result.GetRawPtr()) { if (result.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter)) { converted = Value::From(result.GetRawPtr()); } else { return false; } } break; case Value::SharedPtr: if (result.GetValueType() == Value::BoxedValue) { return false; } else if (result.GetRawPtr()) { if (result.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter)) { converted = Value::From(Ptr(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()) { return false; } else { auto intValue = result.GetBoxedValue().Cast>()->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()) { return false; } else { auto intValue = result.GetTypeDescriptor()->GetEnumType()->FromEnum(result); converted = BoxValue(intValue); } break; default: return false; } } } return true; } /*********************************************************************** WfRuntimeThreadContext (Range) ***********************************************************************/ template 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(first); T secondValue = UnboxValue(second); auto enumerable = Ptr(new WfRuntimeRange(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 LoadFunction(Ptr context, const WString& name) { const auto& names = context->assembly->functionByName[name]; CHECK_ERROR(names.Count() == 1, L"vl::workflow::runtime::LoadFunction(Ptr, 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(*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 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(); auto functionIndex = UnboxValue(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(key); auto func = UnboxValue(value); proxy->functions.Add(name, func); } CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); auto capturedVariables = operand.GetSharedPtr().Cast(); proxy->capturedVariables = capturedVariables; proxy->globalContext = globalContext; Array 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""; } 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(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>(thisValue); if (!proxy) { INTERNAL_ERROR(L"failed to invoke a null function proxy."); return WfRuntimeExecutionAction::Nop; } if (auto lambda = proxy.Cast()) { if (lambda->globalContext == globalContext) { CONTEXT_ACTION(PushStackFrame(lambda->functionIndex, ins.countParameter, lambda->capturedVariables), L"failed to invoke a function."); return WfRuntimeExecutionAction::EnterStackFrame; } } List 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 list = Ptr(new ValueListWrapper*>(&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(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(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 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(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 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(ins.methodParameter)) { ctor->InvokeBaseCtor(thisValue, arguments); } else { auto instance = dynamic_cast(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>(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>(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()) { RaiseException(info); } else if (auto ex = operand.GetSharedPtr().Cast()) { 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>(set); auto enumerator = enumerable->CreateEnumerator(); while (enumerator->Next()) { if (enumerator->GetCurrent() == element) { CONTEXT_ACTION(PushValue(BoxValue(true)), L"failed to push a value to the stack."); return WfRuntimeExecutionAction::ExecuteInstruction; } } CONTEXT_ACTION(PushValue(BoxValue(false)), L"failed to push a value to the stack."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CompareLiteral: BEGIN_TYPE EXECUTE(OpCompare, Bool) EXECUTE(OpCompare, I1) EXECUTE(OpCompare, I2) EXECUTE(OpCompare, I4) EXECUTE(OpCompare, I8) EXECUTE(OpCompare, U1) EXECUTE(OpCompare, U2) EXECUTE(OpCompare, U4) EXECUTE(OpCompare, U8) EXECUTE(OpCompare, F4) EXECUTE(OpCompare, F8) EXECUTE(OpCompare, String) END_TYPE case WfInsCode::CompareReference: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); bool result = first.GetValueType() != Value::BoxedValue && second.GetValueType() != Value::BoxedValue && first.GetRawPtr() == second.GetRawPtr(); CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CompareValue: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); bool result = first == second; CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::OpNot: BEGIN_TYPE EXECUTE(OpNot_Bool, Bool) EXECUTE(OpNot, I1) EXECUTE(OpNot, I2) EXECUTE(OpNot, I4) EXECUTE(OpNot, I8) EXECUTE(OpNot, U1) EXECUTE(OpNot, U2) EXECUTE(OpNot, U4) EXECUTE(OpNot, U8) END_TYPE case WfInsCode::OpPositive: BEGIN_TYPE EXECUTE(OpPositive, I1) EXECUTE(OpPositive, I2) EXECUTE(OpPositive, I4) EXECUTE(OpPositive, I8) EXECUTE(OpPositive, U1) EXECUTE(OpPositive, U2) EXECUTE(OpPositive, U4) EXECUTE(OpPositive, U8) EXECUTE(OpPositive, F4) EXECUTE(OpPositive, F8) END_TYPE case WfInsCode::OpNegative: BEGIN_TYPE EXECUTE(OpNegative, I1) EXECUTE(OpNegative, I2) EXECUTE(OpNegative, I4) EXECUTE(OpNegative, I8) EXECUTE(OpNegative, F4) EXECUTE(OpNegative, F8) END_TYPE case WfInsCode::OpConcat: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); WString firstText, secondText; first.GetTypeDescriptor()->GetSerializableType()->Serialize(first, firstText); first.GetTypeDescriptor()->GetSerializableType()->Serialize(second, secondText); CONTEXT_ACTION(PushValue(BoxValue(firstText + secondText)), L"failed to push a value to the stack."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::OpExp: BEGIN_TYPE EXECUTE(OpExp, F4) EXECUTE(OpExp, F8) END_TYPE case WfInsCode::OpAdd: BEGIN_TYPE EXECUTE(OpAdd, I1) EXECUTE(OpAdd, I2) EXECUTE(OpAdd, I4) EXECUTE(OpAdd, I8) EXECUTE(OpAdd, U1) EXECUTE(OpAdd, U2) EXECUTE(OpAdd, U4) EXECUTE(OpAdd, U8) EXECUTE(OpAdd, F4) EXECUTE(OpAdd, F8) END_TYPE case WfInsCode::OpSub: BEGIN_TYPE EXECUTE(OpSub, I1) EXECUTE(OpSub, I2) EXECUTE(OpSub, I4) EXECUTE(OpSub, I8) EXECUTE(OpSub, U1) EXECUTE(OpSub, U2) EXECUTE(OpSub, U4) EXECUTE(OpSub, U8) EXECUTE(OpSub, F4) EXECUTE(OpSub, F8) END_TYPE case WfInsCode::OpMul: BEGIN_TYPE EXECUTE(OpMul, I1) EXECUTE(OpMul, I2) EXECUTE(OpMul, I4) EXECUTE(OpMul, I8) EXECUTE(OpMul, U1) EXECUTE(OpMul, U2) EXECUTE(OpMul, U4) EXECUTE(OpMul, U8) EXECUTE(OpMul, F4) EXECUTE(OpMul, F8) END_TYPE case WfInsCode::OpDiv: BEGIN_TYPE EXECUTE(OpDiv, I1) EXECUTE(OpDiv, I2) EXECUTE(OpDiv, I4) EXECUTE(OpDiv, I8) EXECUTE(OpDiv, U1) EXECUTE(OpDiv, U2) EXECUTE(OpDiv, U4) EXECUTE(OpDiv, U8) EXECUTE(OpDiv, F4) EXECUTE(OpDiv, F8) END_TYPE case WfInsCode::OpMod: BEGIN_TYPE EXECUTE(OpMod, I1) EXECUTE(OpMod, I2) EXECUTE(OpMod, I4) EXECUTE(OpMod, I8) EXECUTE(OpMod, U1) EXECUTE(OpMod, U2) EXECUTE(OpMod, U4) EXECUTE(OpMod, U8) END_TYPE case WfInsCode::OpShl: BEGIN_TYPE EXECUTE(OpShl, I1) EXECUTE(OpShl, I2) EXECUTE(OpShl, I4) EXECUTE(OpShl, I8) EXECUTE(OpShl, U1) EXECUTE(OpShl, U2) EXECUTE(OpShl, U4) EXECUTE(OpShl, U8) END_TYPE case WfInsCode::OpShr: BEGIN_TYPE EXECUTE(OpShr, I1) EXECUTE(OpShr, I2) EXECUTE(OpShr, I4) EXECUTE(OpShr, I8) EXECUTE(OpShr, U1) EXECUTE(OpShr, U2) EXECUTE(OpShr, U4) EXECUTE(OpShr, U8) END_TYPE case WfInsCode::OpXor: BEGIN_TYPE EXECUTE(OpXor, Bool) EXECUTE(OpXor, I1) EXECUTE(OpXor, I2) EXECUTE(OpXor, I4) EXECUTE(OpXor, I8) EXECUTE(OpXor, U1) EXECUTE(OpXor, U2) EXECUTE(OpXor, U4) EXECUTE(OpXor, U8) END_TYPE case WfInsCode::OpAnd: BEGIN_TYPE EXECUTE(OpAnd_Bool, Bool) EXECUTE(OpAnd, I1) EXECUTE(OpAnd, I2) EXECUTE(OpAnd, I4) EXECUTE(OpAnd, I8) EXECUTE(OpAnd, U1) EXECUTE(OpAnd, U2) EXECUTE(OpAnd, U4) EXECUTE(OpAnd, U8) END_TYPE case WfInsCode::OpOr: BEGIN_TYPE EXECUTE(OpOr_Bool, Bool) EXECUTE(OpOr, I1) EXECUTE(OpOr, I2) EXECUTE(OpOr, I4) EXECUTE(OpOr, I8) EXECUTE(OpOr, U1) EXECUTE(OpOr, U2) EXECUTE(OpOr, U4) EXECUTE(OpOr, U8) END_TYPE case WfInsCode::OpLT: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue(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(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(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(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(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(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 arguments) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA return methodInfo->Invoke(thisObject, UnboxParameter>(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 type) { returnInfo = type; } /*********************************************************************** WfStaticMethod ***********************************************************************/ Value WfStaticMethod::InvokeInternal(const Value& thisObject, collections::Array& 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& 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 type) :WfMethodBase(true) { SetReturn(type); } void WfClassConstructor::InvokeBaseCtor(const Value& thisObject, collections::Array& 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& 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& arguments) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA if (arguments.Count() != 1) { throw ArgumentCountMismtatchException(GetOwnerMethodGroup()); } auto proxy = UnboxValue>(arguments[0]); List baseCtors; { const auto& baseTypes = dynamic_cast(GetOwnerTypeDescriptor())->GetExpandedBaseTypes(); for (vint i = 0; i < baseTypes.Count(); i++) { auto td = baseTypes[i]; if (td != description::GetTypeDescriptor()) { 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()) { 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 type) :WfMethodBase(true) { auto argumentType = TypeInfoRetriver>::CreateTypeInfo(); auto parameter = Ptr(new ParameterInfoImpl(this, L"proxy", argumentType)); AddParameter(parameter); SetReturn(type); } /*********************************************************************** WfInterfaceMethod ***********************************************************************/ Value WfInterfaceMethod::InvokeInternal(const Value& thisObject, collections::Array& arguments) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto instance = thisObject.GetRawPtr()->SafeAggregationCast(); 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 Ptr 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(); 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::GetEventRecord(DescriptableObject* thisObject, bool createIfNotExist) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA return GetInfoRecord(this, thisObject, EventRecordInternalPropertyName, createIfNotExist); #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } Ptr WfEvent::AttachInternal(DescriptableObject* thisObject, Ptr 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 handler) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto impl = handler.Cast(); 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 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 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 typeInfo) { handlerType = typeInfo; } /*********************************************************************** WfField ***********************************************************************/ const wchar_t* WfField::FieldRecordInternalPropertyName = L"WfField::FieldRecord"; Ptr WfField::GetFieldRecord(DescriptableObject* thisObject, bool createIfNotExist) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA return GetInfoRecord(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 typeInfo) { returnInfo = typeInfo; } /*********************************************************************** WfStructField ***********************************************************************/ Value WfStructField::GetValueInternal(const Value& thisObject) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto structValue = thisObject.GetBoxedValue().Cast>(); if (!structValue) { throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject); } vint index = structValue->value.fieldValues.Keys().IndexOf(this); if (index == -1) { return returnInfo->GetTypeDescriptor()->GetValueType()->CreateDefault(); } else { return structValue->value.fieldValues.Values()[index]; } #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } void WfStructField::SetValueInternal(Value& thisObject, const Value& newValue) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto structValue = thisObject.GetBoxedValue().Cast>(); if (!structValue) { throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject); } structValue->value.fieldValues.Set(this, newValue); #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } WfStructField::WfStructField(ITypeDescriptor* ownerTypeDescriptor, const WString& name) :FieldInfoImpl(ownerTypeDescriptor, name, nullptr) { } WfStructField::~WfStructField() { } IPropertyInfo::ICpp* WfStructField::GetCpp() { return nullptr; } void WfStructField::SetReturn(Ptr 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(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(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(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 value) { AddMethod(name, value); } void WfCustomType::AddMember(Ptr value) { AddConstructor(value); } void WfCustomType::AddMember(Ptr value) { AddConstructor(value); } void WfCustomType::AddMember(Ptr value) { AddProperty(value); } void WfCustomType::AddMember(Ptr value) { AddProperty(value); } void WfCustomType::AddMember(Ptr value) { AddEvent(value); } /*********************************************************************** WfClass ***********************************************************************/ WfClass::WfClass(const WString& typeName) :WfCustomType(TypeDescriptorFlags::Class, typeName) { } WfClass::~WfClass() { } /*********************************************************************** WfInterface ***********************************************************************/ WfInterface::WfInterface(const WString& typeName) :WfCustomType(TypeDescriptorFlags::Interface, typeName) { } WfInterface::~WfInterface() { } /*********************************************************************** WfStruct ***********************************************************************/ WfStruct::WfValueType::WfValueType(WfStruct* _owner) :owner(_owner) { } Value WfStruct::WfValueType::CreateDefault() { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA return Value::From(Ptr(new IValueType::TypedBox), owner); #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } IBoxedValue::CompareResult WfStruct::WfValueType::Compare(const Value& a, const Value& b) { return IBoxedValue::NotComparable; } WfStruct::WfStruct(const WString& typeName) :WfCustomTypeBase(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 value) { fields.Add(value->GetName(), value); } /*********************************************************************** WfEnum::WfEnumType ***********************************************************************/ WfEnum::WfEnumType::WfEnumType(WfEnum* _owner) :owner(_owner) { } bool WfEnum::WfEnumType::IsFlagEnum() { return owner->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum; } vint WfEnum::WfEnumType::GetItemCount() { return owner->enumItems.Count(); } WString WfEnum::WfEnumType::GetItemName(vint index) { if (index < 0 || index >= owner->enumItems.Count()) { return L""; } return owner->enumItems.Keys()[index]; } vuint64_t WfEnum::WfEnumType::GetItemValue(vint index) { if (index < 0 || index >= owner->enumItems.Count()) { return 0; } return owner->enumItems.Values()[index]; } vint WfEnum::WfEnumType::IndexOfItem(WString name) { return owner->enumItems.Keys().IndexOf(name); } Value WfEnum::WfEnumType::ToEnum(vuint64_t value) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto boxedValue = Ptr(new IValueType::TypedBox); boxedValue->value.value = value; return Value::From(boxedValue, owner); #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } vuint64_t WfEnum::WfEnumType::FromEnum(const Value& value) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto enumValue = value.GetBoxedValue().Cast>(); if (!enumValue) { throw ArgumentTypeMismtatchException(L"enumValue", owner, Value::BoxedValue, value); } return enumValue->value.value; #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } /*********************************************************************** WfEnum ***********************************************************************/ WfEnum::WfValueType::WfValueType(WfEnum* _owner) :owner(_owner) { } Value WfEnum::WfValueType::CreateDefault() { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA return Value::From(Ptr(new IValueType::TypedBox), owner); #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } IBoxedValue::CompareResult WfEnum::WfValueType::Compare(const Value& a, const Value& b) { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA auto ea = a.GetBoxedValue().Cast>(); if (!ea) { throw ArgumentTypeMismtatchException(L"ea", owner, Value::BoxedValue, a); } auto eb = b.GetBoxedValue().Cast>(); if (!eb) { throw ArgumentTypeMismtatchException(L"eb", owner, Value::BoxedValue, b); } if (ea->value.value < eb->value.value) return IBoxedValue::Smaller; if (ea->value.value > eb->value.value)return IBoxedValue::Greater; return IBoxedValue::Equal; #else CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!"); #endif } WfEnum::WfEnum(bool isFlags, const WString& typeName) :WfCustomTypeBase((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(_typeDescriptor) #endif { classType = dynamic_cast(_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 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 _proxy, collections::List& baseCtors) #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA :Description(_typeDescriptor) , proxy(_proxy) #endif { Array arguments(1); arguments[0] = Value::From(_proxy); #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA InitializeAggregation(baseCtors.Count()); for (auto [ctor, index] : indexed(baseCtors)) { Ptr ptr; { auto value = ctor->Invoke(Value(), arguments); if (!(ptr = value.GetSharedPtr())) { ptr = Ptr(value.GetRawPtr()); } } SetAggregationParent(index, ptr); } #endif } WfInterfaceInstance::~WfInterfaceInstance() { } Ptr WfInterfaceInstance::GetProxy() { return proxy; } /*********************************************************************** WfTypeImpl ***********************************************************************/ runtime::WfRuntimeGlobalContext* WfTypeImpl::GetGlobalContext() { return globalContext; } void WfTypeImpl::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext) { if (globalContext) { CHECK_ERROR(!_globalContext, L"vl::workflow::typeimpl::WfTypeImpl::SetGlobalContext(WfRuntimeGlobalContext*)#Only one global context is allowed to create from an assembly at the same time."); } else { CHECK_ERROR(_globalContext, L"vl::workflow::typeimpl::WfTypeImpl::SetGlobalContext(WfRuntimeGlobalContext*)#Only one global context is allowed to create from an assembly at the same time."); } globalContext = _globalContext; for (auto td : classes) { td->SetGlobalContext(globalContext); } for (auto td : interfaces) { td->SetGlobalContext(globalContext); } if (globalContext) { GetGlobalTypeManager()->AddTypeLoader(Ptr(this)); } else { GetGlobalTypeManager()->RemoveTypeLoader(Ptr(this)); } } void WfTypeImpl::Load(reflection::description::ITypeManager* manager) { for (auto td : classes) { if (td->GetBaseTypeDescriptorCount() == 0) { td->AddBaseType(description::GetTypeDescriptor()); } manager->SetTypeDescriptor(td->GetTypeName(), td); } for (auto td : interfaces) { if (td->GetBaseTypeDescriptorCount() == 0) { td->AddBaseType(description::GetTypeDescriptor()); } 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); } } } } }