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); }
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); }