/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppWorkflowRuntime.h"

/***********************************************************************
.\WFRUNTIME.CPP
***********************************************************************/

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA

namespace vl
{
	using namespace reflection;
	using namespace reflection::description;
	using namespace workflow::runtime;
	using namespace collections;

	namespace workflow
	{
		namespace runtime
		{

/***********************************************************************
WfRuntimeGlobalContext
***********************************************************************/

			WfRuntimeGlobalContext::WfRuntimeGlobalContext(Ptr<WfAssembly> _assembly)
				:assembly(_assembly)
			{
				globalVariables = Ptr(new WfRuntimeVariableContext);
				globalVariables->variables.Resize(assembly->variableNames.Count());
				if (assembly->typeImpl)
				{
					assembly->typeImpl->SetGlobalContext(this);
				}
			}

			WfRuntimeGlobalContext::~WfRuntimeGlobalContext()
			{
				if (assembly->typeImpl)
				{
					assembly->typeImpl->SetGlobalContext(nullptr);
				}
			}

/***********************************************************************
WfRuntimeCallStackInfo
***********************************************************************/

			Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetVariables(collections::List<WString>& names, Ptr<WfRuntimeVariableContext> context, Ptr<IValueReadonlyDictionary>& cache)
			{
				if (!cache)
				{
					if (context)
					{
						Dictionary<WString, Value> map;
						for (auto [name, index] : indexed(names))
						{
							map.Add(name, context->variables[index]);
						}
						cache = IValueDictionary::Create(
							From(map)
								.Select([](Pair<WString, Value> pair)
								{
									return Pair<Value, Value>(BoxValue(pair.key), pair.value);
								})
							);
					}
					else
					{
						cache = IValueDictionary::Create();
					}
				}
				return cache;
			}

			WfRuntimeCallStackInfo::WfRuntimeCallStackInfo()
			{
			}

			WfRuntimeCallStackInfo::WfRuntimeCallStackInfo(WfRuntimeThreadContext* context, const WfRuntimeStackFrame& stackFrame)
			{
				assembly = context->globalContext->assembly;
				functionIndex = stackFrame.functionIndex;
				instruction = stackFrame.nextInstructionIndex - 1;

				auto function = assembly->functions[functionIndex];

				if (context->globalContext->globalVariables->variables.Count() > 0)
				{
					global = context->globalContext->globalVariables;
				}

				captured = stackFrame.capturedVariables;

				if (function->argumentNames.Count() > 0)
				{
					arguments = Ptr(new WfRuntimeVariableContext);
					arguments->variables.Resize(function->argumentNames.Count());
					for (vint i = 0; i < arguments->variables.Count(); i++)
					{
						arguments->variables[i] = context->stack[stackFrame.stackBase + i];
					}
				}

				if (function->localVariableNames.Count()>0)
				{
					localVariables = Ptr(new WfRuntimeVariableContext);
					localVariables->variables.Resize(function->localVariableNames.Count());
					for (vint i = 0; i < localVariables->variables.Count(); i++)
					{
						localVariables->variables[i] = context->stack[stackFrame.stackBase + function->argumentNames.Count() + i];
					}
				}
			}

			WfRuntimeCallStackInfo::~WfRuntimeCallStackInfo()
			{
			}

			Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetLocalVariables()
			{
				return GetVariables(assembly->functions[functionIndex]->localVariableNames, localVariables, cachedLocalVariables);
			}

			Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetLocalArguments()
			{
				return GetVariables(assembly->functions[functionIndex]->argumentNames, arguments, cachedLocalArguments);
			}

			Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetCapturedVariables()
			{
				return GetVariables(assembly->functions[functionIndex]->capturedVariableNames, captured, cachedCapturedVariables);
			}

			Ptr<IValueReadonlyDictionary> WfRuntimeCallStackInfo::GetGlobalVariables()
			{
				return GetVariables(assembly->variableNames, global, cachedGlobalVariables);
			}

			WString WfRuntimeCallStackInfo::GetFunctionName()
			{
				if (!assembly)
				{
					return L"<EXTERNAL CODE>";
				}
				return assembly->functions[functionIndex]->name;
			}

			WString WfRuntimeCallStackInfo::GetSourceCodeBeforeCodegen()
			{
				if (!assembly)
				{
					return L"";
				}
				const auto& range = assembly->insBeforeCodegen->instructionCodeMapping[instruction];
				if (range.codeIndex == -1)
				{
					return L"";
				}
				return assembly->insBeforeCodegen->moduleCodes[range.codeIndex];
			}

			WString WfRuntimeCallStackInfo::GetSourceCodeAfterCodegen()
			{
				if (!assembly)
				{
					return L"";
				}
				const auto& range = assembly->insAfterCodegen->instructionCodeMapping[instruction];
				if (range.codeIndex == -1)
				{
					return L"";
				}
				return assembly->insAfterCodegen->moduleCodes[range.codeIndex];
			}

			vint WfRuntimeCallStackInfo::GetRowBeforeCodegen()
			{
				if (!assembly)
				{
					return -1;
				}
				const auto& range = assembly->insBeforeCodegen->instructionCodeMapping[instruction];
				return range.start.row;
			}

			vint WfRuntimeCallStackInfo::GetRowAfterCodegen()
			{
				if (!assembly)
				{
					return -1;
				}
				const auto& range = assembly->insAfterCodegen->instructionCodeMapping[instruction];
				return range.start.row;
			}

/***********************************************************************
WfRuntimeExceptionInfo
***********************************************************************/

			WfRuntimeExceptionInfo::WfRuntimeExceptionInfo(const WString& _message, bool _fatal)
				:message(_message)
				, fatal(_fatal)
			{
			}

			WfRuntimeExceptionInfo::~WfRuntimeExceptionInfo()
			{
			}
				
#pragma push_macro("GetMessage")
#if defined GetMessage
#undef GetMessage
#endif
			WString WfRuntimeExceptionInfo::GetMessage()
			{
				return message;
			}
#pragma pop_macro("GetMessage")

			bool WfRuntimeExceptionInfo::GetFatal()
			{
				return fatal;
			}

			Ptr<IValueReadonlyList> WfRuntimeExceptionInfo::GetCallStack()
			{
				if (!cachedCallStack)
				{
					cachedCallStack = IValueList::Create(
						From(callStack)
							.Cast<IValueCallStack>()
							.Select([](Ptr<IValueCallStack> callStack)
							{
								return BoxValue(callStack);
							})
						);
				}
				return cachedCallStack;
			}

/***********************************************************************
WfRuntimeThreadContext
***********************************************************************/

			WfRuntimeThreadContext::WfRuntimeThreadContext(Ptr<WfRuntimeGlobalContext> _context)
				:globalContext(_context)
			{
			}

			WfRuntimeThreadContext::WfRuntimeThreadContext(Ptr<WfAssembly> _assembly)
				:globalContext(new WfRuntimeGlobalContext(_assembly))
			{
			}

			WfRuntimeStackFrame& WfRuntimeThreadContext::GetCurrentStackFrame()
			{
				return stackFrames[stackFrames.Count() - 1];
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PushStackFrame(vint functionIndex, vint argumentCount, Ptr<WfRuntimeVariableContext> capturedVariables)
			{
				if (stackFrames.Count() == 0)
				{
					if (stack.Count() < argumentCount)
					{
						return WfRuntimeThreadContextError::StackCorrupted;
					}
				}
				else
				{
					auto& frame = GetCurrentStackFrame();
					if (stack.Count() - frame.freeStackBase < argumentCount)
					{
						return WfRuntimeThreadContextError::StackCorrupted;
					}
				}
				if (functionIndex < 0 || functionIndex >= globalContext->assembly->functions.Count())
				{
					return WfRuntimeThreadContextError::WrongFunctionIndex;
				}
				auto meta = globalContext->assembly->functions[functionIndex];
				if (meta->argumentNames.Count() != argumentCount)
				{
					return WfRuntimeThreadContextError::WrongArgumentCount;
				}
				if (meta->capturedVariableNames.Count() == 0)
				{
					if (capturedVariables)
					{
						return WfRuntimeThreadContextError::WrongCapturedVariableCount;
					}
				}
				else
				{
					if (!capturedVariables || capturedVariables->variables.Count() != meta->capturedVariableNames.Count())
					{
						return WfRuntimeThreadContextError::WrongCapturedVariableCount;
					}
				}

				WfRuntimeStackFrame frame;
				frame.capturedVariables = capturedVariables;
				frame.functionIndex = functionIndex;
				frame.nextInstructionIndex = globalContext->assembly->functions[functionIndex]->firstInstruction;
				frame.stackBase = stack.Count() - argumentCount;

				frame.fixedVariableCount = meta->argumentNames.Count() + meta->localVariableNames.Count();
				frame.freeStackBase = frame.stackBase + frame.fixedVariableCount;
				stackFrames.Add(frame);

				for (vint i = 0; i < meta->localVariableNames.Count(); i++)
				{
					stack.Add(Value());
				}
				if (status == WfRuntimeExecutionStatus::Finished || status == WfRuntimeExecutionStatus::FatalError)
				{
					status = WfRuntimeExecutionStatus::Ready;
				}
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PopStackFrame()
			{
				if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
				WfRuntimeStackFrame frame = GetCurrentStackFrame();
				if (trapFrames.Count() > 0)
				{
					WfRuntimeTrapFrame& trapFrame = GetCurrentTrapFrame();
					if (trapFrame.stackFrameIndex == stackFrames.Count() - 1)
					{
						return WfRuntimeThreadContextError::TrapFrameCorrupted;
					}
				}
				stackFrames.RemoveAt(stackFrames.Count() - 1);

				if (stack.Count() > frame.stackBase)
				{
					stack.RemoveRange(frame.stackBase, stack.Count() - frame.stackBase);
				}
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeTrapFrame& WfRuntimeThreadContext::GetCurrentTrapFrame()
			{
				return trapFrames[trapFrames.Count() - 1];
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PushTrapFrame(vint instructionIndex)
			{
				WfRuntimeTrapFrame frame;
				frame.stackFrameIndex = stackFrames.Count() - 1;
				frame.instructionIndex = instructionIndex;
				frame.stackPatternCount = stack.Count();
				trapFrames.Add(frame);
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PopTrapFrame(vint saveStackPatternCount)
			{
				if (trapFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyTrapFrame;
				WfRuntimeTrapFrame& frame = trapFrames[trapFrames.Count() - 1];
				if (frame.stackFrameIndex != stackFrames.Count() - 1) return WfRuntimeThreadContextError::TrapFrameCorrupted;

				vint stackPopCount = stack.Count() - frame.stackPatternCount - saveStackPatternCount;
				if (stackPopCount < 0)
				{
					return WfRuntimeThreadContextError::StackCorrupted;
				}
				else if (stackPopCount>0)
				{
					stack.RemoveRange(stack.Count() - stackPopCount, stackPopCount);
				}

				trapFrames.RemoveAt(trapFrames.Count() - 1);
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PushRuntimeValue(const WfRuntimeValue& value)
			{
				if (value.typeDescriptor)
				{
					switch (value.type)
					{
					case WfInsType::Unknown:
						return PushValue(BoxValue(value.typeDescriptor));
					case WfInsType::U8:
						CHECK_ERROR(value.typeDescriptor->GetEnumType(), L"WfRuntimeThreadContext::PushValue(const WfRuntimeValue&)#Missing typeDescriptor in WfRuntimeValue!");
						return PushValue(value.typeDescriptor->GetEnumType()->ToEnum(value.u8Value));
					default:
						CHECK_FAIL(L"WfRuntimeThreadContext::PushValue(const WfRuntimeValue&)#Unexpected type in WfRuntimeValue with typeDescriptor!");
					}
				}
				else
				{
					switch (value.type)
					{
					case WfInsType::Bool:
						return PushValue(BoxValue(value.boolValue));
					case WfInsType::I1:
						return PushValue(BoxValue(value.i1Value));
					case WfInsType::I2:
						return PushValue(BoxValue(value.i2Value));
					case WfInsType::I4:
						return PushValue(BoxValue(value.i4Value));
					case WfInsType::I8:
						return PushValue(BoxValue(value.i8Value));
					case WfInsType::U1:
						return PushValue(BoxValue(value.u1Value));
					case WfInsType::U2:
						return PushValue(BoxValue(value.u2Value));
					case WfInsType::U4:
						return PushValue(BoxValue(value.u4Value));
					case WfInsType::U8:
						return PushValue(BoxValue(value.u8Value));
					case WfInsType::F4:
						return PushValue(BoxValue(value.f4Value));
					case WfInsType::F8:
						return PushValue(BoxValue(value.f8Value));
					case WfInsType::String:
						return PushValue(BoxValue(value.stringValue));
					default:
						return PushValue(Value());
					}
				}
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PushValue(const reflection::description::Value& value)
			{
				stack.Add(value);
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::PopValue(reflection::description::Value& value)
			{
				if (stackFrames.Count() == 0)
				{
					if (stack.Count() == 0) return WfRuntimeThreadContextError::EmptyStack;
				}
				else
				{
					WfRuntimeStackFrame& frame = GetCurrentStackFrame();
					if (stack.Count() <= frame.freeStackBase) return WfRuntimeThreadContextError::StackCorrupted;
				}
				value = stack[stack.Count() - 1];
				stack.RemoveAt(stack.Count() - 1);
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::RaiseException(const WString& exception, bool fatalError, bool skipDebugger)
			{
				auto info = Ptr(new WfRuntimeExceptionInfo(exception, fatalError));
				return RaiseException(info, skipDebugger);
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::RaiseException(Ptr<WfRuntimeExceptionInfo> info, bool skipDebugger)
			{
				exceptionInfo = info;
				status = info->fatal ? WfRuntimeExecutionStatus::FatalError : WfRuntimeExecutionStatus::RaisedException;

				if (info->callStack.Count() == 0)
				{
					if (auto debugger = GetDebuggerForCurrentThread())
					{
						vint contextCount = debugger->GetThreadContexts().Count();
						for (vint i = contextCount - 1; i >= 0; i--)
						{
							auto context = debugger->GetThreadContexts()[i];
							vint stackCount = context->stackFrames.Count();
							for (vint j = stackCount - 1; j >= 0; j--)
							{
								const auto& stackFrame = context->stackFrames[j];
								info->callStack.Add(Ptr(new WfRuntimeCallStackInfo(context, stackFrame)));
							}

							if (i > 0)
							{
								info->callStack.Add(Ptr(new WfRuntimeCallStackInfo));
							}
						}

						if (!skipDebugger)
						{
							if (auto callback = GetDebuggerCallback(debugger.Obj()))
							{
								if (callback->BreakException(info))
								{
									if (!callback->WaitForContinue())
									{
										RaiseException(L"Internal error: Debugger stopped the program.", true, true);
									}
								}
							}
						}
					}
				}

				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::LoadStackValue(vint stackItemIndex, reflection::description::Value& value)
			{
				if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
				auto frame = GetCurrentStackFrame();
				if (stackItemIndex < frame.freeStackBase || stackItemIndex >= stack.Count())
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				value = stack[stackItemIndex];
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::LoadGlobalVariable(vint variableIndex, reflection::description::Value& value)
			{
				if (variableIndex < 0 || variableIndex >= globalContext->globalVariables->variables.Count())
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				value = globalContext->globalVariables->variables[variableIndex];
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::StoreGlobalVariable(vint variableIndex, const reflection::description::Value& value)
			{
				if (variableIndex < 0 || variableIndex >= globalContext->globalVariables->variables.Count())
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				globalContext->globalVariables->variables[variableIndex] = value;
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::LoadCapturedVariable(vint variableIndex, reflection::description::Value& value)
			{
				if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
				auto frame = GetCurrentStackFrame();
				if (variableIndex < 0 || variableIndex >= frame.capturedVariables->variables.Count())
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				value = frame.capturedVariables->variables[variableIndex];
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::StoreCapturedVariable(vint variableIndex, const reflection::description::Value& value)
			{
				if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
				auto frame = GetCurrentStackFrame();
				if (variableIndex < 0 || variableIndex >= frame.capturedVariables->variables.Count())
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				frame.capturedVariables->variables[variableIndex] = value;
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::LoadLocalVariable(vint variableIndex, reflection::description::Value& value)
			{
				if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
				auto frame = GetCurrentStackFrame();
				if (variableIndex < 0 || variableIndex >= frame.fixedVariableCount)
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				value = stack[frame.stackBase + variableIndex];
				return WfRuntimeThreadContextError::Success;
			}

			WfRuntimeThreadContextError WfRuntimeThreadContext::StoreLocalVariable(vint variableIndex, const reflection::description::Value& value)
			{
				if (stackFrames.Count() == 0) return WfRuntimeThreadContextError::EmptyStackFrame;
				auto frame = GetCurrentStackFrame();
				if (variableIndex < 0 || variableIndex >= frame.fixedVariableCount)
				{
					return WfRuntimeThreadContextError::WrongVariableIndex;
				}

				stack[frame.stackBase + variableIndex] = value;
				return WfRuntimeThreadContextError::Success;
			}

			void WfRuntimeThreadContext::ExecuteToEnd()
			{
				auto callback = GetDebuggerCallback();
				if (callback)
				{
					callback->EnterThreadContext(this);
				}
				while (Execute(callback) != WfRuntimeExecutionAction::Nop);
				if (callback)
				{
					callback->LeaveThreadContext(this);
				}
			}
		}
	}
}

#endif

/***********************************************************************
.\WFRUNTIMEASSEMBLY.CPP
***********************************************************************/

namespace vl
{
	using namespace reflection::description;
	using namespace workflow::runtime;
	using namespace workflow::typeimpl;
	using namespace collections;

	namespace stream
	{
		namespace internal
		{
			struct WfDeserializationException
			{
			};

			struct WfReaderContext
			{
				Dictionary<vint, ITypeDescriptor*>				tdIndex;
				Dictionary<vint, IMethodInfo*>					miIndex;
				Dictionary<vint, IPropertyInfo*>				piIndex;
				Dictionary<vint, IEventInfo*>					eiIndex;
				WfAssemblyLoadErrors&							errors;

				WfReaderContext(WfAssemblyLoadErrors& _errors)
					:errors(_errors)
				{
				}
			};

			struct WfWriterContextPrepare
			{
				SortedList<ITypeDescriptor*>					tds;
				SortedList<IMethodInfo*>						mis;
				SortedList<IPropertyInfo*>						pis;
				SortedList<IEventInfo*>							eis;
			};

			struct WfWriterContext
			{
				Dictionary<ITypeDescriptor*, vint>				tdIndex;
				Dictionary<IMethodInfo*, vint>					miIndex;
				Dictionary<IPropertyInfo*, vint>				piIndex;
				Dictionary<IEventInfo*, vint>					eiIndex;

				void Initialize(WfWriterContextPrepare& prepare)
				{
					for (auto [td, index] : indexed(prepare.tds))
					{
						tdIndex.Add(td, index);
					}
					for (auto [mi, index] : indexed(prepare.mis))
					{
						miIndex.Add(mi, index);
					}
					for (auto [pi, index] : indexed(prepare.pis))
					{
						piIndex.Add(pi, index);
					}
					for (auto [ei, index] : indexed(prepare.eis))
					{
						eiIndex.Add(ei, index);
					}
				}
			};

			using WfReader = Reader<Ptr<WfReaderContext>>;
			using WfWriter = Writer<Ptr<WfWriterContext>>;

/***********************************************************************
Serialization (Sort Keys for Deterministic Binary Serialization)
***********************************************************************/

			static WString GetMethodSortKey(IMethodInfo* mi)
			{
				auto td = mi->GetOwnerTypeDescriptor();
				auto group = mi->GetOwnerMethodGroup();
				WString name = (group == td->GetConstructorGroup()) ? WString(L"#ctor") : mi->GetName();
				WString key = td->GetTypeName() + L"::" + name + L"(";
				vint paramCount = mi->GetParameterCount();
				for (vint i = 0; i < paramCount; i++)
				{
					if (i > 0) key += L",";
					key += mi->GetParameter(i)->GetType()->GetTypeFriendlyName();
				}
				key += L")";
				return key;
			}

			static WString GetPropertySortKey(IPropertyInfo* pi)
			{
				return pi->GetOwnerTypeDescriptor()->GetTypeName() + L"::" + pi->GetName();
			}

			static WString GetEventSortKey(IEventInfo* ei)
			{
				return ei->GetOwnerTypeDescriptor()->GetTypeName() + L"::" + ei->GetName();
			}

/***********************************************************************
Serialization (CollectMetadata)
***********************************************************************/

			static void CollectTd(ITypeDescriptor* td, WfWriterContextPrepare& prepare)
			{
				if (!prepare.tds.Contains(td))
				{
					prepare.tds.Add(td);
				}
			}

			static void CollectTd(ITypeInfo* typeInfo, WfWriterContextPrepare& prepare)
			{
				switch (typeInfo->GetDecorator())
				{
				case ITypeInfo::RawPtr:
				case ITypeInfo::SharedPtr:
				case ITypeInfo::Nullable:
					CollectTd(typeInfo->GetElementType(), prepare);
					break;
				case ITypeInfo::Generic:
					{
						CollectTd(typeInfo->GetElementType(), prepare);
						vint count = typeInfo->GetGenericArgumentCount();
						for (vint i = 0; i < count; i++)
						{
							CollectTd(typeInfo->GetGenericArgument(i), prepare);
						}
					}
					break;
				case ITypeInfo::TypeDescriptor:
					CollectTd(typeInfo->GetTypeDescriptor(), prepare);
					break;
				}
			}

			static void CollectTd(IMethodInfo* info, WfWriterContextPrepare& prepare)
			{
				CollectTd(info->GetOwnerTypeDescriptor(), prepare);
				CollectTd(info->GetReturn(), prepare);
				vint count = info->GetParameterCount();
				for (vint i = 0; i < count; i++)
				{
					CollectTd(info->GetParameter(i)->GetType(), prepare);
				}
			}

			static void CollectTd(IEventInfo* info, WfWriterContextPrepare& prepare)
			{
				CollectTd(info->GetOwnerTypeDescriptor(), prepare);
				CollectTd(info->GetHandlerType(), prepare);
			}

			static void CollectTd(IPropertyInfo* info, WfWriterContextPrepare& prepare)
			{
				CollectTd(info->GetOwnerTypeDescriptor(), prepare);
				CollectTd(info->GetReturn(), prepare);
			}

			static void CollectTd(WfCustomType* td, WfWriterContextPrepare& prepare)
			{
				CollectTd((ITypeDescriptor*)td, prepare);

				vint baseCount = td->GetBaseTypeDescriptorCount();
				for (vint i = 0; i < baseCount; i++)
				{
					auto baseType = td->GetBaseTypeDescriptor(i);
					CollectTd(baseType, prepare);
				}

				if(auto group = td->GetConstructorGroup())
				{
					vint methodCount = group->GetMethodCount();
					for (vint j = 0; j < methodCount; j++)
					{
						auto method = group->GetMethod(j);
						CollectTd(method, prepare);
					}
				}

				vint methodGroupCount = td->GetMethodGroupCount();
				for (vint i = 0; i < methodGroupCount; i++)
				{
					auto group = td->GetMethodGroup(i);
					vint methodCount = group->GetMethodCount();
					for (vint j = 0; j < methodCount; j++)
					{
						auto method = group->GetMethod(j);
						CollectTd(method, prepare);
					}
				}

				vint propertyCount = td->GetPropertyCount();
				for (vint i = 0; i < propertyCount; i++)
				{
					CollectTd(td->GetProperty(i), prepare);
				}

				vint eventCount = td->GetEventCount();
				for (vint i = 0; i < eventCount; i++)
				{
					CollectTd(td->GetEvent(i), prepare);
				}
			}

			static void CollectTd(WfStruct* td, WfWriterContextPrepare& prepare)
			{
				CollectTd((ITypeDescriptor*)td, prepare);

				vint propertyCount = td->GetPropertyCount();
				for (vint i = 0; i < propertyCount; i++)
				{
					CollectTd(td->GetProperty(i), prepare);
				}
			}

			static void CollectTd(WfEnum* td, WfWriterContextPrepare& prepare)
			{
				CollectTd((ITypeDescriptor*)td, prepare);
			}

			static void CollectMetadata(WfTypeImpl* typeImpl, WfWriterContextPrepare& prepare)
			{
				for (auto td : typeImpl->classes)
				{
					CollectTd(td.Obj(), prepare);
				}
				for (auto td : typeImpl->interfaces)
				{
					CollectTd(td.Obj(), prepare);
				}
				for (auto td : typeImpl->structs)
				{
					CollectTd(td.Obj(), prepare);
				}
				for (auto td : typeImpl->enums)
				{
					CollectTd(td.Obj(), prepare);
				}
			}

			static void CollectMetadata(collections::List<WfInstruction>& instructions, WfWriterContextPrepare& prepare)
			{
#define TD(X)										do{ if (!prepare.tds.Contains(X)) prepare.tds.Add(X); }while(0)
#define MI(X)										do{ if (!prepare.mis.Contains(X)) prepare.mis.Add(X); }while(0)
#define PI(X)										do{ if (!prepare.pis.Contains(X)) prepare.pis.Add(X); }while(0)
#define EI(X)										do{ if (!prepare.eis.Contains(X)) prepare.eis.Add(X); }while(0)
#define COLLECTMETADATA(NAME)						case WfInsCode::NAME: break;
#define COLLECTMETADATA_VALUE(NAME)					case WfInsCode::NAME: if (auto td = ins.valueParameter.typeDescriptor) TD(td); break;
#define COLLECTMETADATA_FUNCTION(NAME)				case WfInsCode::NAME: break;
#define COLLECTMETADATA_FUNCTION_COUNT(NAME)		case WfInsCode::NAME: break;
#define COLLECTMETADATA_VARIABLE(NAME)				case WfInsCode::NAME: break;
#define COLLECTMETADATA_COUNT(NAME)					case WfInsCode::NAME: break;
#define COLLECTMETADATA_FLAG_TYPEDESCRIPTOR(NAME)	case WfInsCode::NAME: TD(ins.typeDescriptorParameter); break;
#define COLLECTMETADATA_PROPERTY(NAME)				case WfInsCode::NAME: PI(ins.propertyParameter); break;
#define COLLECTMETADATA_METHOD(NAME)				case WfInsCode::NAME: MI(ins.methodParameter); break;
#define COLLECTMETADATA_METHOD_COUNT(NAME)			case WfInsCode::NAME: MI(ins.methodParameter); break;
#define COLLECTMETADATA_EVENT(NAME)					case WfInsCode::NAME: EI(ins.eventParameter); break;
#define COLLECTMETADATA_EVENT_COUNT(NAME)			case WfInsCode::NAME: EI(ins.eventParameter); break;
#define COLLECTMETADATA_LABEL(NAME)					case WfInsCode::NAME: break;
#define COLLECTMETADATA_TYPE(NAME)					case WfInsCode::NAME: break;

				for (vint i = 0; i < instructions.Count(); i++)
				{
					auto& ins = instructions[i];
					switch (ins.code)
					{
						INSTRUCTION_CASES(
							COLLECTMETADATA,
							COLLECTMETADATA_VALUE,
							COLLECTMETADATA_FUNCTION,
							COLLECTMETADATA_FUNCTION_COUNT,
							COLLECTMETADATA_VARIABLE,
							COLLECTMETADATA_COUNT,
							COLLECTMETADATA_FLAG_TYPEDESCRIPTOR,
							COLLECTMETADATA_PROPERTY,
							COLLECTMETADATA_METHOD,
							COLLECTMETADATA_METHOD_COUNT,
							COLLECTMETADATA_EVENT,
							COLLECTMETADATA_EVENT_COUNT,
							COLLECTMETADATA_LABEL,
							COLLECTMETADATA_TYPE
							)
					}
				}

				for (auto mi : prepare.mis)
				{
					CollectTd(mi, prepare);
				}
				for (auto pi : prepare.pis)
				{
					CollectTd(pi, prepare);
				}
				for (auto ei : prepare.eis)
				{
					CollectTd(ei, prepare);
				}

#undef COLLECTMETADATA
#undef COLLECTMETADATA_VALUE
#undef COLLECTMETADATA_FUNCTION
#undef COLLECTMETADATA_FUNCTION_COUNT
#undef COLLECTMETADATA_VARIABLE
#undef COLLECTMETADATA_COUNT
#undef COLLECTMETADATA_FLAG_TYPEDESCRIPTOR
#undef COLLECTMETADATA_PROPERTY
#undef COLLECTMETADATA_METHOD
#undef COLLECTMETADATA_METHOD_COUNT
#undef COLLECTMETADATA_EVENT
#undef COLLECTMETADATA_EVENT_COUNT
#undef COLLECTMETADATA_LABEL
#undef COLLECTMETADATA_TYPE
#undef MI
#undef TD
#undef PI
#undef EI
			}

/***********************************************************************
Serizliation (Data Structures)
***********************************************************************/

			BEGIN_SERIALIZATION(glr::ParsingTextPos)
				SERIALIZE(index)
				SERIALIZE(row)
				SERIALIZE(column)
			END_SERIALIZATION

			BEGIN_SERIALIZATION(glr::ParsingTextRange)
				SERIALIZE(start)
				SERIALIZE(end)
				SERIALIZE(codeIndex)
			END_SERIALIZATION

			BEGIN_SERIALIZATION(WfInstructionDebugInfo)
				SERIALIZE(moduleCodes)
				SERIALIZE(instructionCodeMapping)
			END_SERIALIZATION

			BEGIN_SERIALIZATION(WfAssemblyFunction)
				SERIALIZE(name)
				SERIALIZE(argumentNames)
				SERIALIZE(capturedVariableNames)
				SERIALIZE(localVariableNames)
				SERIALIZE(firstInstruction)
				SERIALIZE(lastInstruction)
			END_SERIALIZATION

/***********************************************************************
Serizliation (ITypeDescriptor)
***********************************************************************/

			template<>
			struct Serialization<ITypeDescriptor*>
			{
				static void IO(WfReader& reader, ITypeDescriptor*& value)
				{
					WString id;
					reader << id;
					value = GetTypeDescriptor(id);
					if (!value)
					{
						reader.context->errors.unresolvedTypes.Add(id);
					}
				}
					
				static void IO(WfWriter& writer, ITypeDescriptor*& value)
				{
					WString id = value->GetTypeName();
					writer << id;
				}
			};

/***********************************************************************
Serizliation (ITypeInfo)
***********************************************************************/

			template<>
			struct Serialization<ITypeInfo>
			{
				static void IOType(WfReader& reader, Ptr<ITypeInfo>& typeInfo)
				{
					vint decorator = 0;
					reader << decorator;
					switch (static_cast<ITypeInfo::Decorator>(decorator))
					{
					case ITypeInfo::RawPtr:
						{
							Ptr<ITypeInfo> elementType;
							IOType(reader, elementType);
							typeInfo = Ptr(new RawPtrTypeInfo(elementType));
						}
						break;
					case ITypeInfo::SharedPtr:
						{
							Ptr<ITypeInfo> elementType;
							IOType(reader, elementType);
							typeInfo = Ptr(new SharedPtrTypeInfo(elementType));
						}
						break;
					case ITypeInfo::Nullable:
						{
							Ptr<ITypeInfo> elementType;
							IOType(reader, elementType);
							typeInfo = Ptr(new NullableTypeInfo(elementType));
						}
						break;
					case ITypeInfo::Generic:
						{
							Ptr<ITypeInfo> elementType;
							IOType(reader, elementType);
							auto genericType = Ptr(new GenericTypeInfo(elementType));
							typeInfo = genericType;

							vint count = 0;
							reader << count;
							for (vint i = 0; i < count; i++)
							{
								Ptr<ITypeInfo> argumentType;
								IOType(reader, argumentType);
								genericType->AddGenericArgument(argumentType);
							}
						}
						break;
					case ITypeInfo::TypeDescriptor:
						{
							vint hint = 0;
							reader << hint;

							vint index;
							reader << index;
							typeInfo = Ptr(new TypeDescriptorTypeInfo(reader.context->tdIndex[index], static_cast<TypeInfoHint>(hint)));
						}
						break;
					}
				}
					
				static void IOType(WfWriter& writer, ITypeInfo* typeInfo)
				{
					vint decorator = static_cast<vint>(typeInfo->GetDecorator());
					writer << decorator;

					switch (typeInfo->GetDecorator())
					{
					case ITypeInfo::RawPtr:
					case ITypeInfo::SharedPtr:
					case ITypeInfo::Nullable:
						IOType(writer, typeInfo->GetElementType());
						break;
					case ITypeInfo::Generic:
						{
							IOType(writer, typeInfo->GetElementType());
							vint count = typeInfo->GetGenericArgumentCount();
							writer << count;
							for (vint i = 0; i < count; i++)
							{
								IOType(writer, typeInfo->GetGenericArgument(i));
							}
						}
						break;
					case ITypeInfo::TypeDescriptor:
						{
							vint hint = static_cast<vint>(typeInfo->GetHint());
							writer << hint;

							vint index = writer.context->tdIndex[typeInfo->GetTypeDescriptor()];
							writer << index;
						}
						break;
					}
				}
			};

/***********************************************************************
Serizliation (Metadata)
***********************************************************************/

			template<>
			struct Serialization<IMethodInfo*>
			{
				static void IO(WfReader& reader, IMethodInfo*& value)
				{
					value = nullptr;
					vint typeIndex = -1;
					WString name;
					reader << typeIndex << name;
					auto type = reader.context->tdIndex[typeIndex];
					auto group = name == L"#ctor"
						? type->GetConstructorGroup()
						: type->GetMethodGroupByName(name, false);

					if (!group)
					{
						reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): *");
						return;
					}

					vint methodFlag = -1;
					reader << methodFlag;
					if (0 > methodFlag || methodFlag > 3)
					{
						reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): *");
						return;
					}

					vint methodCount = group->GetMethodCount();
					switch (methodFlag)
					{
					case 0:
						{
							if (methodCount > 1)
							{
								reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): *; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings.");
								return;
							}
							value = group->GetMethod(0);
						}
						break;
					case 1:
						{
							vint count = -1;
							reader << count;

							WString parameters;
							for (vint i = 0; i < count; i++)
							{
								if (i == 0)
								{
									parameters = L"*";
								}
								else
								{
									parameters += L", *";
								}
							}

							for (vint i = 0; i < methodCount; i++)
							{
								auto method = group->GetMethod(i);
								if (method->GetParameterCount() == count)
								{
									if (value)
									{
										reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings with the same amount of parameters.");
										return;
									}
									value = method;
								}
							}

							if (!value)
							{
								reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; A qualified method doesn't exist.");
								return;
							}
						}
						break;
					case 2:
						{
							Ptr<ITypeInfo> returnType;
							Serialization<ITypeInfo>::IOType(reader, returnType);
							auto signature = returnType->GetTypeFriendlyName();
							for (vint i = 0; i < methodCount; i++)
							{
								auto method = group->GetMethod(i);
								if (method->GetReturn()->GetTypeFriendlyName() == signature)
								{
									if (value)
									{
										reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): " + signature + L"; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings with the same return type.");
										return;
									}
									value = method;
								}
							}

							if (!value)
							{
								reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(...): " + signature + L"; A qualified method doesn't exist.");
								return;
							}
						}
						break;
					case 3:
						{
							vint count = -1;
							reader << count;
							List<WString> signatures;
							for (vint i = 0; i < count; i++)
							{
								Ptr<ITypeInfo> type;
								Serialization<ITypeInfo>::IOType(reader, type);
								signatures.Add(type->GetTypeFriendlyName());
							}

							WString parameters;
							for (vint i = 0; i < count; i++)
							{
								if (i == 0)
								{
									parameters = signatures[0];
								}
								else
								{
									parameters += L", " + signatures[i];
								}
							}

							for (vint i = 0; i < methodCount; i++)
							{
								auto method = group->GetMethod(i);
								if (method->GetParameterCount() == count)
								{
									bool found = true;
									for (vint j = 0; j < count; j++)
									{
										if (method->GetParameter(j)->GetType()->GetTypeFriendlyName() != signatures[j])
										{
											found = false;
											break;
										}
									}

									if (found)
									{
										if (value)
										{
											reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; This is caused by a change to this class. When the current assembly was compiled, this imported method didn't have overloadings with the same parameter types.");
											return;
										}
										value = method;
									}
								}
							}

							if (!value)
							{
								reader.context->errors.unresolvedMembers.Add(L"method: " + type->GetTypeName() + L"::" + name + L"(" + parameters + L"): *; A qualified method doesn't exist.");
								return;
							}
						}
						break;
					}
				}
					
				static void IO(WfWriter& writer, IMethodInfo*& value)
				{
					auto type = value->GetOwnerTypeDescriptor();
					vint typeIndex = writer.context->tdIndex[type];
					auto group = value->GetOwnerMethodGroup();
					WString name = group == type->GetConstructorGroup()
						? L"#ctor"
						: value->GetName();
					writer << typeIndex << name;

					vint methodFlag = 0;
					if (group->GetMethodCount() == 1)
					{
						writer << methodFlag;
						return;
					}

					vint count = value->GetParameterCount();
					{
						vint satisfied = 0;
						for (vint i = 0; i < group->GetMethodCount(); i++)
						{
							if (group->GetMethod(i)->GetParameterCount() == count)
							{
								satisfied++;
							}
						}

						if (satisfied == 1)
						{
							methodFlag = 1;
							writer << methodFlag << count;
							return;
						}
					}

					auto returnType = value->GetReturn();
					{
						auto signature = returnType->GetTypeFriendlyName();
						vint satisfied = 0;
						for (vint i = 0; i < group->GetMethodCount(); i++)
						{
							if (group->GetMethod(i)->GetReturn()->GetTypeFriendlyName() == signature)
							{
								satisfied++;
							}
						}

						if (satisfied == 1)
						{
							methodFlag = 2;
							writer << methodFlag;
							Serialization<ITypeInfo>::IOType(writer, returnType);
							return;
						}
					}

					methodFlag = 3;
					writer << methodFlag << count;
					for (vint i = 0; i < count; i++)
					{
						Serialization<ITypeInfo>::IOType(writer, value->GetParameter(i)->GetType());
					}
				}
			};

			template<>
			struct Serialization<IPropertyInfo*>
			{
				static void IO(WfReader& reader, IPropertyInfo*& value)
				{
					vint typeIndex = -1;
					WString name;
					reader << typeIndex << name;
					auto type = reader.context->tdIndex[typeIndex];
					value = type->GetPropertyByName(name, false);
					if (!value)
					{
						reader.context->errors.unresolvedMembers.Add(L"property: " + type->GetTypeName() + L"::" + name);
					}
				}
					
				static void IO(WfWriter& writer, IPropertyInfo*& value)
				{
					auto type = value->GetOwnerTypeDescriptor();
					vint typeIndex = writer.context->tdIndex[type];
					WString name = value->GetName();
					writer << typeIndex << name;
				}
			};

			template<>
			struct Serialization<IEventInfo*>
			{
				static void IO(WfReader& reader, IEventInfo*& value)
				{
					vint typeIndex = -1;
					WString name;
					reader << typeIndex << name;
					auto type = reader.context->tdIndex[typeIndex];
					value = type->GetEventByName(name, false);
					if (!value)
					{
						reader.context->errors.unresolvedMembers.Add(L"event: " + type->GetTypeName() + L"::" + name);
					}
				}
					
				static void IO(WfWriter& writer, IEventInfo*& value)
				{
					auto type = value->GetOwnerTypeDescriptor();
					vint typeIndex = writer.context->tdIndex[type];
					WString name = value->GetName();
					writer << typeIndex << name;
				}
			};

			template<>
			struct Serialization<WfRuntimeValue>
			{
				static void IO(WfReader& reader, WfRuntimeValue& value)
				{
					vint typeIndex = -1;
					reader << typeIndex;
					value.typeDescriptor = typeIndex == -1 ? nullptr : reader.context->tdIndex[typeIndex];
					reader << value.type;
					value.stringValue = WString();

					switch (value.type)
					{
					case WfInsType::Bool:			reader << value.boolValue; break;
					case WfInsType::I1:				{ vint64_t intValue = 0; reader << intValue; value.i1Value = (vint8_t)intValue; break; }
					case WfInsType::I2:				{ vint64_t intValue = 0; reader << intValue; value.i2Value = (vint16_t)intValue; break; }
					case WfInsType::I4:				{ vint64_t intValue = 0; reader << intValue; value.i4Value = (vint32_t)intValue; break; }
					case WfInsType::I8:				{ vint64_t intValue = 0; reader << intValue; value.i8Value = (vint64_t)intValue; break; }
					case WfInsType::U1:				{ vuint64_t intValue = 0; reader << intValue; value.u1Value = (vuint8_t)intValue; break; }
					case WfInsType::U2:				{ vuint64_t intValue = 0; reader << intValue; value.u2Value = (vuint16_t)intValue; break; }
					case WfInsType::U4:				{ vuint64_t intValue = 0; reader << intValue; value.u4Value = (vuint32_t)intValue; break; }
					case WfInsType::U8:				{ vuint64_t intValue = 0; reader << intValue; value.u8Value = (vuint64_t)intValue; break; }
					case WfInsType::F4:				reader << value.f4Value; break;
					case WfInsType::F8:				reader << value.f8Value; break;
					case WfInsType::String:			reader << value.stringValue; break;
					default:;
					}
				}
					
				static void IO(WfWriter& writer, WfRuntimeValue& value)
				{
					vint typeIndex = -1;
					if (value.typeDescriptor) typeIndex = writer.context->tdIndex[value.typeDescriptor];
					writer << typeIndex;
					writer << value.type;

					switch (value.type)
					{
					case WfInsType::Bool:			writer << value.boolValue; break;
					case WfInsType::I1:				{ vint64_t intValue = value.i1Value; writer << intValue; break; }
					case WfInsType::I2:				{ vint64_t intValue = value.i2Value; writer << intValue; break; }
					case WfInsType::I4:				{ vint64_t intValue = value.i4Value; writer << intValue; break; }
					case WfInsType::I8:				{ vint64_t intValue = value.i8Value; writer << intValue; break; }
					case WfInsType::U1:				{ vuint64_t intValue = value.u1Value; writer << intValue; break; }
					case WfInsType::U2:				{ vuint64_t intValue = value.u2Value; writer << intValue; break; }
					case WfInsType::U4:				{ vuint64_t intValue = value.u4Value; writer << intValue; break; }
					case WfInsType::U8:				{ vuint64_t intValue = value.u8Value; writer << intValue; break; }
					case WfInsType::F4:				writer << value.f4Value; break;
					case WfInsType::F8:				writer << value.f8Value; break;
					case WfInsType::String:			writer << value.stringValue; break;
					default:;
					}
				}
			};

/***********************************************************************
Serialization (TypeImpl)
***********************************************************************/

			template<>
			struct Serialization<WfTypeImpl>
			{
				static void IOType(WfReader& reader, Ptr<ITypeInfo>& typeInfo)
				{
					Serialization<ITypeInfo>::IOType(reader, typeInfo);
				}
					
				static void IOType(WfWriter& writer, ITypeInfo* typeInfo)
				{
					Serialization<ITypeInfo>::IOType(writer, typeInfo);
				}

				//----------------------------------------------------

				static void IOAttributeBag(WfReader& reader, TypeDescriptorImplBase* td, IMemberInfo* memberInfo)
				{
					vint attCount = 0;
					reader << attCount;
					for (vint i = 0; i < attCount; i++)
					{
						WString attTypeName;
						reader << attTypeName;
						auto attTd = GetTypeDescriptor(attTypeName);
						auto attInfo = Ptr(new AttributeInfoImpl(attTd));

						vint valueCount = 0;
						reader << valueCount;
						for (vint j = 0; j < valueCount; j++)
						{
							WString valueTypeName;
							WString serializedData;
							reader << valueTypeName << serializedData;
							auto valueTd = GetTypeDescriptor(valueTypeName);
							Value value;
							if (auto serializableType = valueTd->GetSerializableType())
							{
								serializableType->Deserialize(serializedData, value);
								value = Value::From(value.GetBoxedValue(), valueTd);
							}
							else
							{
								auto rawTd = GetTypeDescriptor(serializedData);
								value = BoxValue<ITypeDescriptor*>(rawTd);
							}
							attInfo->AddValue(valueTd, value);
						}

						td->RegisterAttribute(memberInfo, attInfo);
					}
				}

				static void IOAttributeBag(WfWriter& writer, IAttributeBag* bag)
				{
					vint attCount = bag->GetAttributeCount();
					writer << attCount;
					for (vint i = 0; i < attCount; i++)
					{
						auto attInfo = bag->GetAttribute(i);
						WString attTypeName = attInfo->GetAttributeType()->GetTypeName();
						writer << attTypeName;

						vint valueCount = attInfo->GetAttributeValueCount();
						writer << valueCount;
						for (vint j = 0; j < valueCount; j++)
						{
							auto valueTd = attInfo->GetAttributeValueType(j);
							auto value = attInfo->GetAttributeValue(j);
							WString valueTypeName = valueTd->GetTypeName();
							WString serializedData;
							if (auto serializableType = valueTd->GetSerializableType())
							{
								serializableType->Serialize(value, serializedData);
							}
							else
							{
								auto rawTd = UnboxValue<ITypeDescriptor*>(value);
								if (rawTd) serializedData = rawTd->GetTypeName();
							}
							writer << valueTypeName << serializedData;
						}
					}
				}

				//----------------------------------------------------

				static void IOMethodBase(WfReader& reader, WfMethodBase* info)
				{
					Ptr<ITypeInfo> type;
					IOType(reader, type);
					info->SetReturn(type);

					vint count = 0;
					reader << count;
					for (vint i = 0; i < count; i++)
					{
						WString name;
						IOType(reader, type);
						reader << name;
						info->AddParameter(Ptr(new ParameterInfoImpl(info, name, type)));
					}
				}
					
				static void IOMethodBase(WfWriter& writer, WfMethodBase* info)
				{
					IOType(writer, info->GetReturn());

					vint count = info->GetParameterCount();
					writer << count;
					for (vint i = 0; i < count; i++)
					{
						auto parameter = info->GetParameter(i);
						IOType(writer, parameter->GetType());

						WString name = parameter->GetName();
						writer << name;
					}
				}

				//----------------------------------------------------

				static void IOStaticMethod(WfReader& reader, WfStaticMethod* info)
				{
					reader << info->functionIndex;
					IOMethodBase(reader, info);
				}

				static void IOStaticMethod(WfWriter& writer, WfStaticMethod* info)
				{
					writer << info->functionIndex;
					IOMethodBase(writer, info);
				}

				//----------------------------------------------------

				static void IOClassMethod(WfReader& reader, WfClassMethod* info)
				{
					reader << info->functionIndex;
					IOMethodBase(reader, info);
				}

				static void IOClassMethod(WfWriter& writer, WfClassMethod* info)
				{
					writer << info->functionIndex;
					IOMethodBase(writer, info);
				}

				//----------------------------------------------------

				static void IOClassConstructor(WfReader& reader, Ptr<WfClassConstructor>& info)
				{
					info = Ptr(new WfClassConstructor(nullptr));
					reader << info->functionIndex;
					IOMethodBase(reader, info.Obj());
				}

				static void IOClassConstructor(WfWriter& writer, WfClassConstructor* info)
				{
					writer << info->functionIndex;
					IOMethodBase(writer, info);
				}

				//----------------------------------------------------

				static void IOInterfaceConstructor(WfReader& reader, Ptr<WfInterfaceConstructor>& info)
				{
					Ptr<ITypeInfo> type;
					IOType(reader, type);
					info = Ptr(new WfInterfaceConstructor(type));
				}

				static void IOInterfaceConstructor(WfWriter& writer, WfInterfaceConstructor* info)
				{
					IOType(writer, info->GetReturn());
				}

				//----------------------------------------------------

				static void IOInterfaceMethod(WfReader& reader, WfInterfaceMethod* info)
				{
					IOMethodBase(reader, info);
				}

				static void IOInterfaceMethod(WfWriter& writer, WfInterfaceMethod* info)
				{
					IOMethodBase(writer, info);
				}

				//----------------------------------------------------

				static void IOCustomType(WfReader& reader, WfCustomType* td, bool isClass)
				{
					// constructors
					{
						vint methodCount = 0;
						reader << methodCount;

						for (vint i = 0; i < methodCount; i++)
						{
							if (isClass)
							{
								Ptr<WfClassConstructor> ctor;
								IOClassConstructor(reader, ctor);
								td->AddMember(ctor);
							}
							else
							{
								Ptr<WfInterfaceConstructor> ctor;
								IOInterfaceConstructor(reader, ctor);
								td->AddMember(ctor);
							}
						}
					}

					// base types
					vint baseCount = 0;
					reader << baseCount;
					for (vint i = 0; i < baseCount; i++)
					{
						vint index = 0;
						reader << index;
						auto baseTd = reader.context->tdIndex[index];
						td->AddBaseType(baseTd);
					}

					// methods
					vint methodGroupCount = 0;
					reader << methodGroupCount;
					for (vint i = 0; i < methodGroupCount; i++)
					{
						vint methodCount = 0;
						WString methodName;
						reader << methodCount << methodName;
						for (vint j = 0; j < methodCount; j++)
						{
							bool isStaticMethod = false;
							reader << isStaticMethod;

							if (isStaticMethod)
							{
								auto info = Ptr(new WfStaticMethod);
								td->AddMember(methodName, info);
								IOStaticMethod(reader, info.Obj());
							}
							else if (isClass)
							{
								auto info = Ptr(new WfClassMethod);
								td->AddMember(methodName, info);
								IOClassMethod(reader, info.Obj());
							}
							else
							{
								auto info = Ptr(new WfInterfaceMethod);
								td->AddMember(methodName, info);
								IOInterfaceMethod(reader, info.Obj());
							}
						}
					}

					// events
					vint eventCount = 0;
					reader << eventCount;
					for (vint i = 0; i < eventCount; i++)
					{
						WString eventName;
						reader << eventName;

						Ptr<ITypeInfo> eventType;
						IOType(reader, eventType);

						auto info = Ptr(new WfEvent(td, eventName));
						info->SetHandlerType(eventType);
						td->AddMember(info);
					}

					// properties
					vint propertyCount = 0;
					reader << propertyCount;
					for (vint i = 0; i < propertyCount; i++)
					{
						bool isProperty = false;
						WString propName;
						reader << isProperty << propName;

						if (isProperty)
						{
							auto info = Ptr(new WfProperty(td, propName));

							WString getterName, setterName, eventName;
							reader << getterName << setterName << eventName;

							if (getterName != L"")
							{
								info->SetGetter(dynamic_cast<MethodInfoImpl*>(td->GetMethodGroupByName(getterName, false)->GetMethod(0)));
							}
							if (setterName != L"")
							{
								info->SetSetter(dynamic_cast<MethodInfoImpl*>(td->GetMethodGroupByName(setterName, false)->GetMethod(0)));
							}
							if (eventName != L"")
							{
								info->SetValueChangedEvent(dynamic_cast<EventInfoImpl*>(td->GetEventByName(eventName, false)));
							}

							td->AddMember(info);
						}
						else
						{
							Ptr<ITypeInfo> fieldType;
							IOType(reader, fieldType);

							auto info = Ptr(new WfField(td, propName));
							info->SetReturn(fieldType);
							td->AddMember(info);
						}
					}

					// attributes
					{
						// type-level attributes
						IOAttributeBag(reader, td, nullptr);

						// constructor attributes
						if (auto group = td->GetConstructorGroup())
						{
							for (vint i = 0; i < group->GetMethodCount(); i++)
							{
								IOAttributeBag(reader, td, group->GetMethod(i));
							}
						}

						// method attributes
						for (vint i = 0; i < td->GetMethodGroupCount(); i++)
						{
							auto group = td->GetMethodGroup(i);
							for (vint j = 0; j < group->GetMethodCount(); j++)
							{
								IOAttributeBag(reader, td, group->GetMethod(j));
							}
						}

						// event attributes
						for (vint i = 0; i < td->GetEventCount(); i++)
						{
							IOAttributeBag(reader, td, td->GetEvent(i));
						}

						// property attributes
						for (vint i = 0; i < td->GetPropertyCount(); i++)
						{
							IOAttributeBag(reader, td, td->GetProperty(i));
						}
					}
				}
					
				static void IOCustomType(WfWriter& writer, WfCustomType* td, bool isClass)
				{
					// constructors
					{
						vint methodCount = 0;
						if (auto group = td->GetConstructorGroup())
						{
							vint methodCount = group->GetMethodCount();
							writer << methodCount;

							for (vint i = 0; i < methodCount; i++)
							{
								if (isClass)
								{
									auto ctor = dynamic_cast<WfClassConstructor*>(group->GetMethod(i));
									IOClassConstructor(writer, ctor);
								}
								else
								{
									auto ctor = dynamic_cast<WfInterfaceConstructor*>(group->GetMethod(i));
									IOInterfaceConstructor(writer, ctor);
								}
							}
						}
						else
						{
							writer << methodCount;
						}
					}

					// base types
					vint baseCount = td->GetBaseTypeDescriptorCount();
					writer << baseCount;
					for (vint i = 0; i < baseCount; i++)
					{
						auto baseTd = td->GetBaseTypeDescriptor(i);
						vint index = writer.context->tdIndex[baseTd];
						writer << index;
					}

					// methods
					vint methodGroupCount = td->GetMethodGroupCount();
					writer << methodGroupCount;
					for (vint i = 0; i < methodGroupCount; i++)
					{
						auto group = td->GetMethodGroup(i);
						vint methodCount = group->GetMethodCount();
						WString methodName = group->GetName();
						writer << methodCount << methodName;
						for (vint j = 0; j < methodCount; j++)
						{
							auto method = group->GetMethod(j);
							bool isStaticMethod = false;

							if (auto staticMethod = dynamic_cast<WfStaticMethod*>(method))
							{
								isStaticMethod = true;
								writer << isStaticMethod;
								IOStaticMethod(writer, staticMethod);
							}
							else if (isClass)
							{
								writer << isStaticMethod;
								IOClassMethod(writer, dynamic_cast<WfClassMethod*>(method));
							}
							else
							{
								auto interfaceMethod = dynamic_cast<WfInterfaceMethod*>(method);
								writer << isStaticMethod;
								IOInterfaceMethod(writer, interfaceMethod);
							}
						}
					}

					// events
					vint eventCount = td->GetEventCount();
					writer << eventCount;
					for (vint i = 0; i < eventCount; i++)
					{
						auto info = td->GetEvent(i);
						WString eventName = info->GetName();
						writer << eventName;
						IOType(writer, info->GetHandlerType());
					}

					// properties
					vint propertyCount = td->GetPropertyCount();
					writer << propertyCount;
					for (vint i = 0; i < propertyCount; i++)
					{
						auto propInfo = td->GetProperty(i);
						bool isProperty = false;

						if (dynamic_cast<WfProperty*>(propInfo))
						{
							isProperty = true;
							WString propName = propInfo->GetName();
							writer << isProperty << propName;

							auto getterName = propInfo->GetGetter() ? propInfo->GetGetter()->GetName() : L"";
							auto setterName = propInfo->GetSetter() ? propInfo->GetSetter()->GetName() : L"";
							auto eventName = propInfo->GetValueChangedEvent() ? propInfo->GetValueChangedEvent()->GetName() : L"";
							writer << getterName << setterName << eventName;
						}
						else
						{
							isProperty = false;
							WString propName = propInfo->GetName();
							writer << isProperty << propName;
							IOType(writer, propInfo->GetReturn());
						}
					}

					// attributes
					{
						// type-level attributes
						IOAttributeBag(writer, td);

						// constructor attributes
						if (auto group = td->GetConstructorGroup())
						{
							for (vint i = 0; i < group->GetMethodCount(); i++)
							{
								IOAttributeBag(writer, group->GetMethod(i));
							}
						}

						// method attributes
						for (vint i = 0; i < td->GetMethodGroupCount(); i++)
						{
							auto group = td->GetMethodGroup(i);
							for (vint j = 0; j < group->GetMethodCount(); j++)
							{
								IOAttributeBag(writer, group->GetMethod(j));
							}
						}

						// event attributes
						for (vint i = 0; i < td->GetEventCount(); i++)
						{
							IOAttributeBag(writer, td->GetEvent(i));
						}

						// property attributes
						for (vint i = 0; i < td->GetPropertyCount(); i++)
						{
							IOAttributeBag(writer, td->GetProperty(i));
						}
					}
				}

				//----------------------------------------------------

				static void IOClass(WfReader& reader, WfClass* td)
				{
					reader << td->destructorFunctionIndex;
					IOCustomType(reader, td, true);
				}

				static void IOClass(WfWriter& writer, WfClass* td)
				{
					writer << td->destructorFunctionIndex;
					IOCustomType(writer, td, true);
				}

				//----------------------------------------------------

				static void IOInterface(WfReader& reader, WfInterface* td)
				{
					IOCustomType(reader, td, false);
				}

				static void IOInterface(WfWriter& writer, WfInterface* td)
				{
					IOCustomType(writer, td, false);
				}

				//----------------------------------------------------

				static void IOStruct(WfReader& reader, WfStruct* td)
				{
					vint count;
					reader << count;

					for (vint i = 0; i < count; i++)
					{
						WString name;
						reader << name;

						Ptr<ITypeInfo> typeInfo;
						IOType(reader, typeInfo);

						auto field = Ptr(new WfStructField(td, name));
						field->SetReturn(typeInfo);
						td->AddMember(field);
					}

					// attributes
					{
						// type-level attributes
						IOAttributeBag(reader, td, nullptr);

						// field attributes
						for (vint i = 0; i < td->GetPropertyCount(); i++)
						{
							IOAttributeBag(reader, td, td->GetProperty(i));
						}
					}
				}

				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);
					}

					// attributes
					{
						// type-level attributes
						IOAttributeBag(writer, td);

						// field attributes
						for (vint i = 0; i < td->GetPropertyCount(); i++)
						{
							IOAttributeBag(writer, td->GetProperty(i));
						}
					}
				}

				//----------------------------------------------------

				static void IOEnum(WfReader& reader, WfEnum* td)
				{
					vint count;
					reader << count;

					auto et = td->GetEnumType();
					for (vint i = 0; i < count; i++)
					{
						WString name;
						vint64_t value;
						reader << name << value;
						td->AddEnumItem(name, (vuint64_t)value);
					}
				}

				static void IOEnum(WfWriter& writer, WfEnum* td)
				{
					auto et = td->GetEnumType();

					vint count = et->GetItemCount();
					writer << count;
					
					for (vint i = 0; i < count; i++)
					{
						WString name = et->GetItemName(i);
						vint64_t value = (vint64_t)et->GetItemValue(i);
						writer << name << value;
					}
				}

				//----------------------------------------------------

				static void IO(WfReader& reader, WfTypeImpl& value)
				{
					// fill types
					for (auto td : value.classes)
					{
						IOClass(reader, td.Obj());
					}
					for (auto td : value.interfaces)
					{
						IOInterface(reader, td.Obj());
					}
					for (auto td : value.structs)
					{
						IOStruct(reader, td.Obj());
					}
					for (auto td : value.enums)
					{
						IOEnum(reader, td.Obj());
					}
				}
					
				static void IO(WfWriter& writer, WfTypeImpl& value)
				{
					// fill types
					for (auto td : value.classes)
					{
						IOClass(writer, td.Obj());
					}
					for (auto td : value.interfaces)
					{
						IOInterface(writer, td.Obj());
					}
					for (auto td : value.structs)
					{
						IOStruct(writer, td.Obj());
					}
					for (auto td : value.enums)
					{
						IOEnum(writer, td.Obj());
					}
				}
			};

/***********************************************************************
Serialization (Instruction)
***********************************************************************/

			template<>
			struct Serialization<WfInstruction>
			{
				static void IO(WfReader& reader, WfInstruction& value)
				{
					reader << value.code;
#define IO(X)								do{ reader << (X); }while(0)
#define TD(X)								do{ vint index = -1; reader << index; X = reader.context->tdIndex[index]; }while(0)
#define MI(X)								do{ vint index = -1; reader << index; X = reader.context->miIndex[index]; }while(0)
#define PI(X)								do{ vint index = -1; reader << index; X = reader.context->piIndex[index]; }while(0)
#define EI(X)								do{ vint index = -1; reader << index; X = reader.context->eiIndex[index]; }while(0)
#define STREAMIO(NAME)						case WfInsCode::NAME: break;
#define STREAMIO_VALUE(NAME)				case WfInsCode::NAME: IO(value.valueParameter); break;
#define STREAMIO_FUNCTION(NAME)				case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_FUNCTION_COUNT(NAME)		case WfInsCode::NAME: IO(value.indexParameter); IO(value.countParameter); break;
#define STREAMIO_VARIABLE(NAME)				case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_COUNT(NAME)				case WfInsCode::NAME: IO(value.countParameter); break;
#define STREAMIO_FLAG_TYPEDESCRIPTOR(NAME)	case WfInsCode::NAME: IO(value.flagParameter); TD(value.typeDescriptorParameter); break;
#define STREAMIO_PROPERTY(NAME)				case WfInsCode::NAME: PI(value.propertyParameter); break;
#define STREAMIO_METHOD(NAME)				case WfInsCode::NAME: MI(value.methodParameter); break;
#define STREAMIO_METHOD_COUNT(NAME)			case WfInsCode::NAME: MI(value.methodParameter); IO(value.countParameter); break;
#define STREAMIO_EVENT(NAME)				case WfInsCode::NAME: EI(value.eventParameter); break;
#define STREAMIO_EVENT_COUNT(NAME)			case WfInsCode::NAME: EI(value.eventParameter); IO(value.countParameter); break;
#define STREAMIO_LABEL(NAME)				case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_TYPE(NAME)					case WfInsCode::NAME: IO(value.typeParameter); break;

					switch (value.code)
					{
						INSTRUCTION_CASES(
							STREAMIO,
							STREAMIO_VALUE,
							STREAMIO_FUNCTION,
							STREAMIO_FUNCTION_COUNT,
							STREAMIO_VARIABLE,
							STREAMIO_COUNT,
							STREAMIO_FLAG_TYPEDESCRIPTOR,
							STREAMIO_PROPERTY,
							STREAMIO_METHOD,
							STREAMIO_METHOD_COUNT,
							STREAMIO_EVENT,
							STREAMIO_EVENT_COUNT,
							STREAMIO_LABEL,
							STREAMIO_TYPE)
					}

#undef STREAMIO
#undef STREAMIO_VALUE
#undef STREAMIO_FUNCTION
#undef STREAMIO_FUNCTION_COUNT
#undef STREAMIO_VARIABLE
#undef STREAMIO_COUNT
#undef STREAMIO_FLAG_TYPEDESCRIPTOR
#undef STREAMIO_PROPERTY
#undef STREAMIO_METHOD
#undef STREAMIO_METHOD_COUNT
#undef STREAMIO_EVENT
#undef STREAMIO_EVENT_COUNT
#undef STREAMIO_LABEL
#undef STREAMIO_TYPE
#undef MI
#undef TD
#undef PI
#undef EI
#undef IO
				}

				static void IO(WfWriter& writer, WfInstruction& value)
				{
					writer << value.code;
#define IO(X)								do{ writer << (X); }while(0)
#define TD(X)								do{ vint index = writer.context->tdIndex[X]; writer << index; }while(0)
#define MI(X)								do{ vint index = writer.context->miIndex[X]; writer << index; }while(0)
#define PI(X)								do{ vint index = writer.context->piIndex[X]; writer << index; }while(0)
#define EI(X)								do{ vint index = writer.context->eiIndex[X]; writer << index; }while(0)
#define STREAMIO(NAME)						case WfInsCode::NAME: break;
#define STREAMIO_VALUE(NAME)				case WfInsCode::NAME: IO(value.valueParameter); break;
#define STREAMIO_FUNCTION(NAME)				case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_FUNCTION_COUNT(NAME)		case WfInsCode::NAME: IO(value.indexParameter); IO(value.countParameter); break;
#define STREAMIO_VARIABLE(NAME)				case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_COUNT(NAME)				case WfInsCode::NAME: IO(value.countParameter); break;
#define STREAMIO_FLAG_TYPEDESCRIPTOR(NAME)	case WfInsCode::NAME: IO(value.flagParameter); TD(value.typeDescriptorParameter); break;
#define STREAMIO_PROPERTY(NAME)				case WfInsCode::NAME: PI(value.propertyParameter); break;
#define STREAMIO_METHOD(NAME)				case WfInsCode::NAME: MI(value.methodParameter); break;
#define STREAMIO_METHOD_COUNT(NAME)			case WfInsCode::NAME: MI(value.methodParameter); IO(value.countParameter); break;
#define STREAMIO_EVENT(NAME)				case WfInsCode::NAME: EI(value.eventParameter); break;
#define STREAMIO_EVENT_COUNT(NAME)			case WfInsCode::NAME: EI(value.eventParameter); IO(value.countParameter); break;
#define STREAMIO_LABEL(NAME)				case WfInsCode::NAME: IO(value.indexParameter); break;
#define STREAMIO_TYPE(NAME)					case WfInsCode::NAME: IO(value.typeParameter); break;

					switch (value.code)
					{
						INSTRUCTION_CASES(
							STREAMIO,
							STREAMIO_VALUE,
							STREAMIO_FUNCTION,
							STREAMIO_FUNCTION_COUNT,
							STREAMIO_VARIABLE,
							STREAMIO_COUNT,
							STREAMIO_FLAG_TYPEDESCRIPTOR,
							STREAMIO_PROPERTY,
							STREAMIO_METHOD,
							STREAMIO_METHOD_COUNT,
							STREAMIO_EVENT,
							STREAMIO_EVENT_COUNT,
							STREAMIO_LABEL,
							STREAMIO_TYPE)
					}

#undef STREAMIO
#undef STREAMIO_VALUE
#undef STREAMIO_FUNCTION
#undef STREAMIO_FUNCTION_COUNT
#undef STREAMIO_VARIABLE
#undef STREAMIO_COUNT
#undef STREAMIO_FLAG_TYPEDESCRIPTOR
#undef STREAMIO_PROPERTY
#undef STREAMIO_METHOD
#undef STREAMIO_METHOD_COUNT
#undef STREAMIO_EVENT
#undef STREAMIO_EVENT_COUNT
#undef STREAMIO_LABEL
#undef STREAMIO_TYPE
#undef MI
#undef TD
#undef PI
#undef EI
#undef IO
				}
			};

/***********************************************************************
Serialization (Assembly)
***********************************************************************/

			template<>
			struct Serialization<WfAssembly>
			{
				//----------------------------------------------------

				static void IOCustomType(WfReader& reader, Ptr<WfEnum>& type)
				{
					bool isFlags;
					WString typeName;
					if (GetTypeDescriptor(typeName))
					{
						reader.context->errors.duplicatedTypes.Add(typeName);
					}
					reader << isFlags << typeName;
					type = Ptr(new WfEnum(isFlags, typeName));
				}

				static void IOCustomType(WfWriter& writer, Ptr<WfEnum>& type)
				{
					bool isFlags = type->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum;
					WString typeName = type->GetTypeName();
					writer << isFlags << typeName;
				}

				template<typename TType>
				static void IOCustomType(WfReader& reader, Ptr<TType>& type)
				{
					WString typeName;
					reader << typeName;
					if (GetTypeDescriptor(typeName))
					{
						reader.context->errors.duplicatedTypes.Add(typeName);
					}
					type = Ptr(new TType(typeName));
				}

				template<typename TType>
				static void IOCustomType(WfWriter& writer, Ptr<TType>& type)
				{
					WString typeName = type->GetTypeName();
					writer << typeName;
				}

				//----------------------------------------------------

				template<typename TType>
				static void IOCustomTypeList(WfReader& reader, List<Ptr<TType>>& types)
				{
					vint typeCount = 0;
					reader << typeCount;
					for (vint i = 0; i < typeCount; i++)
					{
						Ptr<TType> type;
						IOCustomType(reader, type);
						types.Add(type);
					}

					for (vint i = 0; i < typeCount; i++)
					{
						vint index = -reader.context->tdIndex.Count() - 1;
						reader.context->tdIndex.Add(index, types[i].Obj());
					}
				}

				template<typename TType>
				static void IOCustomTypeList(WfWriter& writer, List<Ptr<TType>>& types)
				{
					vint typeCount = types.Count();
					writer << typeCount;
					for (vint i = 0; i < typeCount; i++)
					{
						auto type = types[i];
						IOCustomType(writer, type);
					}
					
					for (vint i = 0; i < typeCount; i++)
					{
						vint index = -writer.context->tdIndex.Count() - 1;
						writer.context->tdIndex.Add(types[i].Obj(), index);
					}
				}

				//----------------------------------------------------

				static void IOPrepare(WfReader& reader, WfAssembly& value, WfAssemblyLoadErrors& errors)
				{
					reader.context = Ptr(new WfReaderContext(errors));
					bool hasTypeImpl = false;
					reader << hasTypeImpl;
					if (hasTypeImpl)
					{
						value.typeImpl = Ptr(new WfTypeImpl);
						IOCustomTypeList(reader, value.typeImpl->classes);
						IOCustomTypeList(reader, value.typeImpl->interfaces);
						IOCustomTypeList(reader, value.typeImpl->structs);
						IOCustomTypeList(reader, value.typeImpl->enums);
					}

					vint tdCount = -1;
					vint miCount = -1;
					vint piCount = -1;
					vint eiCount = -1;
					reader << tdCount << miCount << piCount << eiCount;
					for (vint i = 0; i < tdCount; i++)
					{
						ITypeDescriptor* td = nullptr;
						reader << td;
						reader.context->tdIndex.Add(i, td);
					}

					if (errors.unresolvedTypes.Count() + errors.duplicatedTypes.Count() > 0)
					{
						throw WfDeserializationException();
					}

					if (hasTypeImpl)
					{
						Serialization<WfTypeImpl>::IO(reader, *value.typeImpl.Obj());
						GetGlobalTypeManager()->AddTypeLoader(value.typeImpl);
					}

					for (vint i = 0; i < miCount; i++)
					{
						IMethodInfo* mi = nullptr;
						reader << mi;
						reader.context->miIndex.Add(i, mi);
					}
					for (vint i = 0; i < piCount; i++)
					{
						IPropertyInfo* pi = nullptr;
						reader << pi;
						reader.context->piIndex.Add(i, pi);
					}
					for (vint i = 0; i < eiCount; i++)
					{
						IEventInfo* ei = nullptr;
						reader << ei;
						reader.context->eiIndex.Add(i, ei);
					}

					if (errors.unresolvedMembers.Count() > 0)
					{
						throw WfDeserializationException();
					}
				}

				static void IOPrepare(WfWriter& writer, WfAssembly& value, WfAssemblyLoadErrors&)
				{
					writer.context = Ptr(new WfWriterContext);
					bool hasTypeImpl = value.typeImpl != nullptr;
					writer << hasTypeImpl;
					if (hasTypeImpl)
					{
						IOCustomTypeList(writer, value.typeImpl->classes);
						IOCustomTypeList(writer, value.typeImpl->interfaces);
						IOCustomTypeList(writer, value.typeImpl->structs);
						IOCustomTypeList(writer, value.typeImpl->enums);
					}

					WfWriterContextPrepare prepare;
					if (hasTypeImpl)
					{
						CollectMetadata(value.typeImpl.Obj(), prepare);
					}
					CollectMetadata(value.instructions, prepare);

					// Copy collected metadata to Lists and sort deterministically by name
					// instead of using pointer-sorted SortedLists which vary between runs
					List<ITypeDescriptor*> sortedTds;
					for (auto td : prepare.tds)
					{
						if (!writer.context->tdIndex.Keys().Contains(td))
						{
							sortedTds.Add(td);
						}
					}
					if (sortedTds.Count() > 0)
					{
						Sort(&sortedTds[0], sortedTds.Count(), [](ITypeDescriptor* a, ITypeDescriptor* b)
						{
							return a->GetTypeName() <=> b->GetTypeName();
						});
					}

					List<IMethodInfo*> sortedMis;
					CopyFrom(sortedMis, prepare.mis);
					if (sortedMis.Count() > 0)
					{
						Sort(&sortedMis[0], sortedMis.Count(), [](IMethodInfo* a, IMethodInfo* b)
						{
							return GetMethodSortKey(a) <=> GetMethodSortKey(b);
						});
					}

					List<IPropertyInfo*> sortedPis;
					CopyFrom(sortedPis, prepare.pis);
					if (sortedPis.Count() > 0)
					{
						Sort(&sortedPis[0], sortedPis.Count(), [](IPropertyInfo* a, IPropertyInfo* b)
						{
							return GetPropertySortKey(a) <=> GetPropertySortKey(b);
						});
					}

					List<IEventInfo*> sortedEis;
					CopyFrom(sortedEis, prepare.eis);
					if (sortedEis.Count() > 0)
					{
						Sort(&sortedEis[0], sortedEis.Count(), [](IEventInfo* a, IEventInfo* b)
						{
							return GetEventSortKey(a) <=> GetEventSortKey(b);
						});
					}

					// Build writer context indices from deterministically-sorted lists
					for (auto [td, index] : indexed(sortedTds))
					{
						writer.context->tdIndex.Add(td, index);
					}
					for (auto [mi, index] : indexed(sortedMis))
					{
						writer.context->miIndex.Add(mi, index);
					}
					for (auto [pi, index] : indexed(sortedPis))
					{
						writer.context->piIndex.Add(pi, index);
					}
					for (auto [ei, index] : indexed(sortedEis))
					{
						writer.context->eiIndex.Add(ei, index);
					}

					vint tdCount = sortedTds.Count();
					vint miCount = sortedMis.Count();
					vint piCount = sortedPis.Count();
					vint eiCount = sortedEis.Count();
					writer << tdCount << miCount << piCount << eiCount;
					for (auto td : sortedTds)
					{
						writer << td;
					}

					if (hasTypeImpl)
					{
						Serialization<WfTypeImpl>::IO(writer, *value.typeImpl.Obj());
						GetGlobalTypeManager()->AddTypeLoader(value.typeImpl);
					}

					for (auto mi : sortedMis)
					{
						writer << mi;
					}
					for (auto pi : sortedPis)
					{
						writer << pi;
					}
					for (auto ei : sortedEis)
					{
						writer << ei;
					}
				}

				//----------------------------------------------------

				template<typename TIO>
				static void IO(TIO& io, WfAssembly& value, WfAssemblyLoadErrors& errors)
				{
					IOPrepare(io, value, errors);
					io	<< value.insBeforeCodegen
						<< value.insAfterCodegen
						<< value.variableNames
						<< value.functionByName
						<< value.functions
						<< value.instructions
						;
					if (value.typeImpl)
					{
						GetGlobalTypeManager()->RemoveTypeLoader(value.typeImpl);
					}
				}
			};
		}
	}

	namespace workflow
	{
		namespace runtime
		{

/***********************************************************************
WfInstructionDebugInfo
***********************************************************************/

			void WfInstructionDebugInfo::Initialize()
			{
				for (vint i = 0; i < instructionCodeMapping.Count(); i++)
				{
					const auto& range = instructionCodeMapping[i];
					if (range.codeIndex != -1)
					{
						codeInstructionMapping.Add(Tuple<vint, vint>(range.codeIndex, range.start.row), i);
					}
				}
			}

/***********************************************************************
WfAssembly
***********************************************************************/

			WfAssembly::WfAssembly()
			{
			}

			void WfAssembly::Initialize()
			{
				insBeforeCodegen->Initialize();
				insAfterCodegen->Initialize();
			}

			Ptr<WfAssembly> WfAssembly::Deserialize(stream::IStream& input, WfAssemblyLoadErrors& errors)
			{
				try
				{
					auto assembly = Ptr(new WfAssembly);
					stream::internal::WfReader reader(input);
					stream::internal::Serialization<WfAssembly>::IO(reader, *assembly.Obj(), errors);
					assembly->Initialize();
					return assembly;
				}
				catch (stream::internal::WfDeserializationException)
				{
					return {};
				}
			}

			void WfAssembly::Serialize(stream::IStream& output)
			{
				WfAssemblyLoadErrors dummy;
				stream::internal::WfWriter writer(output);
				stream::internal::Serialization<WfAssembly>::IO(writer, *this, dummy);
			}
		}
	}
}


/***********************************************************************
.\WFRUNTIMECONSTRUCTIONS.CPP
***********************************************************************/

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA

namespace vl
{
	namespace workflow
	{
		namespace runtime
		{
			using namespace reflection::description;
			
/***********************************************************************
WfRuntimeLambda
***********************************************************************/

			WfRuntimeLambda::WfRuntimeLambda(Ptr<WfRuntimeGlobalContext> _globalContext, Ptr<WfRuntimeVariableContext> _capturedVariables, vint _functionIndex)
				:globalContext(_globalContext.Obj())
				, capturedVariables(_capturedVariables)
				, functionIndex(_functionIndex)
			{
			}

			Value WfRuntimeLambda::Invoke(Ptr<reflection::description::IValueReadonlyList> arguments)
			{
				return Invoke(Ptr(globalContext), capturedVariables, functionIndex, arguments);
			}

			Value WfRuntimeLambda::Invoke(Ptr<WfRuntimeGlobalContext> globalContext, Ptr<WfRuntimeVariableContext> capturedVariables, vint functionIndex, Ptr<reflection::description::IValueReadonlyList> arguments)
			{
				WfRuntimeThreadContext context(globalContext);
				vint count = arguments->GetCount();
				for (vint i = 0; i < count; i++)
				{
					context.PushValue(arguments->Get(i));
				}
					
				WString message;
				if (context.PushStackFrame(functionIndex, count, capturedVariables) != WfRuntimeThreadContextError::Success)
				{
					throw WfRuntimeException(L"Internal error: failed to invoke a function.", true);
				}

				context.ExecuteToEnd();
				if (context.status != WfRuntimeExecutionStatus::Finished)
				{
					throw WfRuntimeException(context.exceptionInfo);
				}

				Value result;
				if (context.PopValue(result) != WfRuntimeThreadContextError::Success)
				{
					throw WfRuntimeException(L"Internal error: failed to pop the function result.", true);
				}
					
				return result;
			}
			
/***********************************************************************
WfRuntimeInterfaceInstance
***********************************************************************/

			WfRuntimeInterfaceInstance::~WfRuntimeInterfaceInstance()
			{
				if (destructorFunctionIndex != -1)
				{
					auto arguments = IValueList::Create();
					WfRuntimeLambda::Invoke(Ptr(globalContext), capturedVariables, destructorFunctionIndex, arguments);
				}
			}

			Value WfRuntimeInterfaceInstance::Invoke(IMethodInfo* methodInfo, Ptr<IValueReadonlyList> arguments)
			{
				vint index = functions.Keys().IndexOf(methodInfo);
				if (index == -1)
				{
					throw WfRuntimeException(
						L"Internal error: failed to invoke the interface method \"" +
						methodInfo->GetName() +
						L"\" of type \"" +
						methodInfo->GetOwnerTypeDescriptor()->GetTypeName() +
						L"\"", true);
				}
				else
				{
					vint functionIndex = functions.Values()[index];
					return WfRuntimeLambda::Invoke(Ptr(globalContext), capturedVariables, functionIndex, arguments);
				}
			}
		}
	}
}

#endif

/***********************************************************************
.\WFRUNTIMEDEBUGGER.CPP
***********************************************************************/
#include <math.h>

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA

namespace vl
{
	namespace workflow
	{
		namespace runtime
		{
			using namespace collections;
			using namespace reflection;
			using namespace reflection::description;

/***********************************************************************
IWfDebuggerCallback
***********************************************************************/

			WfBreakPoint WfBreakPoint::Ins(WfAssembly* assembly, vint instruction)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = Instruction;
				breakPoint.assembly = assembly;
				breakPoint.instruction = instruction;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Read(WfAssembly* assembly, vint variable)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = ReadGlobalVar;
				breakPoint.assembly = assembly;
				breakPoint.variable = variable;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Write(WfAssembly* assembly, vint variable)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = WriteGlobalVar;
				breakPoint.assembly = assembly;
				breakPoint.variable = variable;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Get(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = GetProperty;
				breakPoint.thisObject = thisObject;
				breakPoint.propertyInfo = propertyInfo;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Set(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = SetProperty;
				breakPoint.thisObject = thisObject;
				breakPoint.propertyInfo = propertyInfo;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Attach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = AttachEvent;
				breakPoint.thisObject = thisObject;
				breakPoint.eventInfo = eventInfo;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Detach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = DetachEvent;
				breakPoint.thisObject = thisObject;
				breakPoint.eventInfo = eventInfo;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Invoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = InvokeEvent;
				breakPoint.thisObject = thisObject;
				breakPoint.eventInfo = eventInfo;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Invoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = InvokeMethod;
				breakPoint.thisObject = thisObject;
				breakPoint.methodInfo = methodInfo;
				return breakPoint;
			}

			WfBreakPoint WfBreakPoint::Create(reflection::description::ITypeDescriptor* typeDescriptor)
			{
				WfBreakPoint breakPoint;
				breakPoint.type = CreateObject;
				breakPoint.typeDescriptor = typeDescriptor;
				return breakPoint;
			}

/***********************************************************************
InstructionLocation
***********************************************************************/

			bool WfDebugger::InstructionLocation::BreakStepOver(const InstructionLocation& il, bool beforeCodegen)
			{
				if (contextIndex != il.contextIndex) return contextIndex > il.contextIndex;
				if (assembly != il.assembly) return true;
				if (stackFrameIndex != il.stackFrameIndex) return stackFrameIndex > il.stackFrameIndex;

				auto debugInfo = (beforeCodegen ? assembly->insBeforeCodegen : assembly->insAfterCodegen);
				auto& range1 = debugInfo->instructionCodeMapping[instruction];
				auto& range2 = debugInfo->instructionCodeMapping[il.instruction];

				if (range1.codeIndex != range2.codeIndex) return true;
				if (range1.start.row != range2.start.row) return true;

				return false;
			}

			bool WfDebugger::InstructionLocation::BreakStepInto(const InstructionLocation& il, bool beforeCodegen)
			{
				if (contextIndex != il.contextIndex) return true;
				if (assembly != il.assembly) return true;
				if (stackFrameIndex != il.stackFrameIndex) return true;

				auto debugInfo = (beforeCodegen ? assembly->insBeforeCodegen : assembly->insAfterCodegen);
				auto& range1 = debugInfo->instructionCodeMapping[instruction];
				auto& range2 = debugInfo->instructionCodeMapping[il.instruction];

				if (range1.codeIndex != range2.codeIndex) return true;
				if (range1.start.row != range2.start.row) return true;

				return false;
			}

/***********************************************************************
WfDebugger Callback Handlers
***********************************************************************/

			void WfDebugger::OnBlockExecution()
			{
			}

			void WfDebugger::OnStartExecution()
			{
			}

			void WfDebugger::OnStopExecution()
			{
			}

			WfDebugger::InstructionLocation WfDebugger::MakeCurrentInstructionLocation()
			{
				auto context = threadContexts[threadContexts.Count() - 1];
				InstructionLocation il;
				il.contextIndex = threadContexts.Count() - 1;
				il.assembly = context->globalContext->assembly.Obj();
				il.stackFrameIndex = context->stackFrames.Count() - 1;
				il.instruction = context->stackFrames[context->stackFrames.Count() - 1].nextInstructionIndex;
				return il;
			}
				
			template<typename TKey>
			bool WfDebugger::HandleBreakPoint(const TKey& key, collections::Dictionary<TKey, vint>& breakPointMap)
			{
				if (evaluatingBreakPoint)
				{
					return false;
				}

				evaluatingBreakPoint = true;
				bool activated = false;
				vint index = breakPointMap.Keys().IndexOf(key);
				if (index != -1)
				{
					index = breakPointMap.Values()[index];
					const auto& breakPoint = breakPoints[index];
					if (breakPoint.available && breakPoint.enabled)
					{
						if (breakPoint.action)
						{
							activated = breakPoint.action->EvaluateCondition(this);
							breakPoint.action->PostAction(this, activated);
						}
						else
						{
							activated = true;
						}
					}

					if (activated)
					{
						lastActivatedBreakPoint = index;
					}
				}
				evaluatingBreakPoint = false;
				return activated;
			}

			void WfDebugger::EnterThreadContext(WfRuntimeThreadContext* context)
			{
				if (threadContexts.Count() == 0)
				{
					lastActivatedBreakPoint = InvalidBreakPoint;
					instructionLocation = InstructionLocation();
					OnStartExecution();
					if (state == Stopped)
					{
						state = Running;
					}
				}
				threadContexts.Add(context);
			}

			void WfDebugger::LeaveThreadContext(WfRuntimeThreadContext* context)
			{
				auto oldContext = threadContexts[threadContexts.Count() - 1];
				threadContexts.RemoveAt(threadContexts.Count() - 1);
				CHECK_ERROR(context == oldContext, L"vl::workflow::runtime::WfDebugger::LeaveThreadContext(WfRuntimeThreadContext*)#EnterThreadContext and LeaveThreadContext should be called in pairs.");

				if (threadContexts.Count() == 0)
				{
					state = Stopped;
					OnStopExecution();
				}
			}

			bool WfDebugger::BreakIns(WfAssembly* assembly, vint instruction)
			{
				if (runningType != RunUntilBreakPoint)
				{
					auto il = MakeCurrentInstructionLocation();
					bool needToBreak = false;
					switch (runningType)
					{
					case RunStepOver:
						needToBreak = instructionLocation.BreakStepOver(il, stepBeforeCodegen);
						break;
					case RunStepInto:
						needToBreak = instructionLocation.BreakStepInto(il, stepBeforeCodegen);
						break;
					default:;
					}
					if (needToBreak)
					{
						instructionLocation = il;
						lastActivatedBreakPoint = WfDebugger::PauseBreakPoint;
						return true;
					}
				}

				switch (state)
				{
				case RequiredToPause:
				case RequiredToStop:
					lastActivatedBreakPoint = WfDebugger::PauseBreakPoint;
					return true;
				default:;
				}

				AssemblyKey key(assembly, instruction);
				return HandleBreakPoint(key, insBreakPoints);
			}

			bool WfDebugger::BreakRead(WfAssembly* assembly, vint variable)
			{
				AssemblyKey key(assembly, variable);
				return HandleBreakPoint(key, getGlobalVarBreakPoints);
			}

			bool WfDebugger::BreakWrite(WfAssembly* assembly, vint variable)
			{
				AssemblyKey key(assembly, variable);
				return HandleBreakPoint(key, setGlobalVarBreakPoints);
			}

			bool WfDebugger::BreakGet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
			{
				PropertyKey key1(thisObject, propertyInfo);
				PropertyKey key2(nullptr, propertyInfo);
				return HandleBreakPoint(key1, getPropertyBreakPoints) || HandleBreakPoint(key2, getPropertyBreakPoints);
			}

			bool WfDebugger::BreakSet(reflection::DescriptableObject* thisObject, reflection::description::IPropertyInfo* propertyInfo)
			{
				PropertyKey key1(thisObject, propertyInfo);
				PropertyKey key2(nullptr, propertyInfo);
				return HandleBreakPoint(key1, setPropertyBreakPoints) || HandleBreakPoint(key2, setPropertyBreakPoints);
			}

			bool WfDebugger::BreakAttach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
			{
				EventKey key1(thisObject, eventInfo);
				EventKey key2(nullptr, eventInfo);
				return HandleBreakPoint(key1, attachEventBreakPoints) || HandleBreakPoint(key2, attachEventBreakPoints);
			}

			bool WfDebugger::BreakDetach(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
			{
				EventKey key1(thisObject, eventInfo);
				EventKey key2(nullptr, eventInfo);
				return HandleBreakPoint(key1, detachEventBreakPoints) || HandleBreakPoint(key2, detachEventBreakPoints);
			}

			bool WfDebugger::BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IEventInfo* eventInfo)
			{
				EventKey key1(thisObject, eventInfo);
				EventKey key2(nullptr, eventInfo);
				return HandleBreakPoint(key1, invokeEventBreakPoints) || HandleBreakPoint(key2, invokeEventBreakPoints);
			}

			bool WfDebugger::BreakInvoke(reflection::DescriptableObject* thisObject, reflection::description::IMethodInfo* methodInfo)
			{
				MethodKey key1(thisObject, methodInfo);
				MethodKey key2(nullptr, methodInfo);
				return HandleBreakPoint(key1, invokeMethodBreakPoints) || HandleBreakPoint(key2, invokeMethodBreakPoints);
			}

			bool WfDebugger::BreakCreate(reflection::description::ITypeDescriptor* typeDescriptor)
			{
				return HandleBreakPoint(typeDescriptor, createObjectBreakPoints);
			}

			bool WfDebugger::BreakException(Ptr<WfRuntimeExceptionInfo> info)
			{
				if (breakException)
				{
					lastActivatedBreakPoint = PauseBreakPoint;
					return true;
				}
				else
				{
					return false;
				}
			}

			bool WfDebugger::WaitForContinue()
			{
				if (state == RequiredToStop)
				{
					return false;
				}

				state = lastActivatedBreakPoint >= 0 ? PauseByBreakPoint : PauseByOperation;
				while (state == PauseByBreakPoint || state == PauseByOperation)
				{
					OnBlockExecution();
				}
				
				if (state == Continue)
				{
					state = Running;
				}
				return true;
			}

/***********************************************************************
WfDebugger BreakPoints
***********************************************************************/

#define TEST(AVAILABLE, KEY, MAP) if (AVAILABLE && available == MAP.Keys().Contains(KEY)) return false;
#define SET(KEY, MAP) if (available) MAP.Add(KEY, index); else MAP.Remove(KEY);
#define SETC(AVAILABLE, KEY, MAP) if (AVAILABLE) {if (available) MAP.Add(KEY, index); else MAP.Remove(KEY);}

			bool WfDebugger::SetBreakPoint(const WfBreakPoint& breakPoint, bool available, vint index)
			{
				switch (breakPoint.type)
				{
				case WfBreakPoint::Instruction:
					{
						AssemblyKey key(breakPoint.assembly, breakPoint.instruction);
						TEST(true, key, insBreakPoints);
						SET(key, insBreakPoints);
					}
					break;
				case WfBreakPoint::ReadGlobalVar:
					{
						AssemblyKey key(breakPoint.assembly, breakPoint.variable);
						TEST(true, key, getGlobalVarBreakPoints);
						SET(key, getGlobalVarBreakPoints);
					}
					break;
				case WfBreakPoint::WriteGlobalVar:
					{
						AssemblyKey key(breakPoint.assembly, breakPoint.instruction);
						TEST(true, key, setGlobalVarBreakPoints);
						SET(key, setGlobalVarBreakPoints);
					}
					break;
				case WfBreakPoint::GetProperty:
					{
						PropertyKey key1(breakPoint.thisObject, breakPoint.propertyInfo);
						MethodKey key2(breakPoint.thisObject, breakPoint.propertyInfo->GetGetter());
						TEST(true, key1, getPropertyBreakPoints);
						TEST(key2.get<1>(), key2, invokeMethodBreakPoints);
						SET(key1, getPropertyBreakPoints);
						SETC(key2.get<1>(), key2, invokeMethodBreakPoints);
					}
					break;
				case WfBreakPoint::SetProperty:
					{
						PropertyKey key1(breakPoint.thisObject, breakPoint.propertyInfo);
						MethodKey key2(breakPoint.thisObject, breakPoint.propertyInfo->GetSetter());
						TEST(true, key1, setPropertyBreakPoints);
						TEST(key2.get<1>(), key2, invokeMethodBreakPoints);
						SET(key1, setPropertyBreakPoints);
						SETC(key2.get<1>(), key2, invokeMethodBreakPoints);
					}
					break;
				case WfBreakPoint::AttachEvent:
					{
						EventKey key(breakPoint.thisObject, breakPoint.eventInfo);
						TEST(true, key, attachEventBreakPoints);
						SET(key, attachEventBreakPoints);
					}
					break;
				case WfBreakPoint::DetachEvent:
					{
						EventKey key(breakPoint.thisObject, breakPoint.eventInfo);
						TEST(true, key, detachEventBreakPoints);
						SET(key, detachEventBreakPoints);
					}
					break;
				case WfBreakPoint::InvokeEvent:
					{
						EventKey key(breakPoint.thisObject, breakPoint.eventInfo);
						TEST(true, key, invokeEventBreakPoints);
						SET(key, invokeEventBreakPoints);
					}
					break;
				case WfBreakPoint::InvokeMethod:
					{
						// get property, set property and new object are all compiled to invoke method
						// so here it is not noecessary to generate other keys
						MethodKey key(breakPoint.thisObject, breakPoint.methodInfo);
						TEST(true, key, invokeMethodBreakPoints);
						SET(key, invokeMethodBreakPoints);
					}
					break;
				case WfBreakPoint::CreateObject:
					{
						auto group = breakPoint.typeDescriptor->GetConstructorGroup();
						vint count = group ? group->GetMethodCount() : 0;

						TEST(true, breakPoint.typeDescriptor, createObjectBreakPoints);
						for (vint i = 0; i < count; i++)
						{
							MethodKey key(nullptr, group->GetMethod(i));
							TEST(true, key, invokeMethodBreakPoints);
						}
						SET(breakPoint.typeDescriptor, createObjectBreakPoints);
						for (vint i = 0; i < count; i++)
						{
							MethodKey key(nullptr, group->GetMethod(i));
							SET(key, invokeMethodBreakPoints);
						}
					}
					break;
				default:
					return false;
				}
				return true;
			}

#undef TEST
#undef SET
#undef SETC

			WfDebugger::WfDebugger()
			{
			}

			WfDebugger::~WfDebugger()
			{
			}

			vint WfDebugger::AddBreakPoint(const WfBreakPoint& breakPoint)
			{
				vint index = breakPoints.Count();
				if (freeBreakPointIndices.Count() > 0)
				{
					index = freeBreakPointIndices[freeBreakPointIndices.Count() - 1];
				}

				if (!SetBreakPoint(breakPoint, true, index))
				{
					return -1;
				}
				
				if (index == breakPoints.Count())
				{
					breakPoints.Add(breakPoint);
				}
				else
				{
					freeBreakPointIndices.RemoveAt(freeBreakPointIndices.Count() - 1);
					breakPoints[index] = breakPoint;
				}

				breakPoints[index].id = index;
				breakPoints[index].available = true;
				breakPoints[index].enabled = true;
				breakPoints[index].action = nullptr;
				return index;
			}

			vint WfDebugger::AddCodeLineBreakPoint(WfAssembly* assembly, vint codeIndex, vint row, bool beforeCodegen)
			{
				auto& codeInsMap = (beforeCodegen ? assembly->insBeforeCodegen : assembly->insAfterCodegen)->codeInstructionMapping;
				Tuple<vint, vint> key(codeIndex, row);
				vint index = codeInsMap.Keys().IndexOf(key);
				if (index == -1)
				{
					return -1;
				}

				vint ins = codeInsMap.GetByIndex(index)[0];
				return AddBreakPoint(WfBreakPoint::Ins(assembly, ins));
			}

			bool WfDebugger::IsBreakPointAvailable(vint index)
			{
				return 0 <= index && index < breakPoints.Count() && !freeBreakPointIndices.Contains(index);
			}

			vint WfDebugger::GetBreakPointCount()
			{
				return breakPoints.Count();
			}

			const WfBreakPoint& WfDebugger::GetBreakPoint(vint index)
			{
				return breakPoints[index];
			}

			bool WfDebugger::RemoveBreakPoint(vint index)
			{
				if (index < 0 || index >= breakPoints.Count())
				{
					return false;
				}

				auto& breakPoint = breakPoints[index];
				if (!breakPoint.available || !SetBreakPoint(breakPoint, false, -1))
				{
					return false;
				}

				breakPoint.available = false;
				freeBreakPointIndices.Add(index);
				return true;
			}

			bool WfDebugger::EnableBreakPoint(vint index, bool enabled)
			{
				if (0 <= index && index <= breakPoints.Count())
				{
					auto& breakPoint = breakPoints[index];
					if (breakPoint.available)
					{
						breakPoint.enabled = enabled;
						return true;
					}
				}
				return false;
			}

			bool WfDebugger::GetBreakException()
			{
				return breakException;
			}

			void WfDebugger::SetBreakException(bool value)
			{
				breakException = value;
			}

/***********************************************************************
WfDebugger Operations
***********************************************************************/

			bool WfDebugger::Run()
			{
				if (state != PauseByOperation && state != PauseByBreakPoint)
				{
					return false;
				}
				state = Continue;
				runningType = RunUntilBreakPoint;
				return true;
			}

			bool WfDebugger::Pause()
			{
				if (state != Running && state != Stopped)
				{
					return false;
				}
				state = RequiredToPause;
				return true;
			}

			bool WfDebugger::Stop()
			{
				if (state != PauseByOperation && state != PauseByBreakPoint && state != Running)
				{
					return false;
				}
				state = RequiredToStop;
				return true;
			}

			bool WfDebugger::StepOver(bool beforeCodegen)
			{
				if (state != PauseByOperation && state != PauseByBreakPoint && state != Stopped)
				{
					return false;
				}
				if (state != Stopped)
				{
					state = Continue;
					instructionLocation = MakeCurrentInstructionLocation();
				}
				runningType = RunStepOver;
				stepBeforeCodegen = beforeCodegen;
				return true;
			}

			bool WfDebugger::StepInto(bool beforeCodegen)
			{
				if (state != PauseByOperation && state != PauseByBreakPoint && state != Stopped)
				{
					return false;
				}
				if (state != Stopped)
				{
					state = Continue;
					instructionLocation = MakeCurrentInstructionLocation();
				}
				state = Continue;
				runningType = RunStepInto;
				stepBeforeCodegen = beforeCodegen;
				return true;
			}

/***********************************************************************
WfDebugger
***********************************************************************/

			WfDebugger::State WfDebugger::GetState()
			{
				return state;
			}

			WfDebugger::RunningType WfDebugger::GetRunningType()
			{
				return runningType;
			}

			vint WfDebugger::GetLastActivatedBreakPoint()
			{
				return lastActivatedBreakPoint;
			}

			const WfDebugger::ThreadContextList& WfDebugger::GetThreadContexts()
			{
				return threadContexts;
			}

			WfRuntimeThreadContext* WfDebugger::GetCurrentThreadContext()
			{
				if (threadContexts.Count() == 0)
				{
					return nullptr;
				}
				return threadContexts[threadContexts.Count() - 1];
			}

			const glr::ParsingTextRange& WfDebugger::GetCurrentPosition(bool beforeCodegen, WfRuntimeThreadContext* context, vint callStackIndex)
			{
				if (!context)
				{
					context = GetCurrentThreadContext();
				}
				if (callStackIndex == -1)
				{
					callStackIndex = context->stackFrames.Count() - 1;
				}

				auto& stackFrame = context->stackFrames[callStackIndex];
				auto ins = stackFrame.nextInstructionIndex;
				auto debugInfo = (beforeCodegen ? context->globalContext->assembly->insBeforeCodegen : context->globalContext->assembly->insAfterCodegen);
				return debugInfo->instructionCodeMapping[ins];
			}

			reflection::description::Value WfDebugger::GetValueByName(const WString& name, WfRuntimeThreadContext* context, vint callStackIndex)
			{
				if (!context)
				{
					context = GetCurrentThreadContext();
				}
				if (callStackIndex == -1)
				{
					callStackIndex = context->stackFrames.Count() - 1;
				}

				auto& stackFrame = context->stackFrames[callStackIndex];
				auto function = context->globalContext->assembly->functions[stackFrame.functionIndex];

				vint index = function->argumentNames.IndexOf(name);
				if (index != -1)
				{
					return context->stack[stackFrame.stackBase + index];
				}

				index = function->localVariableNames.IndexOf(name);
				if (index != -1)
				{
					return context->stack[stackFrame.stackBase + function->argumentNames.Count() + index];
				}

				index = function->capturedVariableNames.IndexOf(name);
				if (index != -1)
				{
					return stackFrame.capturedVariables->variables[index];
				}

				index = context->globalContext->assembly->variableNames.IndexOf(name);
				if (index != -1)
				{
					return context->globalContext->globalVariables->variables[index];
				}

				return Value();
			}

/***********************************************************************
Helper Functions
***********************************************************************/

			ThreadVariable<Ptr<WfDebugger>> threadDebugger;

			IWfDebuggerCallback* GetDebuggerCallback()
			{
				auto debugger = GetDebuggerForCurrentThread();
				return GetDebuggerCallback(debugger.Obj());
			}

			IWfDebuggerCallback* GetDebuggerCallback(WfDebugger* debugger)
			{
				return debugger;
			}

			Ptr<WfDebugger> GetDebuggerForCurrentThread()
			{
				if (threadDebugger.HasData())
				{
					return threadDebugger.Get();
				}
				else
				{
					return {};
				}
			}

			void SetDebuggerForCurrentThread(Ptr<WfDebugger> debugger)
			{
#define ERROR_PREFIX L"vl::workflow::runtime::SetDebuggerForCurrentThread(Ptr<WfDebugger>)#"
				CHECK_ERROR(debugger, ERROR_PREFIX L"This function cannot be called with nullptr.");
				threadDebugger.Set(debugger);
#undef ERROR_PREFIX
			}

			void ResetDebuggerForCurrentThread()
			{
				threadDebugger.Clear();
			}
		}
	}
}

#endif

/***********************************************************************
.\WFRUNTIMEEXECUTION.CPP
***********************************************************************/

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA

namespace vl
{
	namespace workflow
	{
		namespace runtime
		{
			using namespace collections;
			using namespace reflection;
			using namespace reflection::description;
			using namespace typeimpl;

/***********************************************************************
WfRuntimeThreadContext (Operators)
***********************************************************************/

#define INTERNAL_ERROR(MESSAGE)\
				do{\
					context.RaiseException(WString(L"Internal error: " MESSAGE), true);\
					return WfRuntimeExecutionAction::Nop; \
				} while (0)\

#define CONTEXT_ACTION(ACTION, MESSAGE)\
				do{\
					if ((context.ACTION) != WfRuntimeThreadContextError::Success)\
					{\
						INTERNAL_ERROR(MESSAGE);\
					}\
				} while (0)\

			//-------------------------------------------------------------------------------

#define UNARY_OPERATOR(NAME, OPERATOR)\
			template<typename T>\
			WfRuntimeExecutionAction OPERATOR_##NAME(WfRuntimeThreadContext& context)\
			{\
				Value operand;\
				CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");\
				T value = OPERATOR UnboxValue<T>(operand);\
				CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");\
				return WfRuntimeExecutionAction::ExecuteInstruction;\
			}\

#define BINARY_OPERATOR(NAME, OPERATOR)\
			template<typename T>\
			WfRuntimeExecutionAction OPERATOR_##NAME(WfRuntimeThreadContext& context)\
			{\
				Value first, second;\
				CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");\
				CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");\
				T value = UnboxValue<T>(first) OPERATOR UnboxValue<T>(second);\
				CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");\
				return WfRuntimeExecutionAction::ExecuteInstruction;\
			}\

			//-------------------------------------------------------------------------------

			UNARY_OPERATOR(OpNot, ~)
			UNARY_OPERATOR(OpNot_Bool, !)
			UNARY_OPERATOR(OpPositive, +)
			UNARY_OPERATOR(OpNegative, -)

			BINARY_OPERATOR(OpAdd, +)
			BINARY_OPERATOR(OpSub, -)
			BINARY_OPERATOR(OpMul, *)
			BINARY_OPERATOR(OpDiv, /)
			BINARY_OPERATOR(OpMod, %)
			BINARY_OPERATOR(OpShl, <<)
			BINARY_OPERATOR(OpShr, >>)
			BINARY_OPERATOR(OpAnd, &)
			BINARY_OPERATOR(OpAnd_Bool, &&)
			BINARY_OPERATOR(OpOr, |)
			BINARY_OPERATOR(OpOr_Bool, ||)
			BINARY_OPERATOR(OpXor, ^)

			template<typename T>
			WfRuntimeExecutionAction OPERATOR_OpExp(WfRuntimeThreadContext& context)
			{
				Value first, second;
				CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
				CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
				T firstValue = UnboxValue<T>(first);
				T secondValue = UnboxValue<T>(second);
				T value = (T)exp(secondValue * log(firstValue));
				CONTEXT_ACTION(PushValue(BoxValue(value)), L"failed to push a value to the stack.");
				return WfRuntimeExecutionAction::ExecuteInstruction;
			}

			//-------------------------------------------------------------------------------
			
			template<typename T>
			WfRuntimeExecutionAction OPERATOR_OpCompare(WfRuntimeThreadContext& context)
			{
				Value first, second;
				CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
				CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");

				bool firstNull = first.GetValueType() == Value::Null;
				bool secondNull = second.GetValueType() == Value::Null;
				if (firstNull)
				{
					if (secondNull)
					{
						CONTEXT_ACTION(PushValue(BoxValue((vint)0)), L"failed to push a value to the stack.");
					}
					else
					{
						CONTEXT_ACTION(PushValue(BoxValue((vint)-1)), L"failed to push a value to the stack.");
					}
				}
				else
				{
					if (secondNull)
					{
						CONTEXT_ACTION(PushValue(BoxValue((vint)1)), L"failed to push a value to the stack.");
					}
					else
					{
						T firstValue = UnboxValue<T>(first);
						T secondValue = UnboxValue<T>(second);
						if (firstValue < secondValue)
						{
							CONTEXT_ACTION(PushValue(BoxValue((vint)-1)), L"failed to push a value to the stack.");
						}
						else if (firstValue > secondValue)
						{
							CONTEXT_ACTION(PushValue(BoxValue((vint)1)), L"failed to push a value to the stack.");
						}
						else
						{
							CONTEXT_ACTION(PushValue(BoxValue((vint)0)), L"failed to push a value to the stack.");
						}
					}
				}
				return WfRuntimeExecutionAction::ExecuteInstruction;
			}

			//-------------------------------------------------------------------------------

			WfRuntimeExecutionAction OPERATOR_OpCompareReference(WfRuntimeThreadContext& context)
			{
				Value first, second;
				CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
				CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");

				bool result = false;
				if (first.GetValueType() == Value::Null || second.GetValueType() == Value::Null)
				{
					result = first.GetValueType() == Value::Null && second.GetValueType() == Value::Null;
				}
				else if (first.GetValueType() == Value::BoxedValue || second.GetValueType() == Value::BoxedValue)
				{
					INTERNAL_ERROR(L"CompareReference instruction can only apply on null or pointers.");
				}
				else
				{
					result = first.GetRawPtr() == second.GetRawPtr();
				}
				CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
				return WfRuntimeExecutionAction::ExecuteInstruction;
			}

			//-------------------------------------------------------------------------------

			WfRuntimeExecutionAction OPERATOR_OpCompareValue(WfRuntimeThreadContext& context)
			{
				Value first, second;
				CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
				CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
				bool result = first == second;
				CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
				return WfRuntimeExecutionAction::ExecuteInstruction;
			}
			
/***********************************************************************
WfRuntimeThreadContext (TypeConversion)
***********************************************************************/

			bool OPERATOR_OpConvertToType(const Value& result, Value& converted, const WfInstruction& ins)
			{
				switch (ins.flagParameter)
				{
				case Value::Null:
					return false;
				case Value::RawPtr:
					if (result.GetValueType() == Value::BoxedValue)
					{
						return false;
					}
					else if (result.GetRawPtr())
					{
						if (result.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter))
						{
							converted = Value::From(result.GetRawPtr());
						}
						else
						{
							return false;
						}
					}
					break;
				case Value::SharedPtr:
					if (result.GetValueType() == Value::BoxedValue)
					{
						return false;
					}
					else if (result.GetRawPtr())
					{
						if (result.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter))
						{
							converted = Value::From(Ptr<DescriptableObject>(result.GetRawPtr()));
						}
						else
						{
							return false;
						}
					}
					break;
				case Value::BoxedValue:
					if (result.GetValueType() != Value::BoxedValue)
					{
						return false;
					}
					if (result.GetTypeDescriptor() == ins.typeDescriptorParameter)
					{
						converted = result;
						return true;
					}

					if (auto stFrom = result.GetTypeDescriptor()->GetSerializableType())
					{
						if (auto stTo = ins.typeDescriptorParameter->GetSerializableType())
						{
							WString text;
							return stFrom->Serialize(result, text) && stTo->Deserialize(text, converted);
						}
						else
						{
							switch (ins.typeDescriptorParameter->GetTypeDescriptorFlags())
							{
							case TypeDescriptorFlags::FlagEnum:
							case TypeDescriptorFlags::NormalEnum:
								if (result.GetTypeDescriptor() != GetTypeDescriptor<vuint64_t>())
								{
									return false;
								}
								else
								{
									auto intValue = result.GetBoxedValue().Cast<IValueType::TypedBox<vuint64_t>>()->value;
									converted = ins.typeDescriptorParameter->GetEnumType()->ToEnum(intValue);
								}
								break;
							default:
								return false;
							}
						}
					}
					else
					{
						switch (result.GetTypeDescriptor()->GetTypeDescriptorFlags())
						{
						case TypeDescriptorFlags::FlagEnum:
						case TypeDescriptorFlags::NormalEnum:
							if (ins.typeDescriptorParameter != GetTypeDescriptor<vuint64_t>())
							{
								return false;
							}
							else
							{
								auto intValue = result.GetTypeDescriptor()->GetEnumType()->FromEnum(result);
								converted = BoxValue<vuint64_t>(intValue);
							}
							break;
						default:
							return false;
						}
					}
				}

				return true;
			}
			
/***********************************************************************
WfRuntimeThreadContext (Range)
***********************************************************************/
			
			template<typename T>
			WfRuntimeExecutionAction OPERATOR_OpCreateRange(WfRuntimeThreadContext& context)
			{
				Value first, second;
				CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
				CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");
				T firstValue = UnboxValue<T>(first);
				T secondValue = UnboxValue<T>(second);
				auto enumerable = Ptr(new WfRuntimeRange<T>(firstValue, secondValue));
				CONTEXT_ACTION(PushValue(Value::From(enumerable)), L"failed to push a value to the stack.");
				return WfRuntimeExecutionAction::ExecuteInstruction;
			}

#undef INTERNAL_ERROR
#undef CONTEXT_ACTION
#undef UNARY_OPERATOR
#undef BINARY_OPERATOR

/***********************************************************************
Helper Functions
***********************************************************************/

			Ptr<reflection::description::IValueFunctionProxy> LoadFunction(Ptr<WfRuntimeGlobalContext> context, const WString& name)
			{
				const auto& names = context->assembly->functionByName[name];
				CHECK_ERROR(names.Count() == 1, L"vl::workflow::runtime::LoadFunction(Ptr<WfRUntimeGlobalContext>, const WString&)#Multiple functions are found.");
				vint functionIndex = names[0];
				auto lambda = Ptr(new WfRuntimeLambda(context, nullptr, functionIndex));
				return lambda;
			}

/***********************************************************************
WfRuntimeThreadContext
***********************************************************************/
			
#define INTERNAL_ERROR(MESSAGE)\
				do{\
					RaiseException(WString(L"Internal error: " MESSAGE), true);\
					return WfRuntimeExecutionAction::Nop; \
				} while (0)\

#define CONTEXT_ACTION(ACTION, MESSAGE)\
				do{\
					if ((ACTION) != WfRuntimeThreadContextError::Success)\
					{\
						INTERNAL_ERROR(MESSAGE);\
					}\
				} while (0)\

#define CALL_DEBUGGER(ACTION)\
				do {\
					if (callback)\
					{\
						if (ACTION)\
						{\
							if (!callback->WaitForContinue())\
							{\
								INTERNAL_ERROR(L"Debugger stopped the program.");\
							}\
						}\
					}\
				} while (0)\

#define TYPE_OF_Bool							bool
#define TYPE_OF_I1								vint8_t
#define TYPE_OF_I2								vint16_t
#define TYPE_OF_I4								vint32_t
#define TYPE_OF_I8								vint64_t
#define TYPE_OF_U1								vuint8_t
#define TYPE_OF_U2								vuint16_t
#define TYPE_OF_U4								vuint32_t
#define TYPE_OF_U8								vuint64_t
#define TYPE_OF_F4								float
#define TYPE_OF_F8								double
#define TYPE_OF_String							WString
#define EXECUTE(OPERATION, TYPE)				case WfInsType::TYPE: return OPERATOR_##OPERATION<TYPE_OF_##TYPE>(*this);
#define BEGIN_TYPE								switch(ins.typeParameter) {
#define END_TYPE								default: INTERNAL_ERROR(L"unexpected type argument."); }

			WfRuntimeExecutionAction WfRuntimeThreadContext::ExecuteInternal(WfInstruction& ins, WfRuntimeStackFrame& stackFrame, IWfDebuggerCallback* callback)
			{
				switch (ins.code)
				{
				case WfInsCode::LoadValue:
					CONTEXT_ACTION(PushRuntimeValue(ins.valueParameter), L"failed to push a value to the stack.");
					return WfRuntimeExecutionAction::ExecuteInstruction;
				case WfInsCode::LoadFunction:
					{
						CONTEXT_ACTION(PushValue(BoxValue(ins.indexParameter)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadException:
					{
						CONTEXT_ACTION(PushValue(BoxValue(exceptionInfo)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadLocalVar:
					{
						Value operand;
						CONTEXT_ACTION(LoadLocalVariable(ins.indexParameter, operand), L"illegal local variable index.");
						CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadCapturedVar:
					{
						Value operand;
						CONTEXT_ACTION(LoadCapturedVariable(ins.indexParameter, operand), L"illegal captured variable index.");
						CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadGlobalVar:
					{
						CALL_DEBUGGER(callback->BreakRead(globalContext->assembly.Obj(), ins.indexParameter));
						Value operand;
						CONTEXT_ACTION(LoadGlobalVariable(ins.indexParameter, operand), L"illegal global variable index.");
						CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadMethodInfo:
					{
						CONTEXT_ACTION(PushValue(Value::From(ins.methodParameter)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadMethodClosure:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						auto closure = ins.methodParameter->CreateFunctionProxy(operand);
						CONTEXT_ACTION(PushValue(closure), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::LoadClosureContext:
					{
						auto capturedVariables = GetCurrentStackFrame().capturedVariables;
						CONTEXT_ACTION(PushValue(Value::From(capturedVariables)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::StoreLocalVar:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(StoreLocalVariable(ins.indexParameter, operand), L"illegal local variable index.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::StoreCapturedVar:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(StoreCapturedVariable(ins.indexParameter, operand), L"illegal global variable index.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::StoreGlobalVar:
					{
						CALL_DEBUGGER(callback->BreakWrite(globalContext->assembly.Obj(), ins.indexParameter));
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(StoreGlobalVariable(ins.indexParameter, operand), L"illegal global variable index.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::Duplicate:
					{
						vint index = stack.Count() - 1 - ins.countParameter;
						Value operand;
						CONTEXT_ACTION(LoadStackValue(index, operand), L"failed to duplicate a value from the stack.");
						CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::Pop:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::Return:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop the function result.");
						CONTEXT_ACTION(PopStackFrame(), L"failed to pop the stack frame.");
						CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
						if (stackFrames.Count() == 0)
						{
							status = WfRuntimeExecutionStatus::Finished;
						}
						return WfRuntimeExecutionAction::ExitStackFrame;
					}
				case WfInsCode::NewArray:
					{
						auto list = IValueArray::Create();
						if (ins.countParameter > 0)
						{
							list->Resize(ins.countParameter);
							Value operand;
							for (vint i = 0; i < ins.countParameter; i++)
							{
								CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
								list->Set(i, operand);
							}
						}
						CONTEXT_ACTION(PushValue(Value::From(list)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::NewList:
					{
						auto list = IValueList::Create();
						Value operand;
						for (vint i = 0; i < ins.countParameter; i++)
						{
							CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
							list->Add(operand);
						}
						CONTEXT_ACTION(PushValue(Value::From(list)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::NewObservableList:
					{
						auto list = IValueObservableList::Create();
						Value operand;
						for (vint i = 0; i < ins.countParameter; i++)
						{
							CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
							list->Add(operand);
						}
						CONTEXT_ACTION(PushValue(Value::From(list)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::NewDictionary:
					{
						auto map = IValueDictionary::Create();
						Value key, value;
						for (vint i = 0; i < ins.countParameter; i+=2)
						{
							CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
							CONTEXT_ACTION(PopValue(key), L"failed to pop a value from the stack.");
							map->Set(key, value);
						}
						CONTEXT_ACTION(PushValue(Value::From(map)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::CreateClosureContext:
					{
						Ptr<WfRuntimeVariableContext> capturedVariables;
						if (ins.countParameter > 0)
						{
							capturedVariables = Ptr(new WfRuntimeVariableContext);
							capturedVariables->variables.Resize(ins.countParameter);
							Value operand;
							for (vint i = 0; i < ins.countParameter; i++)
							{
								CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
								capturedVariables->variables[ins.countParameter - 1 - i] = operand;
							}
						}

						CONTEXT_ACTION(PushValue(Value::From(capturedVariables)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::CreateClosure:
					{
						Value context, function;
						CONTEXT_ACTION(PopValue(function), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(context), L"failed to pop a value from the stack.");
						auto capturedVariables = context.GetSharedPtr().Cast<WfRuntimeVariableContext>();
						auto functionIndex = UnboxValue<vint>(function);

						auto lambda = Ptr(new WfRuntimeLambda(globalContext, capturedVariables, functionIndex));
						CONTEXT_ACTION(PushValue(Value::From(lambda)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::CreateInterface:
					{
						auto proxy = Ptr(new WfRuntimeInterfaceInstance);
						Value key, value, operand;
						for (vint i = 0; i < ins.countParameter; i+=2)
						{
							CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
							CONTEXT_ACTION(PopValue(key), L"failed to pop a value from the stack.");
							if (key.IsNull())
							{
								proxy->destructorFunctionIndex = UnboxValue<vint>(value);
							}
							else
							{
								auto name = UnboxValue<IMethodInfo*>(key);
								auto func = UnboxValue<vint>(value);
								proxy->functions.Add(name, func);
							}
						}

						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						auto capturedVariables = operand.GetSharedPtr().Cast<WfRuntimeVariableContext>();
						proxy->capturedVariables = capturedVariables;
						proxy->globalContext = globalContext.Obj();

						Array<Value> arguments(1);
						arguments[0] = Value::From(proxy);
						auto obj = ins.methodParameter->Invoke(Value(), arguments);
						capturedVariables->variables[capturedVariables->variables.Count() - 1] = Value::From(obj.GetRawPtr());

						CONTEXT_ACTION(PushValue(obj), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::CreateRange:
					BEGIN_TYPE
						EXECUTE(OpCreateRange, I1)
						EXECUTE(OpCreateRange, I2)
						EXECUTE(OpCreateRange, I4)
						EXECUTE(OpCreateRange, I8)
						EXECUTE(OpCreateRange, U1)
						EXECUTE(OpCreateRange, U2)
						EXECUTE(OpCreateRange, U4)
						EXECUTE(OpCreateRange, U8)
					END_TYPE
				case WfInsCode::CreateStruct:
					{
						if (ins.typeDescriptorParameter->GetTypeDescriptorFlags() != TypeDescriptorFlags::Struct)
						{
							INTERNAL_ERROR(L"Type \"" + ins.typeDescriptorParameter->GetTypeName() + L"\" is not a struct.");
						}
						Value result = ins.typeDescriptorParameter->GetValueType()->CreateDefault();
						CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::DeleteRawPtr:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						operand.DeleteRawPtr();
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::ConvertToType:
					{
						Value result, converted;
						CONTEXT_ACTION(PopValue(result), L"failed to pop a value from the stack.");
						if (OPERATOR_OpConvertToType(result, converted, ins))
						{
							CONTEXT_ACTION(PushValue(converted), L"failed to push a value to the stack.");
						}
						else
						{
							WString from;
							if (result.IsNull())
							{
								from = L"<null>";
							}
							else
							{
								if (auto st = result.GetTypeDescriptor()->GetSerializableType())
								{
									WString text;
									st->Serialize(result, text);
									from = L"<" + text + L"> of " + result.GetTypeDescriptor()->GetTypeName();
								}
								else
								{
									from = result.GetTypeDescriptor()->GetTypeName();
								}
							}
							WString to = ins.typeDescriptorParameter->GetTypeName();
							RaiseException(L"Failed to convert from \"" + from + L"\" to \"" + to + L"\".", false);
						}
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::TryConvertToType:
					{
						Value result, converted;
						CONTEXT_ACTION(PopValue(result), L"failed to pop a value from the stack.");
						if (OPERATOR_OpConvertToType(result, converted, ins))
						{
							CONTEXT_ACTION(PushValue(converted), L"failed to push a value to the stack.");
						}
						else
						{
							CONTEXT_ACTION(PushValue(Value()), L"failed to push a value to the stack.");
						}
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::TestType:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						if (operand.GetTypeDescriptor() && operand.GetValueType() == ins.flagParameter && operand.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter))
						{
							CONTEXT_ACTION(PushValue(BoxValue(true)), L"failed to push a value to the stack.");
						}
						else
						{
							CONTEXT_ACTION(PushValue(BoxValue(false)), L"failed to push a value to the stack.");
						}
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::GetType:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PushValue(Value::From(operand.GetTypeDescriptor())), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::Jump:
					{
						stackFrame.nextInstructionIndex = ins.indexParameter;
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::JumpIf:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						if (UnboxValue<bool>(operand))
						{
							stackFrame.nextInstructionIndex = ins.indexParameter;
						}
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::Invoke:
					{
						CONTEXT_ACTION(PushStackFrame(ins.indexParameter, ins.countParameter), L"failed to invoke a function.");
						return WfRuntimeExecutionAction::EnterStackFrame;
					}
				case WfInsCode::InvokeWithContext:
					{
						CONTEXT_ACTION(PushStackFrame(ins.indexParameter, ins.countParameter, GetCurrentStackFrame().capturedVariables), L"failed to invoke a function.");
						return WfRuntimeExecutionAction::EnterStackFrame;
					}
				case WfInsCode::GetProperty:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakGet(operand.GetRawPtr(), ins.propertyParameter));
						Value result = ins.propertyParameter->GetValue(operand);
						CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::SetProperty:
					{
						Value operand, value;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakSet(operand.GetRawPtr(), ins.propertyParameter));
						ins.propertyParameter->SetValue(operand, value);
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::UpdateProperty:
					{
						Value operand, value;
						CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakSet(operand.GetRawPtr(), ins.propertyParameter));
						ins.propertyParameter->SetValue(operand, value);
						CONTEXT_ACTION(PushValue(operand), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::InvokeProxy:
					{
						Value thisValue;
						CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
						auto proxy = UnboxValue<Ptr<IValueFunctionProxy>>(thisValue);
						if (!proxy)
						{
							INTERNAL_ERROR(L"failed to invoke a null function proxy.");
							return WfRuntimeExecutionAction::Nop;
						}

						if (auto lambda = proxy.Cast<WfRuntimeLambda>())
						{
							if (lambda->globalContext == globalContext)
							{
								CONTEXT_ACTION(PushStackFrame(lambda->functionIndex, ins.countParameter, lambda->capturedVariables), L"failed to invoke a function.");
								return WfRuntimeExecutionAction::EnterStackFrame;
							}
						}

						List<Value> arguments;
						for (vint i = 0; i < ins.countParameter; i++)
						{
							Value argument;
							CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
							arguments.Insert(0, argument);
						}

						Ptr<IValueList> list = Ptr(new ValueListWrapper<List<Value>*>(&arguments));
						Value result = proxy->Invoke(list);
						CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::InvokeMethod:
					{
						Value thisValue;
						CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.methodParameter));

						if (auto staticMethod = dynamic_cast<WfStaticMethod*>(ins.methodParameter))
						{
							if (staticMethod->GetGlobalContext() == globalContext.Obj())
							{
								CONTEXT_ACTION(PushStackFrame(staticMethod->functionIndex, ins.countParameter, nullptr), L"failed to invoke a function.");
								return WfRuntimeExecutionAction::EnterStackFrame;
							}
						}

						if (auto classMethod = dynamic_cast<WfClassMethod*>(ins.methodParameter))
						{
							if (classMethod->GetGlobalContext() == globalContext.Obj())
							{
								auto capturedVariable = Ptr(new WfRuntimeVariableContext);
								capturedVariable->variables.Resize(1);
								capturedVariable->variables[0] = Value::From(thisValue.GetRawPtr());

								CONTEXT_ACTION(PushStackFrame(classMethod->functionIndex, ins.countParameter, capturedVariable), L"failed to invoke a function.");
								return WfRuntimeExecutionAction::EnterStackFrame;
							}
						}

						Array<Value> arguments(ins.countParameter);
						for (vint i = 0; i < ins.countParameter; i++)
						{
							Value argument;
							CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
							arguments[ins.countParameter - i - 1] = argument;
						}

						Value result = ins.methodParameter->Invoke(thisValue, arguments);
						CONTEXT_ACTION(PushValue(result), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::InvokeEvent:
					{
						Value thisValue;
						CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.eventParameter));

						auto arguments = IValueList::Create();
						for (vint i = 0; i < ins.countParameter; i++)
						{
							Value argument;
							CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
							arguments->Insert(0, argument);
						}

						ins.eventParameter->Invoke(thisValue, arguments);
						CONTEXT_ACTION(PushValue(Value()), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::InvokeBaseCtor:
					{
						Value thisValue;
						CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.eventParameter));
						
						if (auto ctor = dynamic_cast<WfClassConstructor*>(ins.methodParameter))
						{
							if (ctor->GetGlobalContext() == globalContext.Obj())
							{
								auto capturedVariable = Ptr(new WfRuntimeVariableContext);
								capturedVariable->variables.Resize(1);
								capturedVariable->variables[0] = Value::From(thisValue.GetRawPtr());

								CONTEXT_ACTION(PushStackFrame(ctor->functionIndex, ins.countParameter, capturedVariable), L"failed to invoke a function.");
								return WfRuntimeExecutionAction::EnterStackFrame;
							}
						}

						Array<Value> arguments(ins.countParameter);
						for (vint i = 0; i < ins.countParameter; i++)
						{
							Value argument;
							CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack.");
							arguments[ins.countParameter - i - 1] = argument;
						}
						
						if (auto ctor = dynamic_cast<WfClassConstructor*>(ins.methodParameter))
						{
							ctor->InvokeBaseCtor(thisValue, arguments);
						}
						else
						{
							auto instance = dynamic_cast<WfClassInstance*>(thisValue.GetRawPtr());
							if (!instance)
							{
								INTERNAL_ERROR(L"Wrong class instance for invoking base constructor.");
							}

							Value baseValue = ins.methodParameter->Invoke(Value(), arguments);
							instance->InstallBaseObject(ins.methodParameter->GetOwnerTypeDescriptor(), baseValue);
						}
						CONTEXT_ACTION(PushValue(Value()), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::AttachEvent:
					{
						Value thisValue, function;
						CONTEXT_ACTION(PopValue(function), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakAttach(thisValue.GetRawPtr(), ins.eventParameter));
						auto proxy = UnboxValue<Ptr<IValueFunctionProxy>>(function);
						auto handler = ins.eventParameter->Attach(thisValue, proxy);
						CONTEXT_ACTION(PushValue(Value::From(handler)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::DetachEvent:
					{
						Value thisValue, operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack.");
						CALL_DEBUGGER(callback->BreakDetach(thisValue.GetRawPtr(), ins.eventParameter));
						auto handler = UnboxValue<Ptr<IEventHandler>>(operand);
						auto result = ins.eventParameter->Detach(thisValue, handler);
						CONTEXT_ACTION(PushValue(BoxValue(result)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::InstallTry:
					CONTEXT_ACTION(PushTrapFrame(ins.indexParameter), L"failed to push a trap frame");
					return WfRuntimeExecutionAction::ExecuteInstruction;
				case WfInsCode::UninstallTry:
					{
						if (trapFrames.Count() == 0)
						{
							INTERNAL_ERROR(L"failed to pop the trap frame.");
						}
						auto frame = GetCurrentTrapFrame();
						CONTEXT_ACTION(PopTrapFrame(ins.countParameter), L"failed to pop the trap frame.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::RaiseException:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						if (operand.GetValueType() == Value::BoxedValue)
						{
							WString text;
							operand.GetTypeDescriptor()->GetSerializableType()->Serialize(operand, text);
							RaiseException(text, false);
						}
						else if (auto info = operand.GetSharedPtr().Cast<WfRuntimeExceptionInfo>())
						{
							RaiseException(info);
						}
						else if (auto ex = operand.GetSharedPtr().Cast<IValueException>())
						{
							RaiseException(ex->GetMessage(), false);
						}
						else
						{
							INTERNAL_ERROR(L"failed to raise an exception which is neither a string nor a WfRuntimeExceptionInfo.");
						}
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::TestElementInSet:
					{
						Value element, set;
						CONTEXT_ACTION(PopValue(set), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(element), L"failed to pop a value from the stack.");

						auto enumerable = UnboxValue<Ptr<IValueEnumerable>>(set);
						auto enumerator = enumerable->CreateEnumerator();
						while (enumerator->Next())
						{
							if (enumerator->GetCurrent() == element)
							{
								CONTEXT_ACTION(PushValue(BoxValue(true)), L"failed to push a value to the stack.");
								return WfRuntimeExecutionAction::ExecuteInstruction;
							}
						}
						CONTEXT_ACTION(PushValue(BoxValue(false)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::CompareLiteral:
					BEGIN_TYPE
						EXECUTE(OpCompare, Bool)
						EXECUTE(OpCompare, I1)
						EXECUTE(OpCompare, I2)
						EXECUTE(OpCompare, I4)
						EXECUTE(OpCompare, I8)
						EXECUTE(OpCompare, U1)
						EXECUTE(OpCompare, U2)
						EXECUTE(OpCompare, U4)
						EXECUTE(OpCompare, U8)
						EXECUTE(OpCompare, F4)
						EXECUTE(OpCompare, F8)
						EXECUTE(OpCompare, String)
					END_TYPE
				case WfInsCode::CompareReference:
					{
						return OPERATOR_OpCompareReference(*this);
					}
				case WfInsCode::CompareValue:
					{
						return OPERATOR_OpCompareValue(*this);
					}
				case WfInsCode::OpNot:
					BEGIN_TYPE
						EXECUTE(OpNot_Bool, Bool)
						EXECUTE(OpNot, I1)
						EXECUTE(OpNot, I2)
						EXECUTE(OpNot, I4)
						EXECUTE(OpNot, I8)
						EXECUTE(OpNot, U1)
						EXECUTE(OpNot, U2)
						EXECUTE(OpNot, U4)
						EXECUTE(OpNot, U8)
					END_TYPE
				case WfInsCode::OpPositive:
					BEGIN_TYPE
						EXECUTE(OpPositive, I1)
						EXECUTE(OpPositive, I2)
						EXECUTE(OpPositive, I4)
						EXECUTE(OpPositive, I8)
						EXECUTE(OpPositive, U1)
						EXECUTE(OpPositive, U2)
						EXECUTE(OpPositive, U4)
						EXECUTE(OpPositive, U8)
						EXECUTE(OpPositive, F4)
						EXECUTE(OpPositive, F8)
					END_TYPE
				case WfInsCode::OpNegative:
					BEGIN_TYPE
						EXECUTE(OpNegative, I1)
						EXECUTE(OpNegative, I2)
						EXECUTE(OpNegative, I4)
						EXECUTE(OpNegative, I8)
						EXECUTE(OpNegative, F4)
						EXECUTE(OpNegative, F8)
					END_TYPE
				case WfInsCode::OpConcat:
					{
						Value first, second;
						CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack.");
						CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack.");

						WString firstText, secondText;
						first.GetTypeDescriptor()->GetSerializableType()->Serialize(first, firstText);
						first.GetTypeDescriptor()->GetSerializableType()->Serialize(second, secondText);

						CONTEXT_ACTION(PushValue(BoxValue(firstText + secondText)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
				case WfInsCode::OpExp:
					BEGIN_TYPE
						EXECUTE(OpExp, F4)
						EXECUTE(OpExp, F8)
					END_TYPE
				case WfInsCode::OpAdd:
					BEGIN_TYPE
						EXECUTE(OpAdd, I1)
						EXECUTE(OpAdd, I2)
						EXECUTE(OpAdd, I4)
						EXECUTE(OpAdd, I8)
						EXECUTE(OpAdd, U1)
						EXECUTE(OpAdd, U2)
						EXECUTE(OpAdd, U4)
						EXECUTE(OpAdd, U8)
						EXECUTE(OpAdd, F4)
						EXECUTE(OpAdd, F8)
					END_TYPE
				case WfInsCode::OpSub:
					BEGIN_TYPE
						EXECUTE(OpSub, I1)
						EXECUTE(OpSub, I2)
						EXECUTE(OpSub, I4)
						EXECUTE(OpSub, I8)
						EXECUTE(OpSub, U1)
						EXECUTE(OpSub, U2)
						EXECUTE(OpSub, U4)
						EXECUTE(OpSub, U8)
						EXECUTE(OpSub, F4)
						EXECUTE(OpSub, F8)
					END_TYPE
				case WfInsCode::OpMul:
					BEGIN_TYPE
						EXECUTE(OpMul, I1)
						EXECUTE(OpMul, I2)
						EXECUTE(OpMul, I4)
						EXECUTE(OpMul, I8)
						EXECUTE(OpMul, U1)
						EXECUTE(OpMul, U2)
						EXECUTE(OpMul, U4)
						EXECUTE(OpMul, U8)
						EXECUTE(OpMul, F4)
						EXECUTE(OpMul, F8)
					END_TYPE
				case WfInsCode::OpDiv:
					BEGIN_TYPE
						EXECUTE(OpDiv, I1)
						EXECUTE(OpDiv, I2)
						EXECUTE(OpDiv, I4)
						EXECUTE(OpDiv, I8)
						EXECUTE(OpDiv, U1)
						EXECUTE(OpDiv, U2)
						EXECUTE(OpDiv, U4)
						EXECUTE(OpDiv, U8)
						EXECUTE(OpDiv, F4)
						EXECUTE(OpDiv, F8)
					END_TYPE
				case WfInsCode::OpMod:
					BEGIN_TYPE
						EXECUTE(OpMod, I1)
						EXECUTE(OpMod, I2)
						EXECUTE(OpMod, I4)
						EXECUTE(OpMod, I8)
						EXECUTE(OpMod, U1)
						EXECUTE(OpMod, U2)
						EXECUTE(OpMod, U4)
						EXECUTE(OpMod, U8)
					END_TYPE
				case WfInsCode::OpShl:
					BEGIN_TYPE
						EXECUTE(OpShl, I1)
						EXECUTE(OpShl, I2)
						EXECUTE(OpShl, I4)
						EXECUTE(OpShl, I8)
						EXECUTE(OpShl, U1)
						EXECUTE(OpShl, U2)
						EXECUTE(OpShl, U4)
						EXECUTE(OpShl, U8)
					END_TYPE
				case WfInsCode::OpShr:
					BEGIN_TYPE
						EXECUTE(OpShr, I1)
						EXECUTE(OpShr, I2)
						EXECUTE(OpShr, I4)
						EXECUTE(OpShr, I8)
						EXECUTE(OpShr, U1)
						EXECUTE(OpShr, U2)
						EXECUTE(OpShr, U4)
						EXECUTE(OpShr, U8)
					END_TYPE
				case WfInsCode::OpXor:
					BEGIN_TYPE
						EXECUTE(OpXor, Bool)
						EXECUTE(OpXor, I1)
						EXECUTE(OpXor, I2)
						EXECUTE(OpXor, I4)
						EXECUTE(OpXor, I8)
						EXECUTE(OpXor, U1)
						EXECUTE(OpXor, U2)
						EXECUTE(OpXor, U4)
						EXECUTE(OpXor, U8)
					END_TYPE
				case WfInsCode::OpAnd:
					BEGIN_TYPE
						EXECUTE(OpAnd_Bool, Bool)
						EXECUTE(OpAnd, I1)
						EXECUTE(OpAnd, I2)
						EXECUTE(OpAnd, I4)
						EXECUTE(OpAnd, I8)
						EXECUTE(OpAnd, U1)
						EXECUTE(OpAnd, U2)
						EXECUTE(OpAnd, U4)
						EXECUTE(OpAnd, U8)
					END_TYPE
				case WfInsCode::OpOr:
					BEGIN_TYPE
						EXECUTE(OpOr_Bool, Bool)
						EXECUTE(OpOr, I1)
						EXECUTE(OpOr, I2)
						EXECUTE(OpOr, I4)
						EXECUTE(OpOr, I8)
						EXECUTE(OpOr, U1)
						EXECUTE(OpOr, U2)
						EXECUTE(OpOr, U4)
						EXECUTE(OpOr, U8)
					END_TYPE
				case WfInsCode::OpLT:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						vint value = UnboxValue<vint>(operand);
						CONTEXT_ACTION(PushValue(BoxValue(value < 0)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
					break;
				case WfInsCode::OpGT:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						vint value = UnboxValue<vint>(operand);
						CONTEXT_ACTION(PushValue(BoxValue(value > 0)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
					break;
				case WfInsCode::OpLE:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						vint value = UnboxValue<vint>(operand);
						CONTEXT_ACTION(PushValue(BoxValue(value <= 0)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
					break;
				case WfInsCode::OpGE:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						vint value = UnboxValue<vint>(operand);
						CONTEXT_ACTION(PushValue(BoxValue(value >= 0)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
					break;
				case WfInsCode::OpEQ:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						vint value = UnboxValue<vint>(operand);
						CONTEXT_ACTION(PushValue(BoxValue(value == 0)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
					break;
				case WfInsCode::OpNE:
					{
						Value operand;
						CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack.");
						vint value = UnboxValue<vint>(operand);
						CONTEXT_ACTION(PushValue(BoxValue(value != 0)), L"failed to push a value to the stack.");
						return WfRuntimeExecutionAction::ExecuteInstruction;
					}
					break;
				default:
					return WfRuntimeExecutionAction::Nop;
				}
			}

			WfRuntimeExecutionAction WfRuntimeThreadContext::Execute(IWfDebuggerCallback* callback)
			{
				try
				{
					switch (status)
					{
					case WfRuntimeExecutionStatus::Ready:
					case WfRuntimeExecutionStatus::Executing:
						{
							if (stackFrames.Count() == 0)
							{
								INTERNAL_ERROR(L"empty stack frame.");
							}
							auto& stackFrame = GetCurrentStackFrame();
							if (stackFrame.nextInstructionIndex < 0 || stackFrame.nextInstructionIndex >= globalContext->assembly->instructions.Count())
							{
								INTERNAL_ERROR(L"illegal instruction index.");
							}

							auto insIndex = stackFrame.nextInstructionIndex;
							CALL_DEBUGGER(callback->BreakIns(globalContext->assembly.Obj(), insIndex));

							stackFrame.nextInstructionIndex++;
							auto& ins = globalContext->assembly->instructions[insIndex];
							return ExecuteInternal(ins, stackFrame, callback);
						}
						break;
					case WfRuntimeExecutionStatus::RaisedException:
						if (trapFrames.Count() > 0)
						{
							auto trapFrame = GetCurrentTrapFrame();
							if (trapFrame.stackFrameIndex == stackFrames.Count() - 1)
							{
								CONTEXT_ACTION(PopTrapFrame(0), L"failed to pop the trap frame");
								GetCurrentStackFrame().nextInstructionIndex = trapFrame.instructionIndex;
								status = WfRuntimeExecutionStatus::Executing;
								return WfRuntimeExecutionAction::UnwrapStack;
							}
							else if (stackFrames.Count() > 0)
							{
								CONTEXT_ACTION(PopStackFrame(), L"failed to pop the stack frame.");
								return WfRuntimeExecutionAction::UnwrapStack;
							}
						}
						break;
					default:;
					}
					return WfRuntimeExecutionAction::Nop;
				}
				catch (const WfRuntimeException& ex)
				{
					if (ex.GetInfo())
					{
						RaiseException(ex.GetInfo());
					}
					else
					{
						RaiseException(ex.Message(), ex.IsFatal());
					}
					return WfRuntimeExecutionAction::ExecuteInstruction;
				}
				catch (const Exception& ex)
				{
					RaiseException(ex.Message(), false);
					return WfRuntimeExecutionAction::ExecuteInstruction;
				}
			}

#undef INTERNAL_ERROR
#undef CONTEXT_ACTION
#undef CALL_DEBUGGER
#undef TYPE_OF_Bool
#undef TYPE_OF_I1
#undef TYPE_OF_I2
#undef TYPE_OF_I4
#undef TYPE_OF_I8
#undef TYPE_OF_U1
#undef TYPE_OF_U2
#undef TYPE_OF_U4
#undef TYPE_OF_U8
#undef TYPE_OF_F4
#undef TYPE_OF_F8
#undef TYPE_OF_String
#undef EXECUTE
#undef BEGIN_TYPE
#undef END_TYPE
		}
	}
}

#endif

/***********************************************************************
.\WFRUNTIMEINSTRUCTION.CPP
***********************************************************************/

namespace vl
{
	namespace workflow
	{
		namespace runtime
		{
			using namespace reflection::description;

/***********************************************************************
WfInstruction
***********************************************************************/

			WfInstruction::WfInstruction()
				:flagParameter(Value::Null)
				, typeDescriptorParameter(0)
			{

			}

#define CTOR(NAME)\
			WfInstruction WfInstruction::NAME()\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				return ins; \
			}\

#define CTOR_VALUE(NAME)\
			WfInstruction WfInstruction::NAME(const WfRuntimeValue& value)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.valueParameter = value; \
				return ins; \
			}\

#define CTOR_FUNCTION(NAME)\
			WfInstruction WfInstruction::NAME(vint function)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.indexParameter = function; \
				return ins; \
			}\

#define CTOR_FUNCTION_COUNT(NAME)\
			WfInstruction WfInstruction::NAME(vint function, vint count)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.indexParameter = function; \
				ins.countParameter = count; \
				return ins; \
			}\

#define CTOR_VARIABLE(NAME)\
			WfInstruction WfInstruction::NAME(vint variable)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.indexParameter = variable; \
				return ins; \
			}\

#define CTOR_COUNT(NAME)\
			WfInstruction WfInstruction::NAME(vint count)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.countParameter = count; \
				return ins; \
			}\

#define CTOR_FLAG_TYPEDESCRIPTOR(NAME)\
			WfInstruction WfInstruction::NAME(reflection::description::Value::ValueType flag, reflection::description::ITypeDescriptor* typeDescriptor)\
			{\
				CHECK_ERROR(typeDescriptor != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(Value::ValueType, ITypeDescriptor*)#Internal error, argument null.");\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.flagParameter = flag; \
				ins.typeDescriptorParameter = typeDescriptor; \
				return ins; \
			}\

#define CTOR_PROPERTY(NAME)\
			WfInstruction WfInstruction::NAME(reflection::description::IPropertyInfo* propertyInfo)\
			{\
				CHECK_ERROR(propertyInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(propertyInfo*)#Internal error, argument null.");\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.propertyParameter = propertyInfo; \
				return ins; \
			}\

#define CTOR_METHOD(NAME)\
			WfInstruction WfInstruction::NAME(reflection::description::IMethodInfo* methodInfo)\
			{\
				CHECK_ERROR(methodInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(methodInfo*)#Internal error, argument null.");\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.methodParameter = methodInfo; \
				return ins; \
			}\

#define CTOR_METHOD_COUNT(NAME)\
			WfInstruction WfInstruction::NAME(reflection::description::IMethodInfo* methodInfo, vint count)\
			{\
				CHECK_ERROR(methodInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(methodInfo*, vint)#Internal error, argument null.");\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.methodParameter = methodInfo; \
				ins.countParameter = count; \
				return ins; \
			}\

#define CTOR_EVENT(NAME)\
			WfInstruction WfInstruction::NAME(reflection::description::IEventInfo* eventInfo)\
			{\
				CHECK_ERROR(eventInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(IEventInfo*)#Internal error, argument null.");\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.eventParameter = eventInfo; \
				return ins; \
			}\

#define CTOR_EVENT_COUNT(NAME)\
			WfInstruction WfInstruction::NAME(reflection::description::IEventInfo* eventInfo, vint count)\
			{\
				CHECK_ERROR(eventInfo != nullptr, L"vl::workflow::runtime::WfInstruction::" L ## #NAME L"(IEventInfo*, vint)#Internal error, argument null.");\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.eventParameter = eventInfo; \
				ins.countParameter = count; \
				return ins; \
			}\

#define CTOR_LABEL(NAME)\
			WfInstruction WfInstruction::NAME(vint label)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.indexParameter = label; \
				return ins; \
			}\

#define CTOR_TYPE(NAME)\
			WfInstruction WfInstruction::NAME(WfInsType type)\
			{\
				WfInstruction ins; \
				ins.code = WfInsCode::NAME; \
				ins.typeParameter = type; \
				return ins; \
			}\

			INSTRUCTION_CASES(
				CTOR,
				CTOR_VALUE,
				CTOR_FUNCTION,
				CTOR_FUNCTION_COUNT,
				CTOR_VARIABLE,
				CTOR_COUNT,
				CTOR_FLAG_TYPEDESCRIPTOR,
				CTOR_PROPERTY,
				CTOR_METHOD,
				CTOR_METHOD_COUNT,
				CTOR_EVENT,
				CTOR_EVENT_COUNT,
				CTOR_LABEL,
				CTOR_TYPE)

#undef CTOR
#undef CTOR_VALUE
#undef CTOR_FUNCTION
#undef CTOR_FUNCTION_COUNT
#undef CTOR_VARIABLE
#undef CTOR_COUNT
#undef CTOR_FLAG_TYPEDESCRIPTOR
#undef CTOR_PROPERTY
#undef CTOR_METHOD
#undef CTOR_METHOD_COUNT
#undef CTOR_EVENT
#undef CTOR_EVENT_COUNT
#undef CTOR_LABEL
#undef CTOR_TYPE
		}
	}
}


/***********************************************************************
.\WFRUNTIMETYPEDESCRIPTOR.CPP
***********************************************************************/

namespace vl
{
	namespace workflow
	{
		namespace typeimpl
		{
			using namespace reflection;
			using namespace reflection::description;
			using namespace collections;
			using namespace runtime;

/***********************************************************************
WfMethodProxy
***********************************************************************/

			WfMethodProxy::WfMethodProxy(const Value& _thisObject, IMethodInfo* _methodInfo)
				:thisObject(_thisObject)
				, methodInfo(_methodInfo)
			{

			}

			WfMethodProxy::~WfMethodProxy()
			{
			}
				
			Value WfMethodProxy::Invoke(Ptr<IValueReadonlyList> arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				return methodInfo->Invoke(thisObject, UnboxParameter<Array<Value>>(Value::From(arguments)).Ref());
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

/***********************************************************************
WfMethodBase
***********************************************************************/

			Value WfMethodBase::CreateFunctionProxyInternal(const Value& thisObject)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				return Value::From(Ptr(new WfMethodProxy(thisObject, this)));
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			void WfMethodBase::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext)
			{
				globalContext = _globalContext;
			}

			WfMethodBase::WfMethodBase(bool isStatic)
				:MethodInfoImpl(nullptr, nullptr, isStatic)
			{
			}

			WfMethodBase::~WfMethodBase()
			{
			}

			IMethodInfo::ICpp* WfMethodBase::GetCpp()
			{
				return nullptr;
			}
			
			runtime::WfRuntimeGlobalContext* WfMethodBase::GetGlobalContext()
			{
				return globalContext;
			}

			void WfMethodBase::SetReturn(Ptr<ITypeInfo> type)
			{
				returnInfo = type;
			}

/***********************************************************************
WfStaticMethod
***********************************************************************/

			Value WfStaticMethod::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto argumentArray = IValueList::Create(arguments);
				return WfRuntimeLambda::Invoke(Ptr(globalContext), nullptr, functionIndex, argumentArray);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfStaticMethod::WfStaticMethod()
				:WfMethodBase(true)
			{
			}

/***********************************************************************
WfClassConstructor
***********************************************************************/

			Value WfClassConstructor::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto instance = Ptr(new WfClassInstance(GetOwnerTypeDescriptor()));
				{
					InvokeBaseCtor(Value::From(instance.Obj()), arguments);
				}

				if (returnInfo->GetDecorator() == ITypeInfo::SharedPtr)
				{
					return Value::From(instance);
				}
				else
				{
					return Value::From(instance.Detach());
				}
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfClassConstructor::WfClassConstructor(Ptr<ITypeInfo> type)
				:WfMethodBase(true)
			{
				SetReturn(type);
			}

			void WfClassConstructor::InvokeBaseCtor(const Value& thisObject, collections::Array<Value>& arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto capturedVariables = Ptr(new WfRuntimeVariableContext);
				capturedVariables->variables.Resize(1);
				capturedVariables->variables[0] = Value::From(thisObject.GetRawPtr());
					
				auto argumentArray = IValueList::Create(arguments);
				WfRuntimeLambda::Invoke(Ptr(globalContext), capturedVariables, functionIndex, argumentArray);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

/***********************************************************************
WfClassMethod
***********************************************************************/

			Value WfClassMethod::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto capturedVariables = Ptr(new WfRuntimeVariableContext);
				capturedVariables->variables.Resize(1);
				capturedVariables->variables[0] = Value::From(thisObject.GetRawPtr());

				auto argumentArray = IValueList::Create(arguments);
				return WfRuntimeLambda::Invoke(Ptr(globalContext), capturedVariables, functionIndex, argumentArray);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfClassMethod::WfClassMethod()
				:WfMethodBase(false)
			{
			}

/***********************************************************************
WfInterfaceConstructor
***********************************************************************/

			Value WfInterfaceConstructor::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				if (arguments.Count() != 1)
				{
					throw ArgumentCountMismtatchException(GetOwnerMethodGroup());
				}
				auto proxy = UnboxValue<Ptr<IValueInterfaceProxy>>(arguments[0]);

				List<IMethodInfo*> baseCtors;
				{
					const auto& baseTypes = dynamic_cast<WfCustomType*>(GetOwnerTypeDescriptor())->GetExpandedBaseTypes();

					for (vint i = 0; i < baseTypes.Count(); i++)
					{
						auto td = baseTypes[i];
						if (td != description::GetTypeDescriptor<IDescriptable>())
						{
							if (auto group = td->GetConstructorGroup())
							{
								vint count = group->GetMethodCount();
								IMethodInfo* selectedCtor = nullptr;

								for (vint j = 0; j < count; j++)
								{
									auto ctor = group->GetMethod(j);
									if (ctor->GetParameterCount() == 1)
									{
										auto type = ctor->GetParameter(0)->GetType();
										if (type->GetDecorator() == ITypeInfo::SharedPtr && type->GetTypeDescriptor() == description::GetTypeDescriptor<IValueInterfaceProxy>())
										{
											selectedCtor = ctor;
											break;
										}
									}
								}

								if (selectedCtor)
								{
									baseCtors.Add(selectedCtor);
								}
								else
								{
									throw ArgumentCountMismtatchException(group);
								}
							}
							else
							{
								throw ConstructorNotExistsException(td);
							}
						}
					}
				}

				auto instance = Ptr(new WfInterfaceInstance(GetOwnerTypeDescriptor(), proxy, baseCtors));

				if (returnInfo->GetDecorator() == ITypeInfo::SharedPtr)
				{
					return Value::From(instance);
				}
				else
				{
					return Value::From(instance.Detach());
				}
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfInterfaceConstructor::WfInterfaceConstructor(Ptr<ITypeInfo> type)
				:WfMethodBase(true)
			{
				auto argumentType = TypeInfoRetriver<Ptr<IValueInterfaceProxy>>::CreateTypeInfo();
				auto parameter = Ptr(new ParameterInfoImpl(this, L"proxy", argumentType));
				AddParameter(parameter);
				SetReturn(type);
			}

/***********************************************************************
WfInterfaceMethod
***********************************************************************/

			Value WfInterfaceMethod::InvokeInternal(const Value& thisObject, collections::Array<Value>& arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto instance = thisObject.GetRawPtr()->SafeAggregationCast<WfInterfaceInstance>();
				return instance->GetProxy()->Invoke(this, IValueList::Create(From(arguments)));
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfInterfaceMethod::WfInterfaceMethod()
				:WfMethodBase(false)
			{
			}

/***********************************************************************
GetInfoRecord
***********************************************************************/

#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
			template<typename TRecord, typename TInfo>
			Ptr<TRecord> GetInfoRecord(TInfo* target, DescriptableObject* thisObject, const WString& key, bool createIfNotExist)
			{
				if (!thisObject)
				{
					throw ArgumentNullException(L"thisObject", target);
				}
				auto untypedValue = thisObject->GetInternalProperty(key);
				auto typedValue = untypedValue.Cast<TRecord>();
				if (untypedValue)
				{
					if (!typedValue)
					{
						throw ArgumentException(L"Key mismatches with the record type.", L"vl::workflow::typeimpl::GetFieldRecord", L"key");
					}
				}
				else if(createIfNotExist)
				{
					typedValue = Ptr(new TRecord);
					thisObject->SetInternalProperty(key, typedValue);
				}
				return typedValue;
			}
#endif

/***********************************************************************
WfEvent
***********************************************************************/

			const wchar_t* WfEvent::EventRecordInternalPropertyName = L"WfEvent::EventRecord";

			Ptr<WfEvent::EventRecord> WfEvent::GetEventRecord(DescriptableObject* thisObject, bool createIfNotExist)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				return GetInfoRecord<EventRecord>(this, thisObject, EventRecordInternalPropertyName, createIfNotExist);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			Ptr<IEventHandler> WfEvent::AttachInternal(DescriptableObject* thisObject, Ptr<IValueFunctionProxy> handler)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto record = GetEventRecord(thisObject, true);
				auto result = Ptr(new EventHandlerImpl(handler));
				record->handlers.Add(this, result);
				return result;
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			bool WfEvent::DetachInternal(DescriptableObject* thisObject, Ptr<IEventHandler> handler)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto impl = handler.Cast<EventHandlerImpl>();
				if (!impl)return false;
				auto record = GetEventRecord(thisObject, true);
				if (record->handlers.Remove(this, impl.Obj()))
				{
					impl->isAttached = false;
					return true;
				}
				return false;
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			void WfEvent::InvokeInternal(DescriptableObject* thisObject, Ptr<IValueReadonlyList> arguments)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto record = GetEventRecord(thisObject, false);
				if (record)
				{
					vint index = record->handlers.Keys().IndexOf(this);
					if (index != -1)
					{
						auto& values = record->handlers.GetByIndex(index);
						for (auto handler : values)
						{
							handler->proxy->Invoke(arguments);
						}
					}
				}
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			Ptr<ITypeInfo> WfEvent::GetHandlerTypeInternal()
			{
				return handlerType;
			}

			WfEvent::WfEvent(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
				:EventInfoImpl(ownerTypeDescriptor, name)
			{
			}

			WfEvent::~WfEvent()
			{
			}

			IEventInfo::ICpp* WfEvent::GetCpp()
			{
				return nullptr;
			}

			void WfEvent::SetHandlerType(Ptr<ITypeInfo> typeInfo)
			{
				handlerType = typeInfo;
			}

/***********************************************************************
WfField
***********************************************************************/

			const wchar_t* WfField::FieldRecordInternalPropertyName = L"WfField::FieldRecord";

			Ptr<WfField::FieldRecord> WfField::GetFieldRecord(DescriptableObject* thisObject, bool createIfNotExist)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				return GetInfoRecord<FieldRecord>(this, thisObject, FieldRecordInternalPropertyName, createIfNotExist);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			Value WfField::GetValueInternal(const Value& thisObject)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto record = GetFieldRecord(thisObject.GetRawPtr(), true);
				return record->values.Get(this);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			void WfField::SetValueInternal(Value& thisObject, const Value& newValue)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto record = GetFieldRecord(thisObject.GetRawPtr(), true);
				record->values.Set(this, newValue);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfField::WfField(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
				:FieldInfoImpl(ownerTypeDescriptor, name, nullptr)
			{
			}

			WfField::~WfField()
			{
			}

			IPropertyInfo::ICpp* WfField::GetCpp()
			{
				return nullptr;
			}

			void WfField::SetReturn(Ptr<ITypeInfo> typeInfo)
			{
				returnInfo = typeInfo;
			}

/***********************************************************************
WfStructField
***********************************************************************/

			Value WfStructField::GetValueInternal(const Value& thisObject)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto structValue = thisObject.GetBoxedValue().Cast<WfStructInstance>();
				if (!structValue)
				{
					throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
				}
				vint index = structValue->fieldValues.Keys().IndexOf(this);
				if (index == -1)
				{
					return returnInfo->GetTypeDescriptor()->GetValueType()->CreateDefault();
				}
				else
				{
					return structValue->fieldValues.Values()[index];
				}
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			void WfStructField::SetValueInternal(Value& thisObject, const Value& newValue)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto structValue = thisObject.GetBoxedValue().Cast<WfStructInstance>();
				if (!structValue)
				{
					throw ArgumentTypeMismtatchException(L"thisObject", GetOwnerTypeDescriptor(), Value::BoxedValue, thisObject);
				}
				structValue->fieldValues.Set(this, newValue);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfStructField::WfStructField(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
				:FieldInfoImpl(ownerTypeDescriptor, name, nullptr)
			{
			}

			WfStructField::~WfStructField()
			{
			}

			IPropertyInfo::ICpp* WfStructField::GetCpp()
			{
				return nullptr;
			}

			void WfStructField::SetReturn(Ptr<ITypeInfo> typeInfo)
			{
				returnInfo = typeInfo;
			}

/***********************************************************************
WfProperty
***********************************************************************/

			WfProperty::WfProperty(ITypeDescriptor* ownerTypeDescriptor, const WString& name)
				:PropertyInfoImpl(ownerTypeDescriptor, name, nullptr, nullptr, nullptr)
			{
			}

			WfProperty::~WfProperty()
			{
			}

			void WfProperty::SetGetter(MethodInfoImpl* value)
			{
				getter = value;
			}

			void WfProperty::SetSetter(MethodInfoImpl* value)
			{
				setter = value;
			}

			void WfProperty::SetValueChangedEvent(EventInfoImpl* value)
			{
				valueChangedEvent = value;
			}

/***********************************************************************
WfTypeInfoContent
***********************************************************************/

			WfTypeInfoContent::WfTypeInfoContent(const WString& _workflowTypeName)
				:workflowTypeName(_workflowTypeName)
			{
				typeName = workflowTypeName.Buffer();
				cppFullTypeName = nullptr;
				cppName = TypeInfoContent::CppType;
			}

/***********************************************************************
WfCustomType
***********************************************************************/

			void WfCustomType::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext, IMethodGroupInfo* group)
			{
				vint methodCount = group->GetMethodCount();
				for (vint j = 0; j < methodCount; j++)
				{
					auto method = group->GetMethod(j);
					if (auto methodInfo = dynamic_cast<WfMethodBase*>(method))
					{
						methodInfo->SetGlobalContext(globalContext);
					}
				}
			}

			void WfCustomType::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext)
			{
				globalContext = _globalContext;
				
				if (auto group = GetConstructorGroup())
				{
					SetGlobalContext(globalContext, group);
				}

				vint methodGroupCount = GetMethodGroupCount();
				for (vint i = 0; i < methodGroupCount; i++)
				{
					auto group = GetMethodGroup(i);
					SetGlobalContext(globalContext, group);
				}
			}

			void WfCustomType::LoadInternal()
			{
			}

			WfCustomType::WfCustomType(reflection::description::TypeDescriptorFlags typeDescriptorFlags, const WString& typeName)
				:WfCustomTypeBase<reflection::description::TypeDescriptorImpl>(typeDescriptorFlags, typeName)
			{
			}

			WfCustomType::~WfCustomType()
			{
			}
			
			runtime::WfRuntimeGlobalContext* WfCustomType::GetGlobalContext()
			{
				return globalContext;
			}

			const WfCustomType::TypeDescriptorList& WfCustomType::GetExpandedBaseTypes()
			{
				if (!baseTypeExpanded)
				{
					baseTypeExpanded = true;
					TypeDescriptorList customTypes;
					customTypes.Add(this);

					for (vint i = 0; i < customTypes.Count(); i++)
					{
						auto td = customTypes[i];
						vint count = td->GetBaseTypeDescriptorCount();
						for (vint j = 0; j < count; j++)
						{
							auto baseTd = td->GetBaseTypeDescriptor(j);
							if (dynamic_cast<WfCustomType*>(baseTd))
							{
								customTypes.Add(baseTd);
							}
							else
							{
								expandedBaseTypes.Add(baseTd);
							}
						}
					}
				}
				return expandedBaseTypes;
			}

			void WfCustomType::AddBaseType(ITypeDescriptor* type)
			{
				TypeDescriptorImpl::AddBaseType(type);
			}

			void WfCustomType::AddMember(const WString& name, Ptr<WfMethodBase> value)
			{
				AddMethod(name, value);
			}

			void WfCustomType::AddMember(Ptr<WfClassConstructor> value)
			{
				AddConstructor(value);
			}

			void WfCustomType::AddMember(Ptr<WfInterfaceConstructor> value)
			{
				AddConstructor(value);
			}

			void WfCustomType::AddMember(Ptr<WfField> value)
			{
				AddProperty(value);
			}

			void WfCustomType::AddMember(Ptr<WfProperty> value)
			{
				AddProperty(value);
			}

			void WfCustomType::AddMember(Ptr<WfEvent> value)
			{
				AddEvent(value);
			}

/***********************************************************************
WfClass
***********************************************************************/

			WfClass::WfClass(const WString& typeName)
				:WfCustomType(TypeDescriptorFlags::Class, typeName)
			{
			}

			WfClass::~WfClass()
			{
			}

/***********************************************************************
WfInterface
***********************************************************************/

			WfInterface::WfInterface(const WString& typeName)
				:WfCustomType(TypeDescriptorFlags::Interface, typeName)
			{
			}

			WfInterface::~WfInterface()
			{
			}

/***********************************************************************
WfStruct
***********************************************************************/

			WfStruct::WfValueType::WfValueType(WfStruct* _owner)
				:owner(_owner)
			{
			}

			Value WfStruct::WfValueType::CreateDefault()
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				return Value::From(Ptr(new WfStructInstance(owner)), owner);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfStruct::WfStruct(const WString& typeName)
				:WfCustomTypeBase<reflection::description::ValueTypeDescriptorBase>(TypeDescriptorFlags::Struct, typeName)
			{
				this->valueType = Ptr(new WfValueType(this));
			}

			WfStruct::~WfStruct()
			{
			}

			vint WfStruct::GetPropertyCount()
			{
				this->Load();
				return fields.Count();
			}

			IPropertyInfo* WfStruct::GetProperty(vint index)
			{
				this->Load();
				if (index < 0 || index >= fields.Count())
				{
					return nullptr;
				}
				return fields.Values()[index].Obj();
			}

			bool WfStruct::IsPropertyExists(const WString& name, bool inheritable)
			{
				this->Load();
				return fields.Keys().Contains(name);
			}

			IPropertyInfo* WfStruct::GetPropertyByName(const WString& name, bool inheritable)
			{
				this->Load();
				vint index = fields.Keys().IndexOf(name);
				if (index == -1) return nullptr;
				return fields.Values()[index].Obj();
			}

			void WfStruct::AddMember(Ptr<WfStructField> value)
			{
				fields.Add(value->GetName(), value);
			}

/***********************************************************************
WfEnum::WfEnumType
***********************************************************************/

			WfEnum::WfEnumType::WfEnumType(WfEnum* _owner)
				:owner(_owner)
			{
			}

			bool WfEnum::WfEnumType::IsFlagEnum()
			{
				return owner->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum;
			}

			vint WfEnum::WfEnumType::GetItemCount()
			{
				return owner->enumItems.Count();
			}

			WString WfEnum::WfEnumType::GetItemName(vint index)
			{
				if (index < 0 || index >= owner->enumItems.Count())
				{
					return L"";
				}
				return owner->enumItems.Keys()[index];
			}

			vuint64_t WfEnum::WfEnumType::GetItemValue(vint index)
			{
				if (index < 0 || index >= owner->enumItems.Count())
				{
					return 0;
				}
				return owner->enumItems.Values()[index];
			}

			vint WfEnum::WfEnumType::IndexOfItem(WString name)
			{
				return owner->enumItems.Keys().IndexOf(name);
			}

			Value WfEnum::WfEnumType::ToEnum(vuint64_t value)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto boxedValue = Ptr(new WfEnumInstance(owner));
				boxedValue->value = value;
				return Value::From(boxedValue, owner);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			vuint64_t WfEnum::WfEnumType::FromEnum(const Value& value)
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				auto enumValue = value.GetBoxedValue().Cast<WfEnumInstance>();
				if (!enumValue)
				{
					throw ArgumentTypeMismtatchException(L"enumValue", owner, Value::BoxedValue, value);
				}
				return enumValue->value;
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

/***********************************************************************
WfEnum
***********************************************************************/

			WfEnum::WfValueType::WfValueType(WfEnum* _owner)
				:owner(_owner)
			{
			}

			Value WfEnum::WfValueType::CreateDefault()
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				return Value::From(Ptr(new WfEnumInstance(owner)), owner);
#else
				CHECK_FAIL(L"Not Implemented under VCZH_DEBUG_METAONLY_REFLECTION!");
#endif
			}

			WfEnum::WfEnum(bool isFlags, const WString& typeName)
				:WfCustomTypeBase<reflection::description::ValueTypeDescriptorBase>((isFlags ? TypeDescriptorFlags::FlagEnum : TypeDescriptorFlags::NormalEnum), typeName)
			{
				this->valueType = Ptr(new WfValueType(this));
				this->enumType = Ptr(new WfEnumType(this));
			}

			WfEnum::~WfEnum()
			{
			}

			void WfEnum::AddEnumItem(const WString& name, vuint64_t value)
			{
				enumItems.Add(name, value);
			}

/***********************************************************************
WfClassInstance
***********************************************************************/

			WfClassInstance::WfClassInstance(ITypeDescriptor* _typeDescriptor)
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				:Description<WfClassInstance>(_typeDescriptor)
#endif
			{
				classType = dynamic_cast<WfClass*>(_typeDescriptor);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				InitializeAggregation(classType->GetExpandedBaseTypes().Count());
#endif
			}

			WfClassInstance::~WfClassInstance()
			{
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				if (classType->destructorFunctionIndex != -1)
				{
					auto capturedVariables = Ptr(new WfRuntimeVariableContext);
					capturedVariables->variables.Resize(1);
					capturedVariables->variables[0] = Value::From(this);

					auto argumentArray = IValueList::Create();
					WfRuntimeLambda::Invoke(Ptr(classType->GetGlobalContext()), capturedVariables, classType->destructorFunctionIndex, argumentArray);
				}
#endif
			}

			void WfClassInstance::InstallBaseObject(ITypeDescriptor* td, Value& value)
			{
				Ptr<DescriptableObject> ptr;
				{
					if (!(ptr = value.GetSharedPtr()))
					{
						ptr = Ptr(value.GetRawPtr());
					}
					value = Value();
				}
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				vint index = classType->GetExpandedBaseTypes().IndexOf(td);
				SetAggregationParent(index, ptr);
#endif
			}

/***********************************************************************
WfInterfaceInstance
***********************************************************************/

			WfInterfaceInstance::WfInterfaceInstance(ITypeDescriptor* _typeDescriptor, Ptr<IValueInterfaceProxy> _proxy, collections::List<IMethodInfo*>& baseCtors)
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				:Description<WfInterfaceInstance>(_typeDescriptor)
				, proxy(_proxy)
#endif
			{
				Array<Value> arguments(1);
				arguments[0] = Value::From(_proxy);
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
				InitializeAggregation(baseCtors.Count());
				for (auto [ctor, index] : indexed(baseCtors))
				{
					Ptr<DescriptableObject> ptr;
					{
						auto value = ctor->Invoke(Value(), arguments);
						if (!(ptr = value.GetSharedPtr()))
						{
							ptr = Ptr(value.GetRawPtr());
						}
					}

					SetAggregationParent(index, ptr);
				}
#endif
			}

			WfInterfaceInstance::~WfInterfaceInstance()
			{
			}

			Ptr<IValueInterfaceProxy> WfInterfaceInstance::GetProxy()
			{
				return proxy;
			}

/***********************************************************************
WfStructInstance
***********************************************************************/

			WfStructInstance::WfStructInstance(reflection::description::ITypeDescriptor* _typeDescriptor)
				: typeDescriptor(_typeDescriptor)
			{
			}

			PredefinedBoxableType WfStructInstance::GetBoxableType()
			{
				return PredefinedBoxableType::PBT_Unknown;
			}

			Ptr<IBoxedValue> WfStructInstance::Copy()
			{
				auto instance = Ptr(new WfStructInstance(typeDescriptor));
				CopyFrom(instance->fieldValues, fieldValues);
				return instance;
			}

			IBoxedValue::CompareResult WfStructInstance::ComparePrimitive(Ptr<IBoxedValue> boxedValue)
			{
				auto instance = boxedValue.Cast<WfStructInstance>();
				if (!instance) return IBoxedValue::NotComparable;
				if (typeDescriptor != instance->typeDescriptor) return IBoxedValue::NotComparable;
				
				auto&& as = fieldValues;
				auto&& bs = instance->fieldValues;
				if (as.Count() == 0 && bs.Count() == 0) return IBoxedValue::Equal;

				vint ai = 0;
				vint bi = 0;
				while (ai < as.Count() || bi < bs.Count())
				{
					Value af, bf;
					auto ap = ai < as.Count() ? as.Keys()[ai] : nullptr;
					auto bp = bi < bs.Count() ? bs.Keys()[bi] : nullptr;
					auto p =
						ap == nullptr ? bp :
						bp == nullptr ? ap :
						ap < bp ? ap : bp;

					if (p == ap)
					{
						af = as.Values()[ai];
					}
					else if (p->GetReturn()->GetDecorator() == ITypeInfo::TypeDescriptor)
					{
						af = p->GetReturn()->GetTypeDescriptor()->GetValueType()->CreateDefault();
					}

					if (p == bp)
					{
						bf = bs.Values()[bi];
					}
					else if (p->GetReturn()->GetDecorator() == ITypeInfo::TypeDescriptor)
					{
						bf = p->GetReturn()->GetTypeDescriptor()->GetValueType()->CreateDefault();
					}

					auto result = af <=> bf;
					if constexpr (std::is_same_v<decltype(result), std::partial_ordering>)
					{
						if (result == std::partial_ordering::unordered) return IBoxedValue::NotComparable;
					}
					if (result < 0) return IBoxedValue::Smaller;
					if (result > 0) return IBoxedValue::Greater;

					if (p == ap) ai++;
					if (p == bp) bi++;
				}

				return IBoxedValue::Equal;
			}

/***********************************************************************
WfEnumInstance
***********************************************************************/

			WfEnumInstance::WfEnumInstance(reflection::description::ITypeDescriptor* _typeDescriptor)
				: typeDescriptor(_typeDescriptor)
			{
			}

			PredefinedBoxableType WfEnumInstance::GetBoxableType()
			{
				return PredefinedBoxableType::PBT_Unknown;
			}

			Ptr<IBoxedValue> WfEnumInstance::Copy()
			{
				auto instance = Ptr(new WfEnumInstance(typeDescriptor));
				instance->value = value;
				return instance;
			}

			IBoxedValue::CompareResult WfEnumInstance::ComparePrimitive(Ptr<IBoxedValue> boxedValue)
			{
				auto instance = boxedValue.Cast<WfEnumInstance>();
				if (!instance) return IBoxedValue::NotComparable;
				if (typeDescriptor != instance->typeDescriptor) return IBoxedValue::NotComparable;
				
				auto result = value <=> instance->value;
				if (result < 0) return IBoxedValue::Smaller;
				if (result > 0) return IBoxedValue::Greater;
				return IBoxedValue::Equal;
			}

/***********************************************************************
WfTypeImpl
***********************************************************************/
			
			runtime::WfRuntimeGlobalContext* WfTypeImpl::GetGlobalContext()
			{
				return globalContext;
			}

			void WfTypeImpl::SetGlobalContext(runtime::WfRuntimeGlobalContext* _globalContext)
			{
				if (globalContext)
				{
					CHECK_ERROR(!_globalContext, L"vl::workflow::typeimpl::WfTypeImpl::SetGlobalContext(WfRuntimeGlobalContext*)#Only one global context is allowed to create from an assembly at the same time.");
				}
				else
				{
					CHECK_ERROR(_globalContext, L"vl::workflow::typeimpl::WfTypeImpl::SetGlobalContext(WfRuntimeGlobalContext*)#Only one global context is allowed to create from an assembly at the same time.");
				}

				globalContext = _globalContext;
				for (auto td : classes)
				{
					td->SetGlobalContext(globalContext);
				}
				for (auto td : interfaces)
				{
					td->SetGlobalContext(globalContext);
				}

				if (globalContext)
				{
					GetGlobalTypeManager()->AddTypeLoader(Ptr<WfTypeImpl>(this));
				}
				else
				{
					GetGlobalTypeManager()->RemoveTypeLoader(Ptr<WfTypeImpl>(this));
				}
			}

			void WfTypeImpl::Load(reflection::description::ITypeManager* manager)
			{
				for (auto td : classes)
				{
					if (td->GetBaseTypeDescriptorCount() == 0)
					{
						td->AddBaseType(description::GetTypeDescriptor<DescriptableObject>());
					}
					manager->SetTypeDescriptor(td->GetTypeName(), td);
				}
				for (auto td : interfaces)
				{
					if (td->GetBaseTypeDescriptorCount() == 0)
					{
						td->AddBaseType(description::GetTypeDescriptor<IDescriptable>());
					}
					manager->SetTypeDescriptor(td->GetTypeName(), td);
				}
				for (auto td : structs)
				{
					manager->SetTypeDescriptor(td->GetTypeName(), td);
				}
				for (auto td : enums)
				{
					manager->SetTypeDescriptor(td->GetTypeName(), td);
				}
			}

			void WfTypeImpl::Unload(reflection::description::ITypeManager* manager)
			{
				for (auto td : classes)
				{
					manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
				}
				for (auto td : interfaces)
				{
					manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
				}
				for (auto td : structs)
				{
					manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
				}
				for (auto td : enums)
				{
					manager->SetTypeDescriptor(td->GetTypeName(), nullptr);
				}
			}
		}
	}
}
