private NovelScript ParseScript(NovelScript script, NovelParserBlock block, ParentBlockType parentType, int nestLevel)
        {
            if (parentType == ParentBlockType.Function)
            {
                ContainsUserReturn = false;
            }

            //Prepeare variable scope
            Variables.AddScope();


            //For each content in block
            for (int i = 0; i < block.Content.Count(); i++)
            {
                //Get the phrase
                var phrase = block.Content[i];

                //Setting up the line for debbugging purposes
                ParsedLine = phrase.CodeLine;

                //If its another block
                if (phrase is NovelParserBlock)
                {
                    var localBlock = phrase as NovelParserBlock;
                    var header     = localBlock.Header;

                    //If header is the function signature
                    if (IsFunctionSignature(header))
                    {
                        //If the function signatures are nested
                        if (parentType != ParentBlockType.StartBlock)
                        {
                            throw new NovelException("Function signatures cannot be nested", ParsedFile, ParsedLine);
                        }

                        //Get the function object
                        var function = ParseFunctionSignature(header, script.Instructions.Count);

                        //Add function to list
                        script.FunctionList.Add(function);

                        Variables.AddScope();
                        //Add arguments to stack
                        for (int j = 0; j < function.ParameterNameList.Count; j++)
                        {
                            Variables.AddVaraible(function.ParameterNameList[j]);
                        }

                        //Parse the local block
                        script = ParseScript(script, localBlock, ParentBlockType.Function, nestLevel + 1);
                        Variables.RemoveScope();
                    }
                    //If header indicates that this is condition start
                    else if (IsCondition(header))
                    {
                        //Check if condition is inside function block or another condition block
                        if (parentType != ParentBlockType.Function &&
                            parentType != ParentBlockType.Condition)
                        {
                            throw new NovelException("Condition has to be in function", ParsedFile, ParsedLine);
                        }

                        //Getting the condition level
                        int conditionLevel = -1;

                        List <NovelInstruction> instructions = new List <NovelInstruction>();

                        //Get the novel condition
                        var condition = ParseCondition(header, out conditionLevel, ref instructions);

                        //TODO check boolean type compatibility
                        //Check if the last term element is logical type
                        //var terms = condition.Expression.Term;
                        //var lastTerm = terms[terms.Count - 1];

                        //if( !(lastTerm is NovelLogicOperator) )
                        //    throw new NovelException("Condition does not contain logic expression", ParsedFile, ParsedLine);

                        //Getting last type of condition (if, else if, else)
                        int lastLevel = Conditions.GetLastConditionLevel(nestLevel);

                        //Check if the upcoming condition is higher than
                        //those in condition scope, or if those are else if
                        if (conditionLevel > lastLevel || (conditionLevel == 1 && lastLevel == 1))
                        {
                            //If lastLevel is "If" or "Else if" then
                            if (lastLevel == 0 || lastLevel == 1)
                            {
                                script.Instructions.Add(new NovelJump());
                            }

                            int firstInstruction = script.Instructions.Count;

                            foreach (var inst in instructions)
                            {
                                script.Instructions.Add(inst);
                            }

                            Conditions.AddCondition(nestLevel, firstInstruction,
                                                    script.Instructions.Count, conditionLevel,
                                                    ConditionScope.ConditionType.Normal);

                            script.Instructions.Add(condition);
                        }
                        else
                        {
                            throw new NovelException("Invalid type of conditional instruction in this context", ParsedFile, ParsedLine);
                        }

                        ParsedScript = ParseScript(script, localBlock, ParentBlockType.Condition, nestLevel + 1);
                    }
                    //If header indicates that this is a loop
                    else if (IsWhileLoop(header))
                    {
                        //Check if condition is inside function block or another condition block
                        if (parentType != ParentBlockType.Function &&
                            parentType != ParentBlockType.Condition)
                        {
                            throw new NovelException("Condition has to be in function", ParsedFile, ParsedLine);
                        }

                        List <NovelInstruction> instructions = new List <NovelInstruction>();
                        var condition = ParseWhileLoop(header, ref instructions);

                        //Get the index of where the local variables for condition start
                        int firstInstructionOfCndIndex = script.Instructions.Count;

                        //Add all instructions
                        foreach (var instruction in instructions)
                        {
                            script.Instructions.Add(instruction);
                        }

                        //Add stuff to condition scope
                        Conditions.AddCondition(nestLevel, firstInstructionOfCndIndex,
                                                script.Instructions.Count, 1,
                                                ConditionScope.ConditionType.Loop);

                        //Add condition at the end
                        script.Instructions.Add(condition);
                        ParsedScript = ParseScript(script, localBlock, ParentBlockType.Condition, nestLevel + 1);
                    }
                }
                //Or if its a plain text
                else if (phrase is NovelParserText)
                {
                    //If condition scope contains
                    if (Conditions.GetLastConditionLevel(nestLevel) > -1)
                    {
                        UpdateConditions(nestLevel);
                    }

                    var localText   = phrase as NovelParserText;
                    var instruction = localText.Instruction;

                    //If is assignment expression
                    //if (IsAssigment(instruction))
                    //{
                    //    //Parse assignment (supports initialization)
                    //    var instructions = ParseAssignment(instruction);
                    //    foreach (var inst in instructions)
                    //        script.Instructions.Add(inst);
                    //}
                    if (IsReturn(instruction))
                    {
                        var instructions = ParseReturn(instruction);
                        foreach (var inst in instructions)
                        {
                            script.Instructions.Add(inst);
                        }

                        ContainsUserReturn = true;
                    }
                    //If its other kind of expression
                    else
                    {
                        //Parse expression (supports initialization)
                        var instructions = ParseExpression(instruction);
                        foreach (var inst in instructions)
                        {
                            script.Instructions.Add(inst);
                        }
                    }
                }

                //TODO find a better way to this
                //Now we have to handle returning values
                //If the last instruction of this block isn't the return value then return default
            }

            //If the end of the block then end condition
            UpdateConditions(nestLevel);

            //Return value should cause local variables to unstack
            if (parentType == ParentBlockType.Function)
            {
                //If contains returns in function but last instruction is not a return
                if (ContainsUserReturn == true && !(script.Instructions[script.Instructions.Count() - 1] is NovelReturn))
                {
                    throw new NovelException("Function does not return a value.", ParsedFile, ParsedLine);
                }
                //If last instruction isn't return
                else if (!(script.Instructions[script.Instructions.Count() - 1] is NovelReturn))
                {
                    script.Instructions.Add(new NovelReturn(new NovelExpressionLiteral((int)0)));
                }
            }
            //No return so manual unstacking
            else
            {
                //Unstack local variables
                var stackVars = Variables.GetScopeStackVariablesCount();
                if (stackVars > 0)
                {
                    foreach (var v in Variables.GetScopeStackVariables())
                    {
                        Console.WriteLine(v);
                    }

                    script.Instructions.Add(new NovelExpandStack(-stackVars));
                }
            }

            //Remove scope before return
            Variables.RemoveScope();

            return(script);
        }