public static object GetObjectFromString(int line, string str, QType type, Dictionary <string, Variable> globals = null, Dictionary <string, Variable> variables = null) { if (str.Length == 0) { throw new ParseFailException(line, "Invalid empty object"); } switch (type) { case QType.Bool: { if (str == "true") { return((object)true); } if (str == "false") { return((object)false); } if (!IsValid.Identifier(str)) { throw new ParseFailException(line, "Invalid identifier used as bool"); } else { Variable var = GetVariableFromString(line, str, globals, variables); if (var.type == QType.Bool) { return(var.obj); } else { throw new ParseFailException(line, "Variable " + str + " is not bool"); } } } case QType.String: { if (str.StartsWith("\"") && str.EndsWith("\"")) { return((object)str.Substring(1, str.Length - 2)); } else { Variable var = GetVariableFromString(line, str, globals, variables); if (var.type == QType.String) { return(var.obj); } else { throw new ParseFailException(line, "Variable " + str + " is not string"); } } } case QType.Int: { if (str[0] <= '9' && str[0] >= '0') { //return (object)int.Parse(str); if (str.Length < 2) { return(int.Parse(str)); } else { if (str[0] != '0') { return(int.Parse(str)); } else { if (str[1] == 'x' || str[1] == 'X') { // hexadecimal digits are 0-9, a-f/A-F // we should be able to get away with just a return(int.Parse(str.Substring(2), NumberStyles.HexNumber)); } else { // octal representation is 012, which is 10 in decimal // C would use octal if 0 prefix is used string octals = str.Substring(1); int result = 0; foreach (char c in octals) { if (c < '0' || c >= '8') { throw new ParseFailException(line, c + " is not a valid digit in octal!"); } result = result * 8 + (c - '0'); } return(result); } } } } else { Variable var = GetVariableFromString(line, str, globals, variables); if (var.type == QType.Int) { return(var.obj); } else { throw new ParseFailException(line, "Variable " + str + " is not int"); } } } } return(null); }
public static List <Function> GetFunctions(string code) { List <Function> functions = new List <Function>(); // Each function has a start and an end. The function officially starts // with a start_function thing, but it can also prepend arguments and return type. Function currentFunction = new Function(); eFunctionScope currentScope = eFunctionScope.None; List <string> lines = code.Split('\n').ToList(); //Console.WriteLine("[DEBUG] Pass 1: getting functions"); for (int i = 0; i < lines.Count; i++) { // Ignore lines that start with a // string line = lines[i].TrimStart(' ').TrimEnd(' '); if (line.StartsWith("//")) { continue; } if (line.StartsWith("function_args_start")) { if (currentScope == eFunctionScope.None) { currentScope = eFunctionScope.Argument; currentFunction.functionArguments.Clear(); } else { throw new ParseFailException(i, "Bad function_args_start inside another scope (duplicate?)"); } } else if (line.StartsWith("start_function")) { if (currentScope == eFunctionScope.None) { currentScope = eFunctionScope.Main; currentFunction.lines.Clear(); // get the name string[] split = line.Split('|'); if (split.Length > 2) { throw new ParseFailException(i, "Too many arguments to start_function!"); } if (split.Length < 2) { throw new ParseFailException(i, "Name needs to be provided (usage: \"start_function|<your name>\")"); } string name = split[1]; if (!IsValid.Identifier(name)) { throw new ParseFailException(i, "Invalid function name"); } currentFunction.name = name; //Console.WriteLine($"[DEBUG] Found function: {name}"); } else { throw new ParseFailException(i, "Bad start_function inside another scope (duplicate?)"); } } else if (line.StartsWith("function_args_end")) { if (currentScope == eFunctionScope.Argument) { currentScope = eFunctionScope.None; } else { throw new ParseFailException(i, "Bad argument end marker without a scope (duplicate line?)"); } } else if (line.StartsWith("end_function")) { if (currentScope == eFunctionScope.Main) { currentScope = eFunctionScope.None; functions.Add(currentFunction); currentFunction = new Function(); } else { throw new ParseFailException(i, "Bad function end marker without a scope (duplicate line?)"); } } else { switch (currentScope) { case eFunctionScope.Argument: { if (line.StartsWith("func_arg")) { string[] split = line.Split('|'); if (split.Length > 3) { throw new ParseFailException(i, "Too many arguments to return_value_type!"); } if (split.Length < 2) { throw new ParseFailException(i, "Argument type missing"); } if (split.Length < 3) { throw new ParseFailException(i, "Argument name missing"); } //currentFunction.returnType = Misc.GetTypeFromString(i, split[1]); currentFunction.functionArguments.Add(new Argument() { argName = split[2], argType = Misc.GetTypeFromString(i, split[1]) }); } break; } case eFunctionScope.Main: { if (string.IsNullOrWhiteSpace(line)) { continue; } currentFunction.lines.Add(line); break; } case eFunctionScope.None: { if (line.StartsWith("return_value_type")) { if (currentFunction.returnType == QType.Void) { string[] split = line.Split('|'); if (split.Length > 2) { throw new ParseFailException(i, "Too many arguments to return_value_type!"); } if (split.Length < 2) { throw new ParseFailException(i, "Name needs to be provided (usage: \"return_value_type|<type: string/s/str/bool/boolean/b/integer/int/int32/i32/i>\")"); } currentFunction.returnType = Misc.GetTypeFromString(i, split[1]); } } break; } } } } return(functions); }