private DynamicMethod BuildMain(ExecutionPath executionPath, out object[] closure)
            {
                var ilBuilderContext = new ILBuilderContext(ContextFieldInfo);

                if (executionPath.EnterReturnNodes.Length > 0)
                {
                    if (IsOverriden(nameof(BuildBeginExecutionPath)))
                    {
                        BuildBeginExecutionPath(ilBuilderContext, executionPath.StackEvalDelta);
                    }

                    ilBuilderContext.EmitLdStack();
                    ilBuilderContext.IL.Emit(OpCodes.Ldc_I4, executionPath.StackEvalDelta);
                    ilBuilderContext.IL.Emit(OpCodes.Call, EnsureDeltaMethodInfo);
                }

                {
                    if (executionPath.PathSourceNode is LeaveStateNode leaveStateNode)
                    {
                        EmitDebugNode(ilBuilderContext, executionPath.PathSourceNode, executionPath);

                        var subGraph = leaveStateNode.SubGraph;

                        if (subGraph.StateEntry != null)
                        {
                            if (IsOverriden(nameof(BuildLeaveStateEntry)))
                            {
                                BuildLeaveStateEntry(ilBuilderContext, subGraph.StateEntry);
                            }
                        }
                    }
                }

                EmitDebugExecutionPath(ilBuilderContext, executionPath);

                for (var index = 0; index < executionPath.Nodes.Length; index++)
                {
                    var node = executionPath.Nodes[index];

                    switch (node)
                    {
                    case LeaveStateNode leaveStateNode:
                    {
                        EmitDebugNode(ilBuilderContext, executionPath.PathSourceNode, executionPath);

                        var subGraph = leaveStateNode.SubGraph;

                        if (subGraph.StateEntry != null)
                        {
                            if (IsOverriden(nameof(BuildLeaveStateEntry)))
                            {
                                BuildLeaveStateEntry(ilBuilderContext, subGraph.StateEntry);
                            }
                        }

                        break;
                    }

                    case ActionNode actionNode:
                    {
                        var action = actionNode.ActionEntry.Action;

                        if (action.Target != null)
                        {
                            ilBuilderContext.EmitLdValue(action.Target);
                            ilBuilderContext.EmitLdContext();
                            ilBuilderContext.IL.Emit(OpCodes.Callvirt, action.Method);
                        }
                        else
                        {
                            ilBuilderContext.EmitLdContext();
                            ilBuilderContext.IL.Emit(OpCodes.Call, action.Method);
                        }

                        break;
                    }

                    case BeginStateNode beginStateNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        break;
                    }

                    case BeginProductionNode beginProductionNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        if (IsOverriden(nameof(BuildEnterProduction)))
                        {
                            BuildEnterProduction(ilBuilderContext, beginProductionNode.Production);
                        }

                        break;
                    }

                    case EndProductionNode endProductionNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        if (IsOverriden(nameof(BuildLeaveProduction)))
                        {
                            BuildLeaveProduction(ilBuilderContext, endProductionNode.Production);
                        }

                        break;
                    }

                    case EnterStateNode enterStateNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        var subGraph = enterStateNode.SubGraph;

                        if (IsOverriden(nameof(BuildEnterStateEntry)))
                        {
                            BuildEnterStateEntry(ilBuilderContext, subGraph.StateEntry);
                        }

                        //stack.Push(subGraph);

                        ilBuilderContext.EmitLdStack();
                        ilBuilderContext.IL.Emit(OpCodes.Ldc_I4, subGraph.Id);
                        ilBuilderContext.IL.Emit(OpCodes.Call, PushSafeIdMethodInfo);


                        break;
                    }

                    case InlineEnterStateNode inlineEnterStateNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        var stateEntry = inlineEnterStateNode.StateEntry;

                        if (IsOverriden(nameof(BuildEnterStateEntry)))
                        {
                            BuildEnterStateEntry(ilBuilderContext, stateEntry);
                        }

                        break;
                    }

                    case InlineLeaveStateNode inlineLeaveStateNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        var stateEntry = inlineLeaveStateNode.StateEntry;

                        if (IsOverriden(nameof(BuildLeaveStateEntry)))
                        {
                            BuildLeaveStateEntry(ilBuilderContext, stateEntry);
                        }

                        break;
                    }

                    case OperandNode operandNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        if (IsOverriden(nameof(BuildInvoke)))
                        {
                            BuildInvoke(ilBuilderContext, operandNode.MatchEntry, true);
                        }

                        //_instructionPointer.MoveNext();
                        ilBuilderContext.EmitLdProcess();
                        ilBuilderContext.IL.Emit(OpCodes.Call, MoveNextMethodInfo);

                        break;
                    }

                    case PredicateNode predicateNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        //if (predicate.Predicate.Predicate(Context) == false)
                        //	return null;

                        var returnPredicateLabel = ilBuilderContext.IL.DefineLabel();
                        var callPredicateLabel   = ilBuilderContext.IL.DefineLabel();
                        var predicate            = predicateNode.PredicateEntry;
                        var consumeResult        = predicate.ConsumeResult && IsOverriden(nameof(BuildConsumePredicateResult));
                        var trueLabel            = ilBuilderContext.IL.DefineLabel();
                        var forkLabel            = ilBuilderContext.IL.DefineLabel();
                        var resultLocal          = ilBuilderContext.IL.DeclareLocal(typeof(PredicateResult));

                        ilBuilderContext.EmitLdProcess();
                        ilBuilderContext.IL.Emit(OpCodes.Ldfld, ExecuteThreadQueueFieldInfo);
                        ilBuilderContext.IL.Emit(OpCodes.Brfalse, callPredicateLabel);

                        // Get Result from Process Result Queue
                        if (consumeResult)
                        {
                            // if (predicate.PopResult == false)
                            //   return

                            ilBuilderContext.EmitLdContext();
                            ilBuilderContext.EmitExecutionPath();
                            ilBuilderContext.IL.Emit(OpCodes.Call, ShouldPopPredicateResultMethodInfo);
                            ilBuilderContext.IL.Emit(OpCodes.Brfalse, returnPredicateLabel);

                            ilBuilderContext.EmitLdProcess();
                            ilBuilderContext.IL.Emit(OpCodes.Call, ProcessDequePredicateResultMethodInfo);
                            ilBuilderContext.IL.Emit(OpCodes.Stloc, resultLocal);

                            BuildConsumePredicateResult(ilBuilderContext, resultLocal, predicateNode.PredicateEntry.GetActualPredicateEntry());

                            ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                            ilBuilderContext.IL.Emit(OpCodes.Callvirt, PredicateResultDisposeMethodInfo);
                        }

                        ilBuilderContext.IL.Emit(OpCodes.Br, returnPredicateLabel);

                        ilBuilderContext.IL.MarkLabel(callPredicateLabel);

                        ilBuilderContext.EmitLdContext();
                        ilBuilderContext.EmitExecutionPath();
                        ilBuilderContext.IL.Emit(OpCodes.Call, CallPredicateMethodInfo);

                        ilBuilderContext.IL.Emit(OpCodes.Stloc, resultLocal);
                        ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);

                        ilBuilderContext.IL.Emit(OpCodes.Brtrue, forkLabel);
                        ilBuilderContext.IL.Emit(OpCodes.Ldnull);
                        ilBuilderContext.IL.Emit(OpCodes.Ret);

                        ilBuilderContext.IL.MarkLabel(forkLabel);

                        // ForkPredicate
                        ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                        ilBuilderContext.IL.Emit(OpCodes.Callvirt, PredicateResultIsForkMethodInfo);
                        ilBuilderContext.IL.Emit(OpCodes.Brfalse, trueLabel);
                        ilBuilderContext.EmitLdProcess();
                        ilBuilderContext.IL.Emit(OpCodes.Ldc_I4, index);
                        ilBuilderContext.EmitExecutionPath();
                        ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                        ilBuilderContext.IL.Emit(OpCodes.Call, BuildForkNodeMethodInfo);
                        ilBuilderContext.IL.Emit(OpCodes.Ret);

                        ilBuilderContext.IL.MarkLabel(trueLabel);

                        if (consumeResult)
                        {
                            BuildConsumePredicateResult(ilBuilderContext, resultLocal, predicateNode.PredicateEntry.GetActualPredicateEntry());

                            ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                            ilBuilderContext.IL.Emit(OpCodes.Callvirt, PredicateResultDisposeMethodInfo);
                        }
                        else
                        {
                            ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                            ilBuilderContext.IL.Emit(OpCodes.Callvirt, PredicateResultDisposeMethodInfo);
                        }

                        ilBuilderContext.IL.MarkLabel(returnPredicateLabel);

                        break;
                    }

                    case ReturnStateNode returnStateNode:
                    {
                        EmitDebugNode(ilBuilderContext, node, executionPath);

                        var lastNode       = index == executionPath.Nodes.Length - 1;
                        var leaveNodeLocal = lastNode ? ilBuilderContext.IL.DeclareLocal(typeof(Node)) : null;


                        ilBuilderContext.EmitLdStack();

                        if (lastNode)
                        {
                            ilBuilderContext.IL.Emit(OpCodes.Call, PopSafeNodeMethodInfo);
                            ilBuilderContext.IL.Emit(OpCodes.Stloc, leaveNodeLocal);
                        }
                        else
                        {
                            ilBuilderContext.IL.Emit(OpCodes.Call, PopSafeMethodInfo);
                        }

                        if (lastNode)
                        {
                            ilBuilderContext.IL.Emit(OpCodes.Ldloc, leaveNodeLocal);
                            ilBuilderContext.IL.Emit(OpCodes.Ret);

                            closure = ilBuilderContext.Values.ToArray();

                            return(ilBuilderContext.DynMethod);
                        }

                        break;
                    }
                    }
                }

                ilBuilderContext.EmitLdValue(executionPath.Output);

                ilBuilderContext.IL.Emit(OpCodes.Ret);

                closure = ilBuilderContext.Values.ToArray();

                return(ilBuilderContext.DynMethod);
            }
            private DynamicMethod BuildParallel(ExecutionPath executionPath, out object[] closure)
            {
                var ilBuilderContext = new ILBuilderContext(ContextFieldInfo);

                for (var index = 0; index < executionPath.Nodes.Length; index++)
                {
                    var node = executionPath.Nodes[index];

                    switch (node)
                    {
                    case EnterStateNode enterStateNode:
                    {
                        var subGraph = enterStateNode.SubGraph;

                        //stack.Push(subGraph);
                        ilBuilderContext.EmitLdStack();
                        ilBuilderContext.EmitLdValue(subGraph);
                        ilBuilderContext.IL.Emit(OpCodes.Call, PushMethodInfo);

                        break;
                    }

                    case ActionNode actionNode:
                    {
                        var action = actionNode.ActionEntry.Action;

                        if (action.Target != null)
                        {
                            ilBuilderContext.EmitLdValue(action.Target);
                            ilBuilderContext.EmitLdContext();
                            ilBuilderContext.IL.Emit(OpCodes.Callvirt, action.Method);
                        }
                        else
                        {
                            ilBuilderContext.EmitLdContext();
                            ilBuilderContext.IL.Emit(OpCodes.Call, action.Method);
                        }

                        break;
                    }

                    case OperandNode operandNode:
                    {
                        if (IsOverriden(nameof(BuildInvoke)))
                        {
                            BuildInvoke(ilBuilderContext, operandNode.MatchEntry, false);
                        }

                        //_instructionPointer.MoveNext();
                        ilBuilderContext.EmitLdProcess();
                        ilBuilderContext.IL.Emit(OpCodes.Call, MoveNextMethodInfo);

                        break;
                    }

                    case PredicateNode predicateNode:
                    {
                        //if (predicate.Predicate.Predicate(Context) == false)
                        //	return null;

                        var predicate   = predicateNode.PredicateEntry;
                        var trueLabel   = ilBuilderContext.IL.DefineLabel();
                        var forkLabel   = ilBuilderContext.IL.DefineLabel();
                        var resultLocal = ilBuilderContext.IL.DeclareLocal(typeof(PredicateResult));

                        ilBuilderContext.EmitLdContext();
                        ilBuilderContext.EmitExecutionPath();
                        ilBuilderContext.IL.Emit(OpCodes.Call, CallPredicateMethodInfo);

                        ilBuilderContext.IL.Emit(OpCodes.Stloc, resultLocal);
                        ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);

                        ilBuilderContext.IL.Emit(OpCodes.Brtrue, forkLabel);

                        ilBuilderContext.IL.Emit(OpCodes.Ldnull);
                        ilBuilderContext.IL.Emit(OpCodes.Ret);

                        ilBuilderContext.IL.MarkLabel(forkLabel);

                        // ForkPredicate
                        ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                        ilBuilderContext.IL.Emit(OpCodes.Callvirt, PredicateResultIsForkMethodInfo);
                        ilBuilderContext.IL.Emit(OpCodes.Brfalse, trueLabel);
                        ilBuilderContext.EmitLdProcess();
                        ilBuilderContext.IL.Emit(OpCodes.Ldc_I4, index);
                        ilBuilderContext.EmitExecutionPath();
                        ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                        ilBuilderContext.IL.Emit(OpCodes.Call, BuildForkNodeMethodInfo);
                        ilBuilderContext.IL.Emit(OpCodes.Ret);

                        ilBuilderContext.IL.MarkLabel(trueLabel);

                        if (predicate.ConsumeResult)
                        {
                            ilBuilderContext.EmitLdProcess();
                            ilBuilderContext.IL.Emit(OpCodes.Ldloc, resultLocal);
                            ilBuilderContext.IL.Emit(OpCodes.Call, ProcessEnqueuePredicateResultMethodInfo);
                        }

                        break;
                    }

                    case ReturnStateNode _:
                    {
                        //return stack.Pop().LeaveNode;
                        ilBuilderContext.EmitLdStack();
                        ilBuilderContext.IL.Emit(OpCodes.Call, PopMethodInfo);
                        ilBuilderContext.IL.Emit(OpCodes.Ldfld, LeaveNodeFieldInfo);

                        if (index == executionPath.Nodes.Length - 1)
                        {
                            ilBuilderContext.IL.Emit(OpCodes.Ret);

                            closure = ilBuilderContext.Values.ToArray();

                            return(ilBuilderContext.DynMethod);
                        }

                        ilBuilderContext.IL.Emit(OpCodes.Pop);

                        break;
                    }
                    }
                }

                ilBuilderContext.EmitLdValue(executionPath.Output);

                ilBuilderContext.IL.Emit(OpCodes.Ret);

                closure = ilBuilderContext.Values.ToArray();

                return(ilBuilderContext.DynMethod);
            }