Beispiel #1
0
        /// <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);
        }