public ActionResult <Result> Post([FromBody] Dto dto)
        {
            if (dto == null || string.IsNullOrEmpty(dto.Text))
            {
                return(BadRequest());
            }

            string       add = dto.Text.Last().Equals('\n') ? " " : "\n";
            OuterLexemes lex = _manager.LexicalAnalyzer(dto.Text + add);
            SyntaxResult syn = _manager.SyntaxAnalyzer(lex);

            if (!syn.Success)
            {
                return(new Result
                {
                    OuterLexemes = lex,
                    SyntaxResult = syn,
                    ReferenceNumber = Guid.NewGuid()
                });
            }

            PolishResult polishResult = _polishManager.Run(lex);

            Guid referenceNumber = Guid.NewGuid();

            _cache.Set(referenceNumber, new ExecutionPoint {
                PolishResult = polishResult
            });

            return(new Result
            {
                OuterLexemes = lex,
                SyntaxResult = syn,
                // todo Use AutoMapper
                PolishResult = new PolishResultDto
                {
                    ReversePolishNotation = string.Join(" ", polishResult.ReversePolishNotation.Select(pn => pn.Token)),
                    Trace = polishResult.Trace.Select(t => new PolishTraceDto
                    {
                        Input = t.Input,
                        Stack = string.Join(" | ", t.Stack.Select(pn => pn.Token)),
                        ReversePolishNotation = string.Join(" ", t.ReversePolishNotation.Select(pn => pn.Token))
                    })
                },
                ReferenceNumber = referenceNumber
            });
        }
        public ExecutionResult Run(
            PolishResult polishResult,
            ExecutionPoint executionPoint = default,
            decimal input = default)
        {
            var outputBuilder = new StringBuilder();

            _stack.Clear();
            _declaredIdentifiers.Clear();
            _identifiersValues.Clear();
            int i = 0;

            if (executionPoint != default)
            {
                _stack = executionPoint.Stack;
                _declaredIdentifiers = executionPoint.DeclaredIdentifiers;
                _identifiersValues   = executionPoint.IdentifiersValues;
                i = executionPoint.PolishNotationIndex;

                _stack.Push(input.ToString(CultureInfo.InvariantCulture));
                HandleSet();
            }

            try
            {
                while (i < polishResult.ReversePolishNotation.Count)
                {
                    PolishNotation element = polishResult.ReversePolishNotation[i];

                    switch (element.Type)
                    {
                    case PolishNotationTokenType.Identifier:
                        _stack.Push(_identifiersValues.ContainsKey(element.Token) &&
                                    !element.IsAssignmentToThisIdentifier
                                                                ? _identifiersValues[element.Token].ToString(CultureInfo.InvariantCulture)
                                                                : element.Token); // only for declaration or assignment
                        break;

                    case PolishNotationTokenType.Literal:
                        _stack.Push(element.Token);
                        break;

                    case PolishNotationTokenType.Operator:
                        switch (element.Token)
                        {
                        case "@+":
                        case "@-":
                            HandleArithmeticUnary(element);
                            break;

                        case "+":
                        case "-":
                        case "*":
                        case "/":
                            HandleArithmeticBinary(element);
                            break;

                        case "var":
                            HandleVar();
                            break;

                        case "set":
                            HandleSet();
                            break;

                        case "write":
                            string head = _stack.Pop();
                            if (head.StartsWith("@"))
                            {
                                throw new RuntimeException($"{head} is not declared");
                            }

                            outputBuilder.AppendLine(head.ToString(CultureInfo.InvariantCulture));
                            break;

                        case "read":
                            return(new ExecutionResult
                            {
                                Type = ExecutionResultType.InputRequired,
                                Output = outputBuilder.ToString(),
                                ExecutionPoint = new ExecutionPoint
                                {
                                    PolishNotationIndex = i + 1,
                                    Stack = _stack,
                                    DeclaredIdentifiers = _declaredIdentifiers,
                                    IdentifiersValues = _identifiersValues,
                                    PolishResult = polishResult
                                }
                            });

                        case "equals":
                        case "greaterthn":
                        case "lessthn":
                            HandleConditional(element);
                            break;
                        }
                        break;

                    case PolishNotationTokenType.Delimiter:
                        break;

                    case PolishNotationTokenType.If:
                        break;

                    case PolishNotationTokenType.Then:
                        break;

                    case PolishNotationTokenType.Fi:
                        break;

                    case PolishNotationTokenType.While:
                        break;

                    case PolishNotationTokenType.TechnicalDo:
                        break;

                    case PolishNotationTokenType.Enddo:
                        break;

                    case PolishNotationTokenType.Label:
                        PolishNotation nextElement = polishResult.ReversePolishNotation[i + 1];
                        switch (nextElement.Token)
                        {
                        case "УПХ":
                            bool operand = Convert.ToBoolean(_stack.Pop());
                            if (!operand)
                            {
                                i = polishResult.LabelAddresses[element.Token];
                                continue;
                            }

                            break;

                        case "БП":
                            i = polishResult.LabelAddresses[element.Token];
                            continue;
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    i++;
                }
            }
            catch (RuntimeException e)
            {
                outputBuilder.AppendLine(e.Message);
            }

            return(new ExecutionResult
            {
                Type = ExecutionResultType.Completed,
                Output = outputBuilder.ToString()
            });
        }