public override void Parse(string input, int charIndex) { if (string.IsNullOrWhiteSpace(input)) { throw new AST_EmptyInputException("Provided string is empty", charIndex); } int i = 0; //Read function access level while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function access level", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } if (input.IndexOf("shared", i) == i) { accessLevel = AccessLevel.Shared; i += "shared".Length; } else if (input.IndexOf("private", i) == i) { accessLevel = AccessLevel.Private; i += "private".Length; } else { accessLevel = AccessLevel.Private; } //Read path while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function path", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } if (input[i] != '\"') { throw new AST_BadFormatException("Failed to parse function path", new ArgumentException("Function path not found"), charIndex + i); } int pathStart = i; ++i; while (input[i] != '\"' || input[i - 1] == '\\') { ++i; } path = input.Substring(pathStart + 1, i - pathStart - 1); ++i; //Read function type //TODO - add more function types while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function type", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } if (input.IndexOf("cdecl", i) == i) { functionType = FunctionType.cdecl; i += "cdecl".Length; } else if (input.IndexOf("stdcall", i) == i) { functionType = FunctionType.stdcall; i += "stdcall".Length; } else { throw new AST_BadFormatException("Unknown function format", charIndex + i); } //Read name while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function name", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } if (!(char.IsLetter(input[i]) || AST_Expression.naming_ast.Contains(input[i]))) { throw new AST_BadFormatException("Function name not allowed", new FormatException("Function name should start with a letter or " + AST_Expression.naming_ast), charIndex + i); } string nm = ""; while (char.IsLetterOrDigit(input[i]) || AST_Expression.naming_ast.Contains(input[i])) { nm += input[i]; ++i; if (i >= input.Length) { break; } } name = nm; //Read parameters while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function parameters, return value or code", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } if (input.IndexOf("takes", i) == i) { int end = input.IndexOf("ends", i); if (end == -1) { throw new AST_BadFormatException("Failed to find a corresponding end to parameters start", new FormatException("No corresponding ends for takes"), charIndex + i); } i += "takes".Length; string inputparameters = input.Substring(i, end - i); string[] vars = inputparameters.Split(AST_Program.separator_ast_nospace.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int varStart = i; if (vars.Length > 0) { parameters = new LinkedList <AST_Variable>(); } foreach (string s in vars) { if (!string.IsNullOrWhiteSpace(s)) { parameters.AddLast(new AST_Variable(this, s, charIndex + varStart)); varStart += s.Length; } else { varStart += 1; } } i = end + "ends".Length; } //Read output while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function return value or code", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } if (input.IndexOf("gives", i) == i) { int end = input.IndexOf("ends", i); if (end == -1) { throw new AST_BadFormatException("Failed to find a corresponding end to return value start", new FormatException("No corresponding ends for gives"), charIndex + input.Length - 1); } i += "gives".Length; string inputreturn = input.Substring(i, end - i); string[] outputVars = inputreturn.Split(AST_Program.separator_ast.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (outputVars.Length != 1) { throw new AST_BadFormatException("Too many or too few return values. Try using a structure instead", new FormatException("Wrong return values count. Should be 1"), charIndex + i); } retValue = new AST_Type(this, outputVars[0], charIndex + i + inputreturn.IndexOf(outputVars[0])); i = end + "ends".Length; } //Read expressions while (i < input.Length && AST_Program.separator_ast.Contains(input[i])) { ++i; } if (i >= input.Length) { throw new AST_BadFormatException("Failed to parse function code", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } //TODO - function declarations //TODO - nested ends and does if (input.IndexOf("does", i) == i) { Stack <string> segments = new Stack <string>(); segments.Push("does"); int endsIndex = i + "does".Length; while (segments.Count > 0) { if (input.IndexOf("ends", endsIndex) == endsIndex) { segments.Pop(); if (segments.Count > 0) { endsIndex += "ends".Length; } } else if (input.IndexOf("does", endsIndex) == endsIndex) { segments.Push("does"); endsIndex += "does".Length; } else { endsIndex++; } if (endsIndex >= input.Length) { throw new AST_BadFormatException("Failed to parse function code", new ArgumentOutOfRangeException("input", "Reached the end of input"), charIndex + input.Length - 1); } } //int end = input.IndexOf("ends", i); int end = endsIndex; if (end == -1) { throw new AST_BadFormatException("Failed to find a corresponding end to code start", new FormatException("No corresponding ends for does"), charIndex + i); } if (input.IndexOf(name, end + "ends".Length + 1) == end + "ends".Length + 1) { throw new AST_BadFormatException("Failed to find a corresponding end to code start", new FormatException("No corresponding ends for does"), charIndex + end); } i += "does".Length; string inputcode = input.Substring(i, end - i); string[] exps = Split(inputcode, charIndex);//inputcode.Split(new char[] { ';' }/*, StringSplitOptions.RemoveEmptyEntries*/); if (exps.Length > 0) { expressions = new LinkedList <AST_Expression>(); } int exLength = 0; foreach (string ex in exps) { bool hasActualExpression = false; for (int p = 0; p < ex.Length; ++p) { if (!AST_Program.separator_ast.Contains(ex[p])) { hasActualExpression = true; break; } } if (hasActualExpression) { string nat = ex.Trim(); if (nat.StartsWith("native does") && nat.EndsWith("ends native")) { expressions.AddLast(new AST_Native(this, nat, charIndex + exLength)); } else if (nat.StartsWith("if") && nat.EndsWith("ends if")) { expressions.AddLast(new AST_If(this, nat, charIndex + exLength)); } else if (nat.StartsWith("while") && nat.EndsWith("ends while")) { expressions.AddLast(new AST_While(this, nat, charIndex + exLength)); } else if (nat.StartsWith("for") && nat.EndsWith("ends for")) { expressions.AddLast(new AST_For(this, nat, charIndex + exLength)); } else { //Try to find local variable bool isVariable = false; string[] pieces = nat.Split(AST_Program.separator_ast.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (pieces.Length == 2) { //We may have a variable declaration isVariable = true; try { //Do a simple parameter check beforehand not to waste time just in case var localType = ParameterType.GetParameterType(pieces[0]); AST_LocalVariable localVariable = new AST_LocalVariable(this, nat, charIndex + exLength); expressions.AddLast(localVariable); } catch (Exception) { //It is not isVariable = false; } } if (!isVariable) { //Parse as an expression expressions.AddLast(new AST_Expression(this, ex + ";", charIndex + exLength)); } } } exLength += ex.Length + 1; } i = end + "ends".Length; } else { throw new AST_BadFormatException("Failed to find function code", charIndex + i); } }
public override void Parse(string input, int charIndex) { input = input.Trim(); if (string.IsNullOrWhiteSpace(input)) { throw new AST_EmptyInputException("Provided string is empty", charIndex); } if (!input.StartsWith("if") || !input.EndsWith("ends if")) { throw new AST_EmptyInputException("Provided string is not an if code piece", charIndex); } int insideIndexStart = "if".Length; while (AST_Program.separator_ast.IndexOf(input[insideIndexStart]) != -1) { //We are skipping white-spaces ++insideIndexStart; } if (input[insideIndexStart] != '(') { throw new AST_BadFormatException("Failed to find conditional expression inside if", charIndex + insideIndexStart); } Stack <string> brackets = new Stack <string>(); int insideIndexEnd = insideIndexStart + 1; brackets.Push("("); while (brackets.Count > 0) { if (input[insideIndexEnd] == '(') { brackets.Push("("); insideIndexEnd++; } else if (input[insideIndexEnd] == ')') { if (brackets.Peek() == "(") { brackets.Pop(); insideIndexEnd++; } else { throw new AST_BadFormatException("Failed to parse conditional expression inside if", new AST_BadFormatException("Encountered unexpected tokens in bracket stack", charIndex + insideIndexEnd), charIndex + insideIndexEnd); } } else { insideIndexEnd++; } if (input.Length <= insideIndexEnd) { throw new AST_BadFormatException("Reached end of input while parsing if brackets", charIndex + insideIndexEnd); } } //insideIndexEnd points at closing bracket + 1 string conditionalExpression = input.Substring(insideIndexStart + 1, insideIndexEnd - insideIndexStart - 2); inside = new AST_Expression(this, conditionalExpression + " ;", charIndex + insideIndexStart + 1); int localInput = insideIndexEnd; while (AST_Program.separator_ast.IndexOf(input[localInput]) != -1) { localInput++; } if (input.IndexOf("does", localInput) != localInput) { //We failed to find if body throw new AST_BadFormatException("Conditional statement body was not found", charIndex + localInput); } Stack <string> codeSegments = new Stack <string>(); codeSegments.Push("does"); int codeSegmentStart = localInput; localInput++; while (codeSegments.Count > 0) { if (input.IndexOf("does", localInput) == localInput) { codeSegments.Push("does"); } else if (input.IndexOf("ends", localInput) == localInput) { if (codeSegments.Peek() != "does") { throw new AST_BadFormatException("Failed to parse conditional expression inside if", new AST_BadFormatException("Encountered unexpected tokens in bracket stack", charIndex + localInput), charIndex + localInput); } codeSegments.Pop(); } localInput++; if (input.Length <= localInput && codeSegments.Count > 0) { throw new AST_BadFormatException("Reached end of input while parsing if body", charIndex + localInput); } } //localInput points at letter n from "ends" string codeBody = input.Substring(codeSegmentStart + "does".Length, localInput - 1 - "does".Length - codeSegmentStart); int elseIndex = localInput + "ends".Length; while (AST_Program.separator_ast.IndexOf(input[elseIndex]) != -1 && elseIndex < input.Length) { ++elseIndex; } if (input.IndexOf("if", elseIndex) != elseIndex) { if (input.IndexOf("else", elseIndex) != elseIndex) { throw new AST_BadFormatException("Bad formatting of if statement", elseIndex); } else { //We should parse "else" elseIndex += "else".Length; while (AST_Program.separator_ast_nosemicolon.IndexOf(input[elseIndex]) != -1) { elseIndex++; } if (input.IndexOf("does", elseIndex) != elseIndex) { throw new AST_BadFormatException("Couldn\'t find does part of else", elseIndex); } elseIndex += "does".Length; int doesCount = 1, elseEndsIndex = elseIndex; while (doesCount != 0) { if (input.IndexOf("does", elseEndsIndex) == elseEndsIndex) { doesCount++; elseEndsIndex += "does".Length; } else if (input.IndexOf("ends", elseEndsIndex) == elseEndsIndex) { doesCount--; elseEndsIndex += "ends".Length; } else { elseEndsIndex++; } if (input.Length <= elseEndsIndex && doesCount != 0) { throw new AST_BadFormatException("Reached end of input while parsing else body", charIndex + elseEndsIndex); } } string elseBody = input.Substring(elseIndex, elseEndsIndex - "ends".Length - elseIndex); string[] elseExps = AST_Function.Split(elseBody, charIndex + codeSegmentStart + "does".Length); if (elseExps.Length > 0) { else_expressions = new LinkedList <AST_Expression>(); } int elseExLength = elseIndex; foreach (string ex in elseExps) { bool hasActualExpression = false; for (int p = 0; p < ex.Length; ++p) { if (!AST_Program.separator_ast.Contains(ex[p])) { hasActualExpression = true; break; } } if (hasActualExpression) { string nat = ex.Trim(); if (nat.StartsWith("native does") && nat.EndsWith("native ends")) { else_expressions.AddLast(new AST_Native(this, nat, charIndex + elseExLength)); } else if (nat.StartsWith("if") && nat.EndsWith("ends if")) { else_expressions.AddLast(new AST_If(this, nat, charIndex + elseExLength)); } else if (nat.StartsWith("while") && nat.EndsWith("ends while")) { else_expressions.AddLast(new AST_While(this, nat, charIndex + elseExLength)); } else if (nat.StartsWith("for") && nat.EndsWith("ends for")) { else_expressions.AddLast(new AST_For(this, nat, charIndex + elseExLength)); } else { //Try to find local variable bool isVariable = false; string[] pieces = nat.Split(AST_Program.separator_ast.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (pieces.Length == 2) { //We may have a variable declaration isVariable = true; try { //Do a simple parameter check beforehand not to waste time just in case var localType = CodeBlocks.ParameterType.GetParameterType(pieces[0]); AST_LocalVariable localVariable = new AST_LocalVariable(this, nat, charIndex + elseExLength); else_expressions.AddLast(localVariable); } catch (Exception) { //It is not isVariable = false; } } if (!isVariable) { //Parse as an expression else_expressions.AddLast(new AST_Expression(this, ex + ";", charIndex + elseExLength)); } } } elseExLength += ex.Length + 1; } } } string[] exps = AST_Function.Split(codeBody, charIndex + codeSegmentStart + "does".Length); if (exps.Length > 0) { expressions = new LinkedList <AST_Expression>(); } int exLength = codeSegmentStart + "does".Length; foreach (string ex in exps) { bool hasActualExpression = false; for (int p = 0; p < ex.Length; ++p) { if (!AST_Program.separator_ast.Contains(ex[p])) { hasActualExpression = true; break; } } if (hasActualExpression) { string nat = ex.Trim(); if (nat.StartsWith("native does") && nat.EndsWith("native ends")) { expressions.AddLast(new AST_Native(this, nat, charIndex + exLength)); } else if (nat.StartsWith("if") && nat.EndsWith("ends if")) { expressions.AddLast(new AST_If(this, nat, charIndex + exLength)); } else if (nat.StartsWith("while") && nat.EndsWith("ends while")) { expressions.AddLast(new AST_While(this, nat, charIndex + exLength)); } else if (nat.StartsWith("for") && nat.EndsWith("ends for")) { expressions.AddLast(new AST_For(this, nat, charIndex + exLength)); } else { //Try to find local variable bool isVariable = false; string[] pieces = nat.Split(AST_Program.separator_ast.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (pieces.Length == 2) { //We may have a variable declaration isVariable = true; try { //Do a simple parameter check beforehand not to waste time just in case var localType = CodeBlocks.ParameterType.GetParameterType(pieces[0]); AST_LocalVariable localVariable = new AST_LocalVariable(this, nat, charIndex + exLength); expressions.AddLast(localVariable); } catch (Exception) { //It is not isVariable = false; } } if (!isVariable) { //Parse as an expression expressions.AddLast(new AST_Expression(this, ex + ";", charIndex + exLength)); } } } exLength += ex.Length + 1; } }