/// <summary> /// Parses the instruction. /// </summary> /// <param name="mainProcessor">The main instruction processor.</param> /// <param name="asmCollection">The papyrus assembly collection.</param> /// <param name="instruction">The instruction.</param> /// <param name="targetMethod">The target method.</param> /// <param name="type">The type.</param> /// <returns></returns> public IEnumerable <PapyrusInstruction> Process( IClrInstructionProcessor mainProcessor, IReadOnlyCollection <PapyrusAssemblyDefinition> asmCollection, Instruction instruction, MethodDefinition targetMethod, TypeDefinition type) { bool isStructAccess; var instructions = new List <PapyrusInstruction>(); if (InstructionHelper.IsBranchConditional(instruction.OpCode.Code)) { var popCount = Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop); if (mainProcessor.EvaluationStack.Count >= popCount) { var obj1 = mainProcessor.EvaluationStack.Pop(); var obj2 = mainProcessor.EvaluationStack.Pop(); // gets or create a temp boolean variable we can use to store the conditional check on. var temp = mainProcessor.GetTargetVariable(instruction, null, out isStructAccess, "Bool"); var allVars = mainProcessor.PapyrusMethod.GetVariables(); var tempVar = allVars.FirstOrDefault(v => v.Name.Value == temp); var destinationInstruction = instruction.Operand; if (InstructionHelper.IsBranchConditionalEq(instruction.OpCode.Code)) { instructions.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.CmpEq, tempVar, obj1, obj2)); } else if (InstructionHelper.IsBranchConditionalLt(instruction.OpCode.Code)) { instructions.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.CmpLt, tempVar, obj1, obj2)); } else if (InstructionHelper.IsBranchConditionalGt(instruction.OpCode.Code)) { instructions.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.CmpGt, tempVar, obj1, obj2)); } else if (InstructionHelper.IsBranchConditionalGe(instruction.OpCode.Code)) { instructions.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.CmpGte, tempVar, obj1, obj2)); } else if (InstructionHelper.IsBranchConditionalGe(instruction.OpCode.Code)) { instructions.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.CmpLte, tempVar, obj1, obj2)); } instructions.Add(mainProcessor.ConditionalJump(PapyrusOpCodes.Jmpt, tempVar, destinationInstruction)); return(instructions); } } if (InstructionHelper.IsBranch(instruction.OpCode.Code)) { var stack = mainProcessor.EvaluationStack; var targetInstruction = instruction.Operand; if (stack.Count > 0) { var conditionalVariable = stack.Pop(); if (InstructionHelper.IsBranchTrue(instruction.OpCode.Code)) { var jmpOp = mainProcessor.TryInvertJump(PapyrusOpCodes.Jmpt); var jmp = mainProcessor.CreatePapyrusInstruction(jmpOp, conditionalVariable, targetInstruction); jmp.Operand = targetInstruction; instructions.Add(jmp); return(instructions); } if (InstructionHelper.IsBranchFalse(instruction.OpCode.Code)) { var jmpOp = mainProcessor.TryInvertJump(PapyrusOpCodes.Jmpf); var jmp = mainProcessor.CreatePapyrusInstruction(jmpOp, conditionalVariable, targetInstruction); jmp.Operand = targetInstruction; instructions.Add(jmp); return(instructions); } } var jmpInst = mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Jmp, targetInstruction); jmpInst.Operand = targetInstruction; instructions.Add(jmpInst); } return(instructions); }