private static UndertaleInstruction.Reference <UndertaleVariable> ParseVariableReference(string line, IList <UndertaleVariable> vars, Dictionary <string, UndertaleVariable> localvars, ref UndertaleInstruction.InstanceType instance, UndertaleInstruction instr, UndertaleData data = null) { string str = line; UndertaleInstruction.VariableType type = UndertaleInstruction.VariableType.Normal; UndertaleInstruction.InstanceType realinstance = instance; if (str[0] != '[') { string inst = null; int instdot = str.IndexOf('.'); if (instdot >= 0) { inst = str.Substring(0, instdot); str = str.Substring(instdot + 1); if (inst == "") { throw new Exception("Whoops?"); } } if (inst != null) { short instnum; if (Int16.TryParse(inst, out instnum)) { instance = (UndertaleInstruction.InstanceType)instnum; } else { instance = (UndertaleInstruction.InstanceType)Enum.Parse(typeof(UndertaleInstruction.InstanceType), inst, true); } } else { instance = UndertaleInstruction.InstanceType.Undefined; } realinstance = instance; if (realinstance >= 0) { realinstance = UndertaleInstruction.InstanceType.Self; } else if (realinstance == UndertaleInstruction.InstanceType.Other) { realinstance = UndertaleInstruction.InstanceType.Self; } else if (realinstance == UndertaleInstruction.InstanceType.Arg) { realinstance = UndertaleInstruction.InstanceType.Builtin; } else if (realinstance == UndertaleInstruction.InstanceType.Builtin) { realinstance = UndertaleInstruction.InstanceType.Self; // used with @@This@@ } else if (realinstance == UndertaleInstruction.InstanceType.Stacktop) { realinstance = UndertaleInstruction.InstanceType.Self; // used with @@GetInstance@@ } } else { int typeend = str.IndexOf(']'); if (typeend >= 0) { string typestr = str.Substring(1, typeend - 1); str = str.Substring(typeend + 1); type = (UndertaleInstruction.VariableType)Enum.Parse(typeof(UndertaleInstruction.VariableType), typestr, true); int instanceEnd = str.IndexOf('.'); if (instanceEnd >= 0) { string instancestr = str.Substring(0, instanceEnd); str = str.Substring(instanceEnd + 1); realinstance = (UndertaleInstruction.InstanceType)Enum.Parse(typeof(UndertaleInstruction.InstanceType), instancestr, true); } else { if (type == UndertaleInstruction.VariableType.Array || type == UndertaleInstruction.VariableType.StackTop) { throw new Exception("Old instruction format is incompatible (missing instance type in array or stacktop)"); } if (realinstance >= 0) { realinstance = UndertaleInstruction.InstanceType.Self; } else if (realinstance == UndertaleInstruction.InstanceType.Other) { realinstance = UndertaleInstruction.InstanceType.Self; } } } else { throw new Exception("Missing ']' character in variable reference"); } } if (data?.GeneralInfo?.BytecodeVersion <= 14) { realinstance = UndertaleInstruction.InstanceType.Undefined; } UndertaleVariable varobj; if (realinstance == UndertaleInstruction.InstanceType.Local) { varobj = localvars.ContainsKey(str) ? localvars[str] : null; } else { varobj = vars.Where((x) => x.Name.Content == str && x.InstanceType == realinstance).FirstOrDefault(); } if (varobj == null) { throw new Exception("Bad variable: " + realinstance.ToString().ToLower() + "." + str); } return(new UndertaleInstruction.Reference <UndertaleVariable>(varobj, type)); }
private static UndertaleInstruction.Reference <UndertaleVariable> ParseVariableReference(string line, IList <UndertaleVariable> vars, Dictionary <string, UndertaleVariable> localvars, ref UndertaleInstruction.InstanceType instance, UndertaleInstruction instr, Func <int, UndertaleInstruction.InstanceType?> lookOnStack = null, UndertaleData data = null) { string str = line; string inst = null; int instdot = str.IndexOf('.'); if (instdot >= 0) { inst = str.Substring(0, instdot); str = str.Substring(instdot + 1); if (inst == "") { throw new Exception("Whoops?"); } } if (inst != null) { short instnum; if (Int16.TryParse(inst, out instnum)) { instance = (UndertaleInstruction.InstanceType)instnum; } else { instance = (UndertaleInstruction.InstanceType)Enum.Parse(typeof(UndertaleInstruction.InstanceType), inst, true); } } else { instance = UndertaleInstruction.InstanceType.Undefined; } UndertaleInstruction.VariableType type = UndertaleInstruction.VariableType.Normal; if (str[0] == '[') { int typeend = str.IndexOf(']'); if (typeend >= 0) { string typestr = str.Substring(1, typeend - 1); str = str.Substring(typeend + 1); type = (UndertaleInstruction.VariableType)Enum.Parse(typeof(UndertaleInstruction.VariableType), typestr, true); } } UndertaleInstruction.InstanceType realinstance = instance; // for arrays, the type is on the stack which totally breaks things // This is an ugly hack to handle that // see https://github.com/krzys-h/UndertaleModTool/issues/27#issuecomment-426637438 if (type == UndertaleInstruction.VariableType.Array && lookOnStack != null) { var instTypeOnStack = lookOnStack(instr.Kind == UndertaleInstruction.Opcode.Pop && instr.Type1 == UndertaleInstruction.DataType.Int32 ? 3 : 2); if (instTypeOnStack.HasValue) { realinstance = instTypeOnStack.Value; } } if (realinstance >= 0) { realinstance = UndertaleInstruction.InstanceType.Self; } else if (realinstance == UndertaleInstruction.InstanceType.Other) { realinstance = UndertaleInstruction.InstanceType.Self; } if (data?.GeneralInfo?.BytecodeVersion <= 14) { realinstance = UndertaleInstruction.InstanceType.Undefined; } UndertaleVariable varobj; if (realinstance == UndertaleInstruction.InstanceType.Local) { varobj = localvars.ContainsKey(str) ? localvars[str] : null; } else { varobj = vars.Where((x) => x.Name.Content == str && x.InstanceType == realinstance).FirstOrDefault(); } if (varobj == null) { throw new Exception("Bad variable: " + realinstance.ToString().ToLower() + "." + str); } return(new UndertaleInstruction.Reference <UndertaleVariable>(varobj, type)); }
private static UndertaleInstruction.Reference <UndertaleVariable> ParseVariableReference(string line, IList <UndertaleVariable> vars, Dictionary <string, UndertaleVariable> localvars, ref UndertaleInstruction.InstanceType instance, UndertaleInstruction.InstanceType?prevInstType) { string str = line; string inst = null; int instdot = str.IndexOf('.'); if (instdot >= 0) { inst = str.Substring(0, instdot); str = str.Substring(instdot + 1); if (inst == "") { throw new Exception("Whoops?"); } } if (inst != null) { short instnum; if (Int16.TryParse(inst, out instnum)) { instance = (UndertaleInstruction.InstanceType)instnum; } else { instance = (UndertaleInstruction.InstanceType)Enum.Parse(typeof(UndertaleInstruction.InstanceType), inst, true); } } else { instance = UndertaleInstruction.InstanceType.Undefined; } UndertaleInstruction.VariableType type = UndertaleInstruction.VariableType.Normal; if (str[0] == '[') { int typeend = str.IndexOf(']'); if (typeend >= 0) { string typestr = str.Substring(1, typeend - 1); str = str.Substring(typeend + 1); type = (UndertaleInstruction.VariableType)Enum.Parse(typeof(UndertaleInstruction.VariableType), typestr, true); } } UndertaleInstruction.InstanceType realinstance = instance; // for arrays, the type is on the stack which totally breaks things // This is an ugly hack to handle that if (type == UndertaleInstruction.VariableType.Array && prevInstType.HasValue) { realinstance = prevInstType.Value; } if (realinstance >= 0) { realinstance = UndertaleInstruction.InstanceType.Self; } UndertaleVariable varobj; if (realinstance == UndertaleInstruction.InstanceType.Local) { varobj = localvars.ContainsKey(str) ? localvars[str] : null; } else { varobj = vars.Where((x) => x.Name.Content == str && x.InstanceType == realinstance).FirstOrDefault(); } if (varobj == null) { throw new Exception("Bad variable!"); } return(new UndertaleInstruction.Reference <UndertaleVariable>(varobj, type)); }