Skip to content

Commit

Permalink
Fix a couple of bugs in the variable resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
krzys-h committed Sep 22, 2018
1 parent e78e345 commit 91e6973
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 19 deletions.
28 changes: 18 additions & 10 deletions UndertaleModLib/Decompiler/Assembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public static class Assembler
public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFunction> funcs, IList<UndertaleVariable> vars, IList<UndertaleString> strg, Dictionary<string, UndertaleVariable> localvars = null)
{
string label;
UndertaleInstruction instr = AssembleOne(source, funcs, vars, strg, localvars, out label);
UndertaleInstruction instr = AssembleOne(source, funcs, vars, strg, localvars, out label, null);
if (label != null)
throw new Exception("Cannot use labels in this context");
return instr;
}

public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFunction> funcs, IList<UndertaleVariable> vars, IList<UndertaleString> strg, Dictionary<string, UndertaleVariable> localvars, out string label)
public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFunction> funcs, IList<UndertaleVariable> vars, IList<UndertaleString> strg, Dictionary<string, UndertaleVariable> localvars, out string label, UndertaleInstruction.InstanceType? prevInstType)
{
label = null;
string line = source;
Expand Down Expand Up @@ -80,7 +80,7 @@ public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFun

case UndertaleInstruction.InstructionType.PopInstruction:
UndertaleInstruction.InstanceType inst = instr.TypeInst;
instr.Destination = ParseVariableReference(line, vars, localvars, ref inst);
instr.Destination = ParseVariableReference(line, vars, localvars, ref inst, prevInstType);
instr.TypeInst = inst;
line = "";
break;
Expand All @@ -105,7 +105,7 @@ public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFun
break;
case UndertaleInstruction.DataType.Variable:
UndertaleInstruction.InstanceType inst2 = instr.TypeInst;
instr.Value = ParseVariableReference(line, vars, localvars, ref inst2);
instr.Value = ParseVariableReference(line, vars, localvars, ref inst2, prevInstType);
instr.TypeInst = inst2;
break;
case UndertaleInstruction.DataType.String:
Expand Down Expand Up @@ -197,7 +197,7 @@ public static List<UndertaleInstruction> Assemble(string source, IList<Undertale
}

string labelTgt;
UndertaleInstruction instr = AssembleOne(line, funcs, vars, strg, localvars, out labelTgt);
UndertaleInstruction instr = AssembleOne(line, funcs, vars, strg, localvars, out labelTgt, instructions.Count >= 2 && instructions[instructions.Count - 2].Kind == UndertaleInstruction.Opcode.PushI ? (UndertaleInstruction.InstanceType?)(short)instructions[instructions.Count - 2].Value : null);
instr.Address = addr;
if (labelTgt != null)
labelTargets.Add(instr, labelTgt);
Expand Down Expand Up @@ -248,7 +248,7 @@ private static UndertaleResourceById<UndertaleString> ParseStringReference(strin
return new UndertaleResourceById<UndertaleString>("STRG") { Resource = strobj, CachedId = (int)id.Value };
}

private static UndertaleInstruction.Reference<UndertaleVariable> ParseVariableReference(string line, IList<UndertaleVariable> vars, Dictionary<string, UndertaleVariable> localvars, ref UndertaleInstruction.InstanceType instance)
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;
Expand All @@ -274,7 +274,7 @@ private static UndertaleInstruction.Reference<UndertaleVariable> ParseVariableRe
}
else
{
instance = UndertaleInstruction.InstanceType.StackTopOrGlobal; // TODO: I think this isn't a thing that exists, 0 would be just object index 0
instance = UndertaleInstruction.InstanceType.Undefined;
}
UndertaleInstruction.VariableType type = UndertaleInstruction.VariableType.Normal;
if (str[0] == '[')
Expand All @@ -288,15 +288,23 @@ private static UndertaleInstruction.Reference<UndertaleVariable> ParseVariableRe
}
}

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 (instance == UndertaleInstruction.InstanceType.Local)
if (realinstance == UndertaleInstruction.InstanceType.Local)
{
varobj = localvars.ContainsKey(str) ? localvars[str] : null;
}
else
{
UndertaleInstruction.InstanceType i = instance; // ugh
varobj = vars.Where((x) => x.Name.Content == str && x.InstanceType == i).FirstOrDefault();
varobj = vars.Where((x) => x.Name.Content == str && x.InstanceType == realinstance).FirstOrDefault();
}
if (varobj == null)
throw new Exception("Bad variable!");
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModLib/Decompiler/Decompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ public override string ToString()
var instTypeVal = TryGetInstType();
if (instTypeVal.HasValue)
{
if (instTypeVal.Value != UndertaleInstruction.InstanceType.StackTopOrGlobal)
if (instTypeVal.Value != UndertaleInstruction.InstanceType.Undefined)
{
name = instTypeVal.Value.ToString().ToLower() + "." + name;
}
Expand Down
8 changes: 4 additions & 4 deletions UndertaleModLib/Models/UndertaleCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ public enum DataType : byte

public enum InstanceType : short
{
StackTopOrGlobal = 0,
Undefined = 0, // actually, this is just object 0, but also occurs in places where no instance type was set

Self = -1,
Other = -2,
All = -3,
Noone = -4,
Global = -5,
Unknown = -6,
Builtin = -6, // Note: Used only in UndertaleVariable.VarID (which is not really even InstanceType)
Local = -7,

// anything > 0 => GameObjectIndex
Expand Down Expand Up @@ -524,7 +524,7 @@ public string ToString(UndertaleCode code, IList<UndertaleVariable> vars)
sb.Append("." + Type1.ToOpcodeParam());
sb.Append("." + Type2.ToOpcodeParam());
sb.Append(" ");
if (Type1 == DataType.Variable && TypeInst != InstanceType.StackTopOrGlobal)
if (Type1 == DataType.Variable && TypeInst != InstanceType.Undefined)
{
sb.Append(TypeInst.ToString().ToLower());
sb.Append(".");
Expand All @@ -535,7 +535,7 @@ public string ToString(UndertaleCode code, IList<UndertaleVariable> vars)
case InstructionType.PushInstruction:
sb.Append("." + Type1.ToOpcodeParam());
sb.Append(" ");
if (Type1 == DataType.Variable && TypeInst != InstanceType.StackTopOrGlobal)
if (Type1 == DataType.Variable && TypeInst != InstanceType.Undefined)
{
sb.Append(TypeInst.ToString().ToLower());
sb.Append(".");
Expand Down
5 changes: 3 additions & 2 deletions UndertaleModLib/UndertaleData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public static UndertaleFunction EnsureDefined(this IList<UndertaleFunction> list
return func;
}

public static UndertaleVariable EnsureDefined(this IList<UndertaleVariable> list, string name, UndertaleInstruction.InstanceType inst, IList<UndertaleString> strg, UndertaleData data)
public static UndertaleVariable EnsureDefined(this IList<UndertaleVariable> list, string name, UndertaleInstruction.InstanceType inst, bool isBuiltin, IList<UndertaleString> strg, UndertaleData data)
{
if (inst == UndertaleInstruction.InstanceType.Local)
throw new InvalidOperationException("Use DefineLocal instead");
Expand All @@ -147,7 +147,7 @@ public static UndertaleVariable EnsureDefined(this IList<UndertaleVariable> list
{
Name = strg.MakeString(name),
InstanceType = inst,
VarID = (int)data.InstanceVarCount++,
VarID = isBuiltin ? (int)UndertaleInstruction.InstanceType.Builtin : (int)data.InstanceVarCount++,
UnknownChainEndingValue = 0 // TODO: seems to work...
};
data.InstanceVarCountAgain = data.InstanceVarCount;
Expand All @@ -167,6 +167,7 @@ public static UndertaleVariable DefineLocal(this IList<UndertaleVariable> list,
};
if (idx >= data.MaxLocalVarCount)
data.MaxLocalVarCount = idx + 1;
list.Add(vari);
return vari;
}
}
Expand Down
4 changes: 2 additions & 2 deletions UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private void DisassembleCode(UndertaleCode code)
par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam()) { Foreground = typeBrush });
par.Inlines.Add(new Run("." + instr.Type2.ToOpcodeParam()) { Foreground = typeBrush });
par.Inlines.Add(new Run(" "));
if (instr.Type1 == UndertaleInstruction.DataType.Variable && instr.TypeInst != UndertaleInstruction.InstanceType.StackTopOrGlobal)
if (instr.Type1 == UndertaleInstruction.DataType.Variable && instr.TypeInst != UndertaleInstruction.InstanceType.Undefined)
{
par.Inlines.Add(new Run(instr.TypeInst.ToString().ToLower()) { Foreground = typeBrush });
par.Inlines.Add(new Run("."));
Expand All @@ -156,7 +156,7 @@ private void DisassembleCode(UndertaleCode code)
case UndertaleInstruction.InstructionType.PushInstruction:
par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam()) { Foreground = typeBrush });
par.Inlines.Add(new Run(" "));
if (instr.Type1 == UndertaleInstruction.DataType.Variable && instr.TypeInst != UndertaleInstruction.InstanceType.StackTopOrGlobal)
if (instr.Type1 == UndertaleInstruction.DataType.Variable && instr.TypeInst != UndertaleInstruction.InstanceType.Undefined)
{
par.Inlines.Add(new Run(instr.TypeInst.ToString().ToLower()) { Foreground = typeBrush });
par.Inlines.Add(new Run("."));
Expand Down

0 comments on commit 91e6973

Please sign in to comment.