public static int maxCommandLength = 50; //This is the maximum length of commands interpreted with this class. THis prevents locking up Unity /*! * Interpret a command * */ public static MethodicalObject MakeChain(MonoBehaviour behaviour, string command) { safetyIndex = 0; //resetting the safety index since we're starting a new interpretation MethodicalObject chain = Interpret(behaviour, null, command); PrintChain(chain); return(chain); }
//************************** Utility methods **************************// #region Utility Methods private static void PrintChain(MethodicalObject chain) { string printedLine = ""; foreach (MethodicalObject mo in chain) { printedLine = printedLine + "=>" + mo.objectName; } //Debug.Log(printedLine); }
/*! * Processes a method into a chunk. * baseObject is the preprocessed chunk. Expects an objectname and objecttype to already be set. * */ private static MethodicalObject ProcessMethodChunk(object context, MethodicalObject baseObject, string commandString) { string argumentsString = GetNextArgumentsString(commandString); List <string> args = SplitArguments(argumentsString); foreach (string argument in args) { baseObject.arguments.Add(Interpret(context, null, argument)); } return(baseObject); }
/*! * Recursively loop through command creating a data chain. * */ private static MethodicalObject Interpret(object context, MethodicalObject chain, string command) { if (!validate(command)) { return(new MethodicalErrorObject("", MethodicalErrorObject.ERRORTYPES.UnsupportedUsage)); } //Doing some safety stuff to make sure I don't lock up Unity in an infinite loop if (safetyIndex > maxCommandLength) { return(null); //TODO Make this return an error to the user. } safetyIndex++; //getting the next chunk MethodicalObject chunk = GetNextChunk(context, command); if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.equalityType)) { //I can safely assume this is the first call of interpret chunk.leftEquality = Interpret(context, null, chunk.leftEqualityString); chunk.rightEquality = Interpret(context, null, chunk.rightEqualityString); return(chunk); } else { //going to shorten the command so the next chunk starts at the first character command = TruncateCommand(chunk, command); command = TrimPeriods(command); if (chain == null) //starting chain if it isn't initiated, otherwise adding to chain { chain = chunk; } else { chain.AppendToChain(chunk); } //if there are any chunks left if (command != "") { return(Interpret(context, chain, command)); } return(chain); } }
/*! * Takes in the latest chunk and the command string. Prepares the command string to retrieve the next chunk * */ public static string TruncateCommand(MethodicalObject chunk, string command) { //trimming the string! int trimLength = 0; if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.arrayType)) { trimLength = command.IndexOf("]") + 1; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.boolType)) { trimLength = chunk.value.ToString().Length; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.floatType) || chunk.objectType.Equals(MethodicalObject.ObjectTypes.DoubleType)) { trimLength = chunk.value.ToString().Length + 1; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.hashMapType)) { trimLength = command.IndexOf("]") + 1; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.intType)) { trimLength = chunk.objectName.Length; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.methodType)) { string filterString = "(?<=\".*)[\\(\\),](?=.*\")"; string fixedString = ReplaceMatch(filterString, command, " "); int startParen = fixedString.IndexOf("("); int lastParen = GetClosingParen(startParen, fixedString); trimLength = lastParen + 1; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.stringType)) { trimLength = chunk.value.ToString().Length + 2; } else if (chunk.objectType.Equals(MethodicalObject.ObjectTypes.variableType)) { trimLength = chunk.objectName.Length; } command = command.Substring(trimLength, command.Length - trimLength); return(command); }
public static object execute(MethodicalObject chain) { object newValue = null; if (chain != null && chain.objectType.Equals(MethodicalObject.ObjectTypes.equalityType)) { newValue = execute(chain.rightEquality); return(execute(chain.leftEquality, newValue)); } else { MethodicalObject currentLink = chain; object lastReturn = root; if (isStatic) { if (currentLink.passesByValue) { lastReturn = currentLink.value; } else { lastReturn = GetFromClass(root, staticRoot, lastReturn, currentLink); currentLink = currentLink.member; } } while (currentLink != null && lastReturn != null) { if (currentLink.passesByValue) { lastReturn = currentLink.value; } else if (ExistsInClass(lastReturn, currentLink.objectName)) { lastReturn = GetFromClass(root, staticRoot, lastReturn, currentLink); } else { return(new MethodicalErrorObject(currentLink.objectName, MethodicalErrorObject.ERRORTYPES.DoesNotExist)); } currentLink = currentLink.member; } return(lastReturn); } }
/*! * Calls commands to the selected monobehaviour using invoke * * */ private void CallCommand() { if (go == null) { //display.Insert(0,new MethodicalMessage("No monobehavior selected!",MethodicalMessage.MessageTypes.Error)); //return; } if (command.Equals("")) { display.Insert(0, new MethodicalMessage("No command entered!", MethodicalMessage.MessageTypes.Error)); return; } commandCalled = true; MethodicalExecutor.isStatic = staticMode; MethodicalExecutor.root = go; MethodicalExecutor.staticRoot = staticVariable; MethodicalObject chain = MethodicalInterpreter.MakeChain(go, command); object returnValue = MethodicalExecutor.execute(chain); commands.Insert(0, command); display.Insert(0, command); if (chain.GetType().Equals(typeof(MethodicalErrorObject))) { display.Insert(0, new MethodicalMessage(chain.ToString(), MethodicalMessage.MessageTypes.Error)); } else if (returnValue != null && returnValue.GetType().Equals(typeof(MethodicalErrorObject))) { display.Insert(0, new MethodicalMessage(returnValue.ToString(), MethodicalMessage.MessageTypes.Error)); } else if (returnValue != null) { display.Insert(0, new MethodicalMessage("- " + returnValue, MethodicalMessage.MessageTypes.Return)); } command = ""; commandIndex = -1; cachedCommand = ""; EditorGUI.FocusTextInControl("MethodicalCommandField"); }
private static object execute(MethodicalObject chain, object assignValue) { MethodicalObject currentLink = chain; object lastReturn = root; while (currentLink != null && lastReturn != null) { if (ExistsInClass(lastReturn, currentLink.objectName)) { lastReturn = SetFromClass(root, staticRoot, lastReturn, currentLink, assignValue); if (lastReturn == null || !lastReturn.GetType().Equals(typeof(MethodicalErrorObject))) { lastReturn = assignValue; // just going to print out the assigned value } } else { return(new MethodicalErrorObject(currentLink.objectName, MethodicalErrorObject.ERRORTYPES.DoesNotExist)); } currentLink = currentLink.member; } return(lastReturn); }
private static MethodicalErrorObject SetFromClass(MonoBehaviour root, string staticRoot, object parentObject, MethodicalObject member, object newValue) { //Going to try to get each as a field, a property, or method and see what sticks FieldInfo field = null; PropertyInfo property = null; //MethodInfo method = null; if (isStatic && parentObject == null) //Then static { System.Type type = GetTypeByName(staticRoot); field = type.GetField(member.objectName); property = type.GetProperty(member.objectName); //method = type.GetMethod(member.objectName); } else { field = MatchField(parentObject.GetType(), member.objectName); property = MatchProperty(parentObject.GetType(), member.objectName); //method = MatchMethod(parentObject.GetType(), member.objectName); } if (field != null) //Ugly and pointlessly verbose but readable { if (member.objectType.Equals(MethodicalObject.ObjectTypes.arrayType)) //If array //Getting the array { object[] array = (object[])field.GetValue(parentObject); int index = (int)execute(member.arrayDictionaryIndex); //Checking bounds if (index < 0 || index >= array.Length) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.OutOfBounds)); } //Making sure the types match if (!array.GetType().ToString().Equals(newValue.GetType().ToString() + "[]")) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.TypeMismatch)); } //Getting the array value array.SetValue(newValue, index); } else if (member.objectType.Equals(MethodicalObject.ObjectTypes.hashMapType)) { object index = (object)execute(member.arrayDictionaryIndex); if (index.GetType().Equals(typeof(MethodicalErrorObject))) //escaping of index variable doesn't exist { return((MethodicalErrorObject)index); } /*object value = field.FieldType.GetMethod("get_Item") * .Invoke(field.GetValue(parentObject), new object[] { index });*/ //Debug.Log("return value: " + value); Debug.Log("How did I get here?"); //field.SetValue(index, newValue);//TODO figure out if this works?!?! } else { field.SetValue(root, newValue); //TODO figure out what to do here } } else if (property != null) { if (member.objectType.Equals(MethodicalObject.ObjectTypes.arrayType)) //If array //Getting the array { object[] array = (object[])property.GetValue(parentObject, null); int index = (int)execute(member.arrayDictionaryIndex); //Checking bounds if (index < 0 || index >= array.Length) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.OutOfBounds)); } //Making sure the types match if (!array.GetType().ToString().Equals(newValue.GetType().ToString() + "[]")) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.TypeMismatch)); } //Getting the array value array.SetValue(newValue, index); } else if (member.objectType.Equals(MethodicalObject.ObjectTypes.hashMapType)) { object index = (object)execute(member.arrayDictionaryIndex); if (index.GetType().Equals(typeof(MethodicalErrorObject))) //escaping of index variable doesn't exist { return((MethodicalErrorObject)index); } property.PropertyType.GetMethod("get_Item") .Invoke(property.GetValue(parentObject, null), new object[] { index }); //Debug.Log("return value: " + value); Debug.Log("How did I get here?"); //return value; } else { //return property.GetValue(parentObject, null); property.SetValue(parentObject, newValue, null); } } return(null); }
/*! * Get the member object from the given class in the given context(root) and evaluates * */ private static object GetFromClass(MonoBehaviour root, string staticRoot, object parentObject, MethodicalObject member) { //Going to try to get each as a field, a property, or method and see what sticks FieldInfo field = null; PropertyInfo property = null; MethodInfo method = null; if (isStatic && parentObject == null) //Then static { System.Type type = GetTypeByName(staticRoot); field = type.GetField(member.objectName); property = type.GetProperty(member.objectName); method = type.GetMethod(member.objectName); } else { field = MatchField(parentObject.GetType(), member.objectName); property = MatchProperty(parentObject.GetType(), member.objectName); method = MatchMethod(parentObject.GetType(), member.objectName); } // Doing fields now if (field != null) //Ugly and pointlessly verbose but readable // Array Field { if (member.objectType.Equals(MethodicalObject.ObjectTypes.arrayType)) //If array //Getting the array { object[] array = (object[])field.GetValue(parentObject); int index = (int)execute(member.arrayDictionaryIndex); //Checking bounds if (index < 0 || index >= array.Length) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.OutOfBounds)); } //Getting the array value return(array.GetValue(index)); //Hashmap Field } else if (member.objectType.Equals(MethodicalObject.ObjectTypes.hashMapType)) { object index = (object)execute(member.arrayDictionaryIndex); if (index.GetType().Equals(typeof(MethodicalErrorObject))) //escaping of index variable doesn't exist { return(index); } //Checking the index type. Messy, but it works I guess if (!field.FieldType.ToString().Contains("[" + index.GetType().ToString()) && field.FieldType.ToString().Contains("System.Collections.Generic.Dictionary")) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.TypeMismatch)); } object value = field.FieldType.GetMethod("get_Item") .Invoke(field.GetValue(parentObject), new object[] { index }); //Debug.Log("return value: " + value); return(value); //Just a normal field } else { return(field.GetValue(parentObject)); } //Getting props } else if (property != null) { // Getting array members if (member.objectType.Equals(MethodicalObject.ObjectTypes.arrayType)) //If array //Getting the array { object[] array = (object[])property.GetValue(parentObject, null); int index = (int)execute(member.arrayDictionaryIndex); //Checking bounds if (index < 0 || index >= array.Length) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.OutOfBounds)); } //Getting the array value return(array.GetValue(index)); // Getting hashmap member } else if (member.objectType.Equals(MethodicalObject.ObjectTypes.hashMapType)) { object index = (object)execute(member.arrayDictionaryIndex); if (index.GetType().Equals(typeof(MethodicalErrorObject))) //escaping of index variable doesn't exist { return(index); } //Checking the index type. Messy, but it works I guess if (!field.FieldType.ToString().Contains("[" + index.GetType().ToString()) && field.FieldType.ToString().Contains("System.Collections.Generic.Dictionary")) { return(new MethodicalErrorObject(member.objectName, MethodicalErrorObject.ERRORTYPES.TypeMismatch)); } object value = property.PropertyType.GetMethod("get_Item") .Invoke(property.GetValue(parentObject, null), new object[] { index }); //Debug.Log("return value: " + value); return(value); //Just a regular member } else { return(property.GetValue(parentObject, null)); } // It's a method! } else if (method != null) { List <object> parameters = new List <object>(); //Evaluating each argument and turn them into something usable for reflection foreach (MethodicalObject mo in member.arguments) { object param = execute(mo); parameters.Add(param); } if (parameters.Count != method.GetParameters().Length) { return(new MethodicalErrorObject(method.Name, MethodicalErrorObject.ERRORTYPES.BadArguments)); } else //Then both parameter counts should be equal, no need to check { for (int i = 0; i < parameters.Count; i++) { if (parameters[i] != null && !method.GetParameters()[i].ParameterType.IsAssignableFrom(parameters[i].GetType())) { return(new MethodicalErrorObject(method.Name, MethodicalErrorObject.ERRORTYPES.BadArguments)); } } } return(method.Invoke(parentObject, parameters.ToArray())); //Well no clue what it is then... } else { return(null); } }
/*! * This method takes an input string, gets the next chunk, and prepares the string * for retrieval of the next chunk by removing the chunk that was just found * */ private static MethodicalObject GetNextChunk(object context, string command) { //Getting next chunk MethodicalObject chunk = new MethodicalObject(); string methodReturn = ""; string[] equality = new string[0]; if ((equality = CheckEquality(command)) != null) { chunk.objectName = "equality"; chunk.objectType = MethodicalObject.ObjectTypes.equalityType; chunk.leftEqualityString = equality[0]; chunk.leftEqualityString = chunk.leftEqualityString.Trim(); chunk.rightEqualityString = equality[1]; chunk.rightEqualityString = chunk.rightEqualityString.Trim(); } else if ((methodReturn = CheckNumber(command)) != "") //is the next chunk a number? { chunk.objectName = methodReturn; //I'll never use this, but it makes printlines readable //float or int? if (methodReturn.Contains("f") || methodReturn.Contains("F")) { chunk.objectType = MethodicalObject.ObjectTypes.floatType; methodReturn = methodReturn.Replace("f", ""); methodReturn = methodReturn.Replace("F", ""); chunk.value = float.Parse(methodReturn); } else if (methodReturn.Contains("d") || methodReturn.Contains("D")) { chunk.objectType = MethodicalObject.ObjectTypes.DoubleType; methodReturn = methodReturn.Replace("d", ""); methodReturn = methodReturn.Replace("D", ""); chunk.value = double.Parse(methodReturn); } else { chunk.objectType = MethodicalObject.ObjectTypes.intType; chunk.value = int.Parse(methodReturn); } } else if ((methodReturn = CheckBool(command)) != "") //is the next chunk a boolean? { chunk.objectName = methodReturn; //I'll never use this, but it makes printlines readable chunk.value = bool.Parse(methodReturn); chunk.objectType = MethodicalObject.ObjectTypes.boolType; } else if ((methodReturn = CheckString(command)) != "") //is the next chunk a string? { chunk.objectName = methodReturn; chunk.objectType = MethodicalObject.ObjectTypes.stringType; methodReturn = methodReturn.Trim('"'); chunk.value = methodReturn; } else if ((methodReturn = CheckArray(context, command)) != "") //is the next chunk an array? { chunk.objectName = methodReturn; chunk.objectType = MethodicalObject.ObjectTypes.arrayType; chunk.arrayDictionaryIndex = Interpret(context, null, GetArrayIndex(command)); //testIndex = new MethodicalObject(); //testIndex.value = 0; //testIndex.objectName = "0"; //testIndex.objectType = MethodicalObject.ObjectTypes.arrayType; //chunk.arrayDictionaryIndex = new MethodicalObject (); } else if ((methodReturn = CheckHashMap(context, command)) != "") //is the next chunk a hashmap? { chunk.objectName = methodReturn; chunk.objectType = MethodicalObject.ObjectTypes.hashMapType; chunk.arrayDictionaryIndex = Interpret(context, null, GetHashmapIndex(command)); } else if ((methodReturn = CheckMethod(command)) != "") //is the next chunk a method? { chunk.objectName = methodReturn; chunk.objectType = MethodicalObject.ObjectTypes.methodType; ProcessMethodChunk(context, chunk, command); // doing some additional processing } else if ((methodReturn = CheckVariable(command)) != "") //is the next chunk a variable? { chunk.objectName = methodReturn; chunk.objectType = MethodicalObject.ObjectTypes.variableType; } return(chunk); }