Ejemplo n.º 1
0
        public NovelScript ParseText(string fileName, string scriptCode, NovelFunctionPool funcPool = null)
        {
            //Setup variables
            CharacterPointer = 0;

            //Setting up parsed text
            ParsedText = scriptCode;

            //Setting up parsed file name
            ParsedFile = fileName;

            //Setting up parsedline
            ParsedLine = -1;

            //Main block of grouped code
            var mainBlock = new NovelParserBlock();

            //For reading purposes
            int endIndex           = 0;
            NovelParserBlock block = null;

            //Read all the blocks in file
            while ((block = ReadBlock(scriptCode, endIndex, out endIndex)) != null)
            {
                mainBlock.Content.Add(block);
            }

            return(ParseScript(fileName, mainBlock, funcPool));
        }
        private NovelScript ParseScript(string name, NovelParserBlock block, NovelFunctionPool funcPool = null)
        {
            //Setup script
            ParsedScript = new NovelScript(name);
            ParsedScript.DelegateFunctionList = funcPool;

            try
            {
                ParsedScript = ParseScript(ParsedScript, block, ParentBlockType.StartBlock, 0);
            }
            catch (NovelException exception)
            {
                //TODO remove
                //Print the exception
                Console.WriteLine(exception.Message);
            }

            return(ParsedScript);
        }
        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);
        }
Ejemplo n.º 4
0
        private NovelParserBlock ReadBlock(string text, int startIndex, out int endIndex)
        {
            //Name of block header
            string blockHeader = "";

            //Create block
            NovelParserBlock block = new NovelParserBlock();

            //Setting up the end index
            endIndex = -1;

            //Found the block
            bool isBlockFound = false;

            var line = "";

            for (int i = startIndex; i < text.Length; i++)
            {
                if (text[i].Equals('{') && !isBlockFound == true)
                {
                    //Read the block header going back from index i to }, SOF, ;
                    blockHeader = StringUtils.GetBackwardsUntil(text, i - 1, new char[] { '}', ';', '{' });

                    //Clean block header
                    block.Header = NovelParserBlock.CleanHeader(blockHeader).Trim();

                    //Getting the block size
                    var tempEnd = -1;

                    //Setting up the character number including {} in this block
                    block.CharacterCount = ReadBlockContent(text, i, out tempEnd).Length + 2;

                    //Set the block line in code
                    block.CodeLine = StringUtils.FindCount(text, 0, text.LastIndexOf(')', i), '\n') + 1;

                    //Set the flag
                    isBlockFound = true;
                }

                //Main block found
                else if (isBlockFound)
                {
                    //Add line to list
                    if (text[i] == ';')
                    {
                        block.Content.Add(new NovelParserText(StringUtils.RefactorWhiteSpaces(line), StringUtils.FindCount(text, 0, i, '\n') + 1));
                        //Reset line
                        line = "";
                    }
                    //If end of block then return it
                    else if (text[i] == '}')
                    {
                        endIndex = i;
                        return(block);
                    }
                    //Add character to line buffer
                    else if (text[i] != '{')
                    {
                        line += text[i];
                    }
                    //Internal block found
                    else if (text[i] == '{')
                    {
                        //Read the internal block if found
                        int tempVal       = -1;
                        var internalBlock = ReadBlock(text, i, out tempVal);

                        //Add internal block to main block
                        block.Content.Add(internalBlock);

                        //Move pointer by number of characters in internal block
                        i += internalBlock.CharacterCount;

                        //Reset line
                        line = "";
                    }
                }
            }
            return(null);
        }