/// <summary>
 /// Initialize a new instance of <see cref="BlockInterpreter"/>
 /// </summary>
 /// <param name="statements">the list of statements to interpret</param>
 /// <param name="debugMode">defines is the debug mode is enabled or not</param>
 /// <param name="parentProgramInterpreter">the parent program interpreter</param>
 /// <param name="parentMethodInterpreter">the parent method interpreter</param>
 /// <param name="parentBlockInterpreter">the parent block interpreter</param>
 /// <param name="parentClassInterpreter">the parent class interpreter</param>
 internal BlockInterpreter(AlgorithmStatementCollection statements, bool debugMode, ProgramInterpreter parentProgramInterpreter, MethodInterpreter parentMethodInterpreter, BlockInterpreter parentBlockInterpreter, ClassInterpreter parentClassInterpreter)
     : base(debugMode)
 {
     ParentProgramInterpreter = parentProgramInterpreter;
     ParentMethodInterpreter  = parentMethodInterpreter;
     ParentBlockInterpreter   = parentBlockInterpreter;
     ParentClassInterpreter   = parentClassInterpreter;
     Statements = statements;
 }
        /// <summary>
        /// Execute a method in the current thread
        /// </summary>
        /// <param name="argumentValues">the list of argument values</param>
        /// <param name="stackTraceId">the user stack trace id</param>
        /// <param name="mustClearStackAtTheEnd">defines if the user call stack must be cleared at the end of this call</param>
        private void RunSync(IReadOnlyList <object> argumentValues, Guid stackTraceId, bool mustClearStackAtTheEnd)
        {
            if (_callStackService.StackTraceCallCount.ContainsKey(stackTraceId))
            {
                if (_callStackService.StackTraceCallCount[stackTraceId] > Consts.CallStackSize)
                {
                    ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new StackOverflowException($"You called too many (more than {Consts.CallStackSize}) methods in the same thread.")), GetParentInterpreter().GetDebugInfo()));
                    return;
                }
                ++_callStackService.StackTraceCallCount[stackTraceId];
            }
            else
            {
                _callStackService.StackTraceCallCount.Add(stackTraceId, 0);
                if (DebugMode)
                {
                    _callStackService.CallStacks.Add(new CallStack(stackTraceId));
                }
            }

            StacktraceId = stackTraceId;
            if (DebugMode)
            {
                var classReference = new AlgorithmClassReferenceExpression(ParentClassInterpreter.ClassDeclaration.Name.ToString());
                var callStack      = _callStackService.CallStacks.Single(cs => cs.TaceId == stackTraceId);
                var arguments      = new List <AlgorithmExpression>();
                foreach (var argumentValue in argumentValues)
                {
                    arguments.Add(new AlgorithmPrimitiveExpression(argumentValue));
                }
                var call = new Call(classReference, new AlgorithmInvokeMethodExpression(classReference, MethodDeclaration._name.ToString(), arguments.ToArray()));
                callStack.Stack.Push(call);
            }

            var block = new BlockInterpreter(MethodDeclaration._statements, DebugMode, ParentProgramInterpreter, this, null, ParentClassInterpreter);

            block.OnGetParentInterpreter += new Func <MethodInterpreter>(() => this);
            block.StateChanged           += ChangeState;
            block.Initialize();

            for (var i = 0; i < MethodDeclaration._arguments.Count; i++)
            {
                var argDecl  = MethodDeclaration._arguments[i];
                var argValue = argumentValues[i];

                if (!(argValue is string) && argValue is IList && !argDecl.IsArray)
                {
                    ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new BadArgumentException(argDecl.Name.ToString(), $"The argument's value '{argDecl.Name}' must not be an array of values."), MethodDeclaration), GetParentInterpreter().GetDebugInfo()));
                    return;
                }
                if ((!(argValue is IList) || argValue is string) && argDecl.IsArray)
                {
                    ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(new BadArgumentException(argDecl.Name.ToString(), $"The argument's value '{argDecl.Name}' must be an array of values."), MethodDeclaration), GetParentInterpreter().GetDebugInfo()));
                    return;
                }

                block.AddVariable(argDecl, argValue, true);
            }

            if (FailedOrStop)
            {
                return;
            }

            // try
            // {
            block.Run();
            // }
            // catch (Exception ex)
            // {
            //     ChangeState(this, new AlgorithmInterpreterStateEventArgs(new Error(ex, MethodDeclaration), GetDebugInfo()));
            //     return;
            // }
            // finally
            // {
            block.StateChanged -= ChangeState;
            block.Dispose();
            //  }


            if (mustClearStackAtTheEnd)
            {
                _callStackService.StackTraceCallCount.Remove(stackTraceId);
            }

            if (DebugMode && !Failed)
            {
                if (mustClearStackAtTheEnd)
                {
                    _callStackService.CallStacks.Remove(_callStackService.CallStacks.Single(callStack => callStack.TaceId == stackTraceId));
                }
                else
                {
                    _callStackService.CallStacks.Single(callStack => callStack.TaceId == stackTraceId).Stack.Pop();
                }
            }



            Done = true;
            OnDone(this);
        }