private static OperatorResult SetFunc(OperatorOperands operands, BinaryArithmeticInstructionType operatorType)
        {
            //if(!operands.A.Type.Equals(operands.B.Type))
            //return new OperatorResult(new CompileError(CompileErrorType.IncompatibleTypes, operands.A.Token));

            //if(operands.LineItem.Operand1 == null)
            //    return new OperatorResult(new CompileError(CompileErrorType.WrongAssignmentOperation, operands.A.Token));

            if (operands.A.VariableType != VariableType.Variable && operands.A.VariableType != VariableType.ArrayItem)
            {
                return(new OperatorResult(new CompileError(CompileErrorType.WrongAssignmentOperation, operands.A.Token)));
            }

            if (!Type.CanCastAssignment(operands.A.Type, operands.B.Type))
            {
                return(new OperatorResult(new CompileError(CompileErrorType.IncompatibleTypes, operands.A.Token)));
            }

            var casts = new List <InstructionCast>();

            if (operands.B.Type != operands.A.Type)
            {
                var castedB = new Variable(operands.A.Type, "__castedReg", operands.Function.Scope, operands.B.Token,
                                           -1, VariableType.Variable);
                casts.Add(new InstructionCast(
                              castedB, operands.B, operands.Function, operands.ByteCode, operands.Label
                              ));

                operands.B = castedB;
            }

            return(new OperatorResult(new BinaryArithmeticInstruction(operatorType,
                                                                      null, operands.A, operands.B, operands.Function, operands.ByteCode, operands.Label), operands.A.Type, casts));
        }
        private void GetInstructionList(Lexeme rootLexeme, Function function, ref int localVarIndex, ref int regCount, ref int labelIndex,
                                        List <Variable> registers, FunctionInstructions instructionsSet, List <NumeratedVariable> locals)
        {
            foreach (var lexeme in rootLexeme.ChildLexemes)
            {
                //localVarIndex = locals.Count;

                switch (lexeme.Type)
                {
                case LexemeType.Block:
                    break;

                case LexemeType.Var:
                {
                    //Calculate expression
                    var expression = ((VarLexeme)lexeme).Expression;

                    //declaration only
                    if (expression == null)
                    {
                        continue;
                    }

                    var storeResult = locals.Find(p => p.Index ==
                                                  ((VarLexeme)lexeme).Index + Program.ProgramGlobals.Count).Variable;

                    Variable variable;
                    ExpressionToList(expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount,
                                     registers, instructionsSet, locals, storeResult);
                }
                break;

                case LexemeType.If:
                {
                    var ifLexeme = lexeme as IfLexeme;

                    //Calculate expression
                    var      expression = ((IfLexeme)lexeme).Expression;
                    Variable variable;
                    ExpressionToList(expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount,
                                     registers, instructionsSet, locals, null);

                    if (variable == null)
                    {
                        throw new CompileException(CompileErrorType.ExpressionIsNotVariable, lexeme.Tokens[1]);
                    }

                    instructionsSet.Instructions.Add(new InstructionBrEq(variable, -1, function, this, labelIndex++));
                    var eq = instructionsSet.Instructions.Last() as InstructionBrEq;

                    //Proceed block
                    GetInstructionList(ifLexeme.Block, function, ref localVarIndex, ref regCount, ref labelIndex,
                                       registers, instructionsSet, locals);

                    if (ifLexeme.ElseLexeme != null)
                    {
                        instructionsSet.Instructions.Add(new InstructionJmp(-1, function, this, labelIndex++));
                        var jmp = instructionsSet.Instructions.Last() as InstructionJmp;

                        eq.Index = labelIndex;

                        //Proceed else block
                        GetInstructionList(ifLexeme.ElseLexeme.Block, function, ref localVarIndex, ref regCount, ref labelIndex,
                                           registers, instructionsSet, locals);

                        jmp.Index = labelIndex;
                    }
                    else
                    {
                        eq.Index = labelIndex;
                    }
                }
                break;

                case LexemeType.Expression:
                {
                    //Calculate expression
                    Variable variable;
                    ExpressionToList((ExpressionLexeme)lexeme, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount,
                                     registers, instructionsSet, locals, null);
                }
                break;

                case LexemeType.While:
                {
                    var whileLexeme = lexeme as WhileLexeme;
                    int startIndex  = labelIndex;

                    //Calculate expression
                    var      expression = whileLexeme.Expression;
                    Variable variable;
                    ExpressionToList(expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount,
                                     registers, instructionsSet, locals, null);

                    if (variable == null)
                    {
                        throw new CompileException(CompileErrorType.ExpressionIsNotVariable, lexeme.Tokens[1]);
                    }

                    instructionsSet.Instructions.Add(new InstructionBrEq(variable, -1, function, this, labelIndex++));
                    var eq = instructionsSet.Instructions.Last() as InstructionBrEq;

                    //Proceed block
                    GetInstructionList(whileLexeme.Block, function, ref localVarIndex, ref regCount, ref labelIndex,
                                       registers, instructionsSet, locals);

                    instructionsSet.Instructions.Add(
                        new InstructionJmp(startIndex, function, this, labelIndex++));

                    eq.Index = labelIndex;
                }
                break;

                case LexemeType.Return:
                {
                    //Calculate expression
                    Variable variable;
                    ExpressionToList(((ReturnLexeme)lexeme).Expression, lexeme, function, out variable, ref labelIndex, ref localVarIndex, ref regCount,
                                     registers, instructionsSet, locals, null);

                    if (variable.Type != function.ReturnType)
                    {
                        //but can we cast?
                        if (!Type.CanCastAssignment(function.ReturnType, variable.Type))
                        {
                            throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[1]);
                        }

                        //casting
                        var castedVar = new Variable(function.ReturnType, "__castedReg", function.Scope,
                                                     null, localVarIndex++, VariableType.Variable);
                        instructionsSet.Instructions.Add(new InstructionCast(castedVar, variable, function, this,
                                                                             labelIndex++));
                        variable = castedVar;
                        registers.Add(castedVar);
                    }

                    instructionsSet.Instructions.Add(new InstructionPush(variable, function, this, labelIndex++));
                }
                break;
                }
            }
        }
        private void ExpressionToList_GetList(
            ExpressionLexeme expression, Lexeme lexeme, Function function, out Variable resultVar,
            ref int labelIndex, ref int localVarIndex, ref int regCount, List <Variable> outRegisters,
            FunctionInstructions instructionsSet, List <NumeratedVariable> locals, Variable storeResultTo)
        {
            var list           = expression.ToList();
            var labelIndexCopy = labelIndex;

            if (list == null)
            {
                if (expression.Root.SubTokens.Count == 1)
                {
                    ExpressionToken token = expression.Root.SubTokens[0];
                    Variable        src   = ExpressionLineItem.GetVariable(locals, this, token.CodeToken);

                    if (token.UnaryOperators.Count != 0 && token.UnaryOperators[0] != null)
                    {
                        var unaryRes = token.UnaryOperators[0].UnaryFunc(new OperatorOperands(function, this, labelIndexCopy++, src));
                        if (unaryRes.Error != null)
                        {
                            throw new CompileException(unaryRes.Error.ErrorType, token.CodeToken);
                        }

                        instructionsSet.Instructions.Add(unaryRes.Instruction);

                        if (storeResultTo != null)
                        {
                            var lastInstruction = (UnaryArithmeticInstruction)unaryRes.Instruction;
                            if (unaryRes.ResultType != storeResultTo.Type)
                            {
                                //but can we cast?
                                if (!Type.CanCastAssignment(storeResultTo.Type, unaryRes.ResultType))
                                {
                                    throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[0]);
                                }

                                var castedVar = new Variable(unaryRes.ResultType, "__unaryReg", function.Scope,
                                                             null, localVarIndex++, VariableType.Variable);
                                instructionsSet.Instructions.Add(new InstructionCast(storeResultTo, castedVar, function, this,
                                                                                     labelIndexCopy++));

                                lastInstruction.Result = castedVar;
                                outRegisters.Add(castedVar);
                            }
                            else
                            {
                                lastInstruction.Result = storeResultTo;
                            }

                            resultVar = storeResultTo;
                        }
                        else
                        {
                            resultVar = (unaryRes.Instruction as UnaryArithmeticInstruction).Result;
                        }
                    }
                    else
                    {
                        if (storeResultTo != null)
                        {
                            if (storeResultTo.Type != src.Type)
                            {
                                //Not equal, cast is needed.
                                if (!Type.CanCastAssignment(storeResultTo.Type, src.Type))
                                {
                                    throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[0]);
                                }

                                instructionsSet.Instructions.Add(new InstructionCast(storeResultTo, src, function, this, labelIndexCopy++));
                                resultVar = storeResultTo;
                            }
                            else
                            {
                                instructionsSet.Instructions.Add(new InstructionLdi(src, storeResultTo, function, this,
                                                                                    labelIndexCopy++));
                                resultVar = storeResultTo;
                            }
                        }
                        else
                        {
                            resultVar = src;
                        }
                    }
                }
                else
                {
                    throw new CompileException(CompileErrorType.WrongOperandList, lexeme.Tokens[0]);
                }
            }
            else
            {
                if (function.Program.Verbose)
                {
                    Console.WriteLine(string.Join("\n", list));
                }

                List <Variable> registers;
                var             res = ExpressionLineItem.GetInstructions(function, this, ref localVarIndex, list, out registers, locals);

                if (
                    (res.Last() is BinaryArithmeticInstruction) &&
                    ((BinaryArithmeticInstruction)res.Last()).CanBeSimplified() &&
                    (res.Count < 2 || res[res.Count - 2].Type != InstructionType.Vget ||
                     (res.Last() as BinaryArithmeticInstruction).Operand1.VariableType != VariableType.ArrayItem))
                {
                    var last = (BinaryArithmeticInstruction)res.Last();

                    if (last.AType == BinaryArithmeticInstructionType.A_Set && res.Count != 1)
                    {
                        res.RemoveAt(res.Count - 1);
                        (res[res.Count - 1] as ArithmeticInstruction).Result = last.Operand1;
                    }
                    else
                    {
                        res[res.Count - 1] = last.Simplify();
                    }
                    registers.RemoveAt(registers.Count - 1);
                }

                regCount += registers.Count;
                outRegisters.AddRange(registers);

                res.ForEach(p => p.Label = labelIndexCopy++);
                instructionsSet.Instructions.AddRange(res);

                if (storeResultTo != null)
                {
                    if (!(instructionsSet.Instructions.Last() is ArithmeticInstruction))
                    {
                        throw new CompileException(CompileErrorType.ExpressionIsNotVariable, lexeme.Tokens[1]);
                    }

                    var lastInstruction = (ArithmeticInstruction)instructionsSet.Instructions.Last();
                    if (lastInstruction.Result.Type != storeResultTo.Type)
                    {
                        //but can we cast?
                        if (!Type.CanCastAssignment(storeResultTo.Type, lastInstruction.Result.Type))
                        {
                            throw new CompileException(CompileErrorType.IncompatibleTypes, lexeme.Tokens[0]);
                        }

                        instructionsSet.Instructions.Add(new InstructionCast(storeResultTo, lastInstruction.Result, function, this,
                                                                             labelIndexCopy++));
                    }
                    else
                    {
                        lastInstruction.Result = storeResultTo;
                    }
                    resultVar = storeResultTo;
                }
                else
                {
                    var last = instructionsSet.Instructions.Last();

                    if (!(last is ArithmeticInstruction))
                    {
                        resultVar = null;
                    }
                    else
                    {
                        resultVar = (last as ArithmeticInstruction).Result;
                    }
                }
            }

            labelIndex = labelIndexCopy;
        }