// Single-command parser // Rules: // Ends with ; - is a signal where one command ends. public static object Process(string Command) { /* Input examples: * string a = "b"; * bool x = false; * int ttt = 5555; * Test("a", b(5, c(true))); * TODO: * string b = "test"; * string a = b; */ Command = Command.Trim(SpacesAndTabs); // Remove spaces and tabs at the end and start if (!Command.EndsWith(";")) { throw new Exceptions.ParserException("Ending character is not found."); } var CommandType = GetCommandType(Command); if (CommandType == CommandTypes.Unknown) { throw new Exceptions.ParserException("Parser can't understand the type of this command (Unknown)"); } else if (CommandType == CommandTypes.VariableInitializer) { // something like: string a = "b"; /* Rules: * space must split variable type and variable name * = is the signal to start write variable's value and ; is the signal to stop parsing */ var CommandSplit = Command.Split(' '); if (CommandSplit.Length < 1) { throw new Exceptions.VariableInitializerException("Variable type or variable name is not found"); } string VariableType = CommandSplit[0]; string VariableName = ""; string ParsingName = CommandSplit[1]; for (int i = 0; i < ParsingName.Length; i++) { char c = ParsingName[i]; if (c == ';' || c == '=') { break; } foreach (var bad in SpacesAndTabs) { if (c == bad) { break; } } VariableName += c; } if (VariableType.Length <= 0) { throw new Exceptions.VariableInitializerException("Invalid variable type"); } if (VariableName.Length <= 0) { throw new Exceptions.VariableInitializerException("Invalid variable name"); } // Moving on, now we must check for value somehow. // It can be: "bool a;" or "bool a = null" which is null or bool a = true; // So, simply read everything to end. By the rules, there are no more spaces/tabes at the start or between var name/value // so we can get length and start from that point int PositionAfterVarInit = (VariableType + " " + VariableName).Length; if (PositionAfterVarInit > Command.Length) { throw new Exceptions.VariableInitializerException("Something wrong"); } string valueString = ""; bool writeValue = false; for (int i = PositionAfterVarInit; i < Command.Length; i++) { char c = Command[i]; if (c == ';') { break; // stop at ; } if (writeValue) { valueString += c; } if (c == '=') { if (!writeValue) { writeValue = true; } else { throw new Exceptions.VariableInitializerException("Unexpected '='"); } } } valueString = valueString.Trim(SpacesAndTabs); var type = GetCommandType(valueString); if (IsCommandTypeCompatibleWith(type, CommandTypes.Method)) { // something like: string a = Return("a"); var invokeType = GetCompatibleTypeByName(VariableType); if (VariableType != "var" && invokeType == null) { throw new Exceptions.VariableSetException($"Type {VariableType} is not compatible with ESCRIPT"); } var invokeResult = Cmd.Process(valueString + ";", false); if (invokeResult != null && VariableType != "var" && invokeResult.GetType() != invokeType.Type) { throw new Exceptions.VariableSetException($"{invokeType.Name} expected, but {invokeResult.GetType().Name} received"); } Variables.SetVariableObject(VariableName, invokeResult); return(new ParseResult(ParseResult.ParserNativeResults.ParserNativeOK, "VariableInitialzer, value is Method-compatible")); } else if (type == CommandTypes.CastValue) { // something like: IntPtr x = (IntPtr)5; var invokeType = GetCompatibleTypeByName(VariableType); if (VariableType != "var" && invokeType == null) { throw new Exceptions.VariableSetException($"Type {VariableType} is not compatible with ESCRIPT"); } var invokeResult = ConvertStringToVar(valueString); if (invokeResult != null && VariableType != "var" && invokeResult.GetType() != invokeType.Type) { throw new Exceptions.VariableSetException($"{invokeType.Name} expected, but {invokeResult.GetType().Name} received"); } Variables.SetVariableObject(VariableName, invokeResult); return(new ParseResult(ParseResult.ParserNativeResults.ParserNativeOK, "VariableInitialzer, value is cast")); } else { // something like: string a = "a"; return(VariableSetValueHandler(VariableType, VariableName, valueString)); } } else if (CommandType == CommandTypes.VariableSet) { // something like: a = true; /* Rules: * = must split variable name and variable value */ // I'm lazy, so temporary solution is to add "var" to the start: return(Process("var " + Command)); #if NOT_LAZY_AUTHOR // TODO string VariableName = Command.Split('=')[0].Trim(SpacesAndTabs); string valueString = ""; bool writeValue = false; for (int i = VariableName.Length; i < Command.Length; i++) { char c = Command[i]; if (c == ';') { break; // stop at ; } if (writeValue) { valueString += c; } if (c == '=') { if (!writeValue) { writeValue = true; } else { throw new Exceptions.VariableInitializerException("Unexpected '='"); } } } valueString = valueString.Trim(SpacesAndTabs); if (valueString.Length == 0) { throw new Exceptions.VariableSetException("Value is not found"); } for (int i = 0; i < Variables.VarList.Count; i++) { var var = Variables.VarList[i]; if (var.Name == VariableName) { return(VariableSetValueHandler(var.Value.GetType().Name, VariableName, valueString)); } } throw new Exceptions.VariableSetException($"Variable {VariableName} is not found"); #endif } else if (CommandType == CommandTypes.Typeof) { // rules: /* * arguments container with only one value which is Class name * returns Type of value */ string ClassName = ""; // Check for CAST string CastTo = CheckForCast(Command); var Pair = ConvertStringToArgumentsContainer(Command); ClassName = Pair.Value; foreach (var t in CompatibleTypes) { if (t.Names.Contains(ClassName)) { return(t.Type); } } throw new Exception($"Class '{ClassName}' not found."); } else if (CommandType == CommandTypes.Method) { // something like: Test(); Test(true); Test("a", 2); Test("a", 2, GetTrue()); /* Rules: * Arguments container must be started with ( and ended with ) */ // First of all, we need to split arguments containt and method name: string MethodName = ""; string ArgumentsContainer = ""; // Check for CAST string CastTo = CheckForCast(Command); var Pair = ConvertStringToArgumentsContainer(Command); MethodName = Pair.Key; ArgumentsContainer = Pair.Value; if (MethodName.Length <= 0) { throw new Exceptions.ParserException("Invalid method name"); } // This method must resolve invokes inside of a container and convert it to an array object[] Args = StaticArgsToArray(ArgumentsContainer); List <object> FutureArguments = new List <object>(); foreach (var argument in Args) { // unknown argument type is string by default if (argument != null) { if (argument.GetType() == typeof(string)) { FutureArguments.Add(ConvertStringToVar((string)argument)); } else { FutureArguments.Add(argument); } } else { throw new NullReferenceException("Argument is null for some reason :/"); } } var invokeResult = Cmd.InvokeMethod(MethodName, FutureArguments.ToArray()); if (CastTo.Length >= 1) { if (invokeResult == null) { throw new NullReferenceException($"Trying to cast method's result to {CastTo}, but result is null"); } invokeResult = ConvertStringToVar($"({CastTo}){CommandNormalizer.ConvertObjectToStringCode(invokeResult)}"); } return(invokeResult); } else if (CommandType == CommandTypes.UsingHeader) { string Namespace = ""; string NamespaceOriginal = Command.Split(' ')[1].Trim(SpacesAndTabs); for (int i = 0; i < NamespaceOriginal.Length; i++) { char c = NamespaceOriginal[i]; if (c == ';') { break; } Namespace += c; } Namespace = Namespace.Trim(SpacesAndTabs); if (Namespace.Length <= 0) { throw new Exceptions.ParserException($"Namespace is invalid"); } EnvironmentManager.AddNamespace(Namespace); return(new ParseResult(ParseResult.ParserNativeResults.ParserNativeOK, $"Namespace '{Namespace}' imported")); } else if (CommandType == CommandTypes.ObjectInitializer) { /* RULES: * Type name is after "new " (4 len) * Contains argument container! */ string TypeName = ""; string ArgumentsContainer = ""; // Check for CAST string CastTo = CheckForCast(Command); var Pair = ConvertStringToArgumentsContainer(Command); TypeName = Pair.Key.Remove(0, 4); // remove from string starting "new " (4 chars) ArgumentsContainer = Pair.Value; if (TypeName.Length <= 0) { throw new Exceptions.ParserException("Invalid type name"); } // This method must resolve invokes inside of a container and convert it to an array object[] Args = StaticArgsToArray(ArgumentsContainer); List <object> FutureArguments = new List <object>(); foreach (var argument in Args) { // unknown argument type is string by default if (argument != null) { if (argument.GetType() == typeof(string)) { FutureArguments.Add(ConvertStringToVar((string)argument)); } else { FutureArguments.Add(argument); } } else { throw new NullReferenceException("Argument is null for some reason :/"); } } var invokeResult = Cmd.CreateInstance(TypeName, FutureArguments.ToArray()); if (CastTo.Length >= 1) { if (invokeResult == null) { throw new NullReferenceException($"Trying to cast {invokeResult.GetType().Name} to {CastTo}, but result is null"); } invokeResult = ConvertStringToVar($"({CastTo}){CommandNormalizer.ConvertObjectToStringCode(invokeResult)}"); } return(invokeResult); } else { throw new NotImplementedException("Type " + CommandType.GetType().Name + "." + CommandType.ToString() + " is not implemented!!!"); } }