コード例 #1
0
 public static bool IsCallMethodInsideNamespace(Instruction instruction, string targetNamespace,
                                                out MethodReference methodRef)
 {
     methodRef = null;
     if (InstructionHelper.IsCallMethod(instruction.OpCode.Code))
     {
         var method = instruction.Operand as MethodReference;
         if (method != null && method.FullName.Contains(targetNamespace))
         {
             methodRef = method;
             return(true);
         }
     }
     return(false);
 }
コード例 #2
0
ファイル: LoadProcessor.cs プロジェクト: madawe/Paprus
        /// <summary>
        /// Parses the instruction.
        /// </summary>
        /// <param name="mainProcessor">The 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>
        /// <exception cref="System.NotImplementedException"></exception>
        /// <exception cref="MissingVariableException"></exception>
        public IEnumerable <PapyrusInstruction> Process(
            IClrInstructionProcessor mainProcessor,
            IReadOnlyCollection <PapyrusAssemblyDefinition> asmCollection,
            Instruction instruction,
            MethodDefinition targetMethod, TypeDefinition type)
        {
            bool isStructAccess;
            var  outputInstructions = new List <PapyrusInstruction>();

            if (InstructionHelper.NextInstructionIs(instruction, Code.Ldnull) &&
                InstructionHelper.NextInstructionIs(instruction.Next, Code.Cgt_Un))
            {
                var stack = mainProcessor.EvaluationStack;
                //var itemToCheck = stack.Pop().Value;
                var itemToCheck = instruction.Operand as FieldReference;

                if (itemToCheck != null)
                {
                    mainProcessor.EvaluationStack.Push(
                        new EvaluationStackItem
                    {
                        Value    = itemToCheck,
                        TypeName = ""
                    }
                        );
                    mainProcessor.EvaluationStack.Push(
                        new EvaluationStackItem
                    {
                        Value    = null,
                        TypeName = "none"
                    }
                        );

                    mainProcessor.SkipToOffset =
                        InstructionHelper.NextInstructionIsOffset(instruction.Next, Code.Cgt_Un) - 1;

                    //bool structAccess;
                    //var targetVar = mainInstructionProcessor.GetTargetVariable(tarInstruction, null, out structAccess, "Bool");

                    //if (mainInstructionProcessor.SkipNextInstruction)
                    //{
                    //    mainInstructionProcessor.SkipToOffset += 2;
                    //    mainInstructionProcessor.SkipNextInstruction = false;
                    //}

                    //outputInstructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Is,
                    //    mainInstructionProcessor.CreateVariableReferenceFromName(targetVar), fieldDef,
                    //    mainInstructionProcessor.CreateVariableReferenceFromName(typeToCheckAgainst.Name)));
                    return(outputInstructions);
                }
            }

            if (InstructionHelper.IsLoadMethodRef(instruction.OpCode.Code))
            {
                // Often used for delegates or Action/func parameters, when loading a reference pointer to a method and pushing it to the stack.
                // To maintain the evaluation stack, this could add a dummy item, but for now im not going to do so.
            }

            if (InstructionHelper.IsLoadLength(instruction.OpCode.Code))
            {
                var popCount = Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop);
                if (mainProcessor.EvaluationStack.Count >= popCount)
                {
                    var val = mainProcessor.EvaluationStack.Pop();
                    if (val.TypeName.EndsWith("[]"))
                    {
                        if (val.Value is PapyrusPropertyDefinition)
                        {
                            // for now, so if this exception is thrown, i will have to remember I have to fix it.
                            throw new NotImplementedException();
                        }

                        if (val.Value is PapyrusVariableReference || val.Value is PapyrusFieldDefinition ||
                            val.Value is PapyrusParameterDefinition)
                        {
                            int variableIndex;

                            var storeInstruction =
                                mainProcessor.GetNextStoreLocalVariableInstruction(instruction,
                                                                                   out variableIndex);

                            if (storeInstruction != null ||
                                InstructionHelper.IsConverToNumber(instruction.Next.OpCode.Code))
                            {
                                if (InstructionHelper.IsConverToNumber(instruction.Next.OpCode.Code))
                                {
                                    mainProcessor.SkipNextInstruction = false;
                                    mainProcessor.SkipToOffset        = 0;

                                    var targetVariableName = mainProcessor.GetTargetVariable(instruction,
                                                                                             null, out isStructAccess, "Int", true);

                                    var allVars        = mainProcessor.PapyrusMethod.GetVariables();
                                    var targetVariable = allVars.FirstOrDefault(v => v.Name.Value == targetVariableName);

                                    if (targetVariable == null &&
                                        mainProcessor.PapyrusCompilerOptions == PapyrusCompilerOptions.Strict)
                                    {
                                        throw new MissingVariableException(targetVariableName);
                                    }
                                    if (targetVariable != null)
                                    {
                                        mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                                        {
                                            TypeName = targetVariable.TypeName.Value,
                                            Value    = targetVariable
                                        });

                                        outputInstructions.Add(
                                            mainProcessor.CreatePapyrusInstruction(
                                                PapyrusOpCodes.ArrayLength,
                                                mainProcessor.CreateVariableReference(
                                                    PapyrusPrimitiveType.Reference, targetVariableName), val.Value));
                                    }
                                }
                                else
                                {
                                    var allVars = mainProcessor.PapyrusMethod.GetVariables();

                                    mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                                    {
                                        TypeName = allVars[variableIndex].TypeName.Value,
                                        Value    = allVars[variableIndex]
                                    });

                                    outputInstructions.Add(
                                        mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.ArrayLength,
                                                                               allVars[variableIndex], val.Value));

                                    //return "ArrayLength " + allVars[variableIndex].Name + " " +
                                    //       (val.Value as VariableReference).Name;
                                }
                            }
                        }
                    }
                }
                // ArrayLength <outputVariableName> <arrayName>
            }


            if (InstructionHelper.IsLoadArgs(instruction.OpCode.Code))
            {
                var index = (int)mainProcessor.GetNumericValue(instruction);
                if (targetMethod.IsStatic && index == 0 && targetMethod.Parameters.Count == 0)
                {
                    mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                    {
                        IsThis   = true,
                        Value    = type,
                        TypeName = type.FullName
                    });
                }
                else
                {
                    if (targetMethod.HasThis && index == 0)
                    {
                        return(outputInstructions);
                    }

                    if (!targetMethod.IsStatic && index > 0)
                    {
                        index--;
                    }
                    if (index < mainProcessor.PapyrusMethod.Parameters.Count)
                    {
                        mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                        {
                            Value    = mainProcessor.PapyrusMethod.Parameters[index],
                            TypeName = mainProcessor.PapyrusMethod.Parameters[index].TypeName.Value
                        });
                    }
                }
            }
            if (InstructionHelper.IsLoadInteger(instruction.OpCode.Code))
            {
                var index = mainProcessor.GetNumericValue(instruction);
                mainProcessor.EvaluationStack.Push(new EvaluationStackItem {
                    Value = index, TypeName = "Int"
                });
            }

            if (InstructionHelper.IsLoadNull(instruction.OpCode.Code))
            {
                mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                {
                    Value    = "None",
                    TypeName = "None"
                });
            }

            if (InstructionHelper.IsLoadLocalVariable(instruction.OpCode.Code))
            {
                var index        = (int)mainProcessor.GetNumericValue(instruction);
                var allVariables = mainProcessor.PapyrusMethod.GetVariables();
                if (index < allVariables.Count)
                {
                    mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                    {
                        Value    = allVariables[index],
                        TypeName = allVariables[index].TypeName.Value
                    });
                }
            }

            if (InstructionHelper.IsLoadString(instruction.OpCode.Code))
            {
                var value = StringUtility.AsString(instruction.Operand);

                mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                {
                    Value    = value,
                    TypeName = "String"
                });
            }

            if (InstructionHelper.IsLoadFieldObject(instruction.OpCode.Code))
            {
                if (instruction.Operand is FieldReference)
                {
                    var fieldRef = instruction.Operand as FieldReference;


                    PapyrusFieldDefinition targetField = null;

                    targetField = mainProcessor.PapyrusType.Fields.FirstOrDefault(
                        f => f.Name.Value == "::" + fieldRef.Name.Replace('<', '_').Replace('>', '_'));

                    if (targetField == null)
                    {
                        targetField = mainProcessor.GetDelegateField(fieldRef);
                    }


                    if (targetField != null)
                    {
                        mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                        {
                            Value    = targetField,
                            TypeName = targetField.TypeName
                        });
                    }

                    if (InstructionHelper.PreviousInstructionWas(instruction, Code.Ldflda) &&
                        fieldRef.FullName.Contains("/"))
                    {
                        var targetStructVariable = mainProcessor.EvaluationStack.Pop().Value;

                        var structRef = new PapyrusStructFieldReference(mainProcessor.PapyrusAssembly, null)
                        {
                            StructSource   = targetStructVariable,
                            StructVariable = mainProcessor.CreateVariableReferenceFromName(fieldRef.Name)
                        };

                        mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                        {
                            Value    = structRef,
                            TypeName = "$StructAccess$"
                        });

                        return(outputInstructions);

                        //    // The target field is not inside the declared type.
                        //    // Most likely, this is a get field from struct.
                        //    if (fieldRef.FieldType.FullName.Contains("/"))
                        //    {
                        //        var location = fieldRef.FieldType.FullName.Split("/").LastOrDefault();

                        //        var targetStruct = mainInstructionProcessor.PapyrusType.NestedTypes.FirstOrDefault(n => n.Name.Value == location);
                        //        if (targetStruct != null)
                        //        {

                        //            targetField = mainInstructionProcessor.PapyrusType.Fields.FirstOrDefault(
                        //                f => f.Name.Value == "::" + fieldRef.Name);
                        //            // var stack = mainInstructionProcessor.EvaluationStack;
                        //            // TODO: Add support for getting values from Structs
                        //            //
                        //            // CreatePapyrusInstruction(PapyrusOpCode.StructGet, ...)
                        //        }
                        //    }
                    }
                    //else
                    //{
                    //    targetField = mainInstructionProcessor.PapyrusType.Fields.FirstOrDefault(
                    //        f => f.Name.Value == "::" + fieldRef.Name.Replace('<', '_').Replace('>', '_'));
                    //}
                }
            }


            if (InstructionHelper.IsLoadElement(instruction.OpCode.Code))
            {
                // TODO: Load Element (Arrays, and what not)
                var popCount = Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop);
                if (mainProcessor.EvaluationStack.Count >= popCount)
                {
                    var itemIndex = mainProcessor.EvaluationStack.Pop();
                    var itemArray = mainProcessor.EvaluationStack.Pop();

                    object targetItemIndex = null;

                    var targetItemArray = itemArray.Value;

                    if (itemIndex.Value != null)
                    {
                        targetItemIndex = itemIndex.Value;
                    }

                    // 128 is the array size limit for Skyrim
                    if (mainProcessor.PapyrusAssembly.VersionTarget == PapyrusVersionTargets.Skyrim)
                    {
                        if ((targetItemIndex as int?) > 128)
                        {
                            targetItemIndex = 128;
                        }
                    }

                    // We want to use the Array Element together with a Method Call?
                    var isBoxing = InstructionHelper.IsBoxing(instruction.Next.OpCode.Code);
                    if (isBoxing || InstructionHelper.IsCallMethod(instruction.Next.OpCode.Code))
                    {
                        if (isBoxing)
                        {
                            var sourceArray = targetItemArray as PapyrusVariableReference;
                            if (sourceArray != null)
                            {
                                // Since we apply our logic necessary for this "boxing" right here
                                // we can skip the next instruction to avoid unexpected behaviour.
                                mainProcessor.SkipNextInstruction = true;

                                // Create a new Temp Variable
                                // Assign our value to this temp variable and push it to the stack
                                // so that the next instruction can take care of it.
                                var tempVariableType = sourceArray.TypeName.Value.Replace("[]", "");

                                var destinationTempVar = mainProcessor.GetTargetVariable(instruction, null,
                                                                                         out isStructAccess, tempVariableType, true);

                                var varRef =
                                    mainProcessor.PapyrusMethod.GetVariables()
                                    .FirstOrDefault(n => n.Name.Value == destinationTempVar);

                                mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                                {
                                    Value = varRef ?? (object)destinationTempVar,
                                    // Should be the actual variable reference
                                    TypeName = tempVariableType
                                });

                                outputInstructions.Add(
                                    mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.ArrayGetElement,
                                                                           mainProcessor.CreateVariableReference(
                                                                               PapyrusPrimitiveType.Reference, destinationTempVar),
                                                                           targetItemArray,
                                                                           targetItemIndex));
                            }
                        }
                        else
                        {
                            // Get the method reference and then create a temp variable that
                            // we can use for assigning the value to.
                            var methodRef = instruction.Next.Operand as MethodReference;
                            if (methodRef != null && methodRef.HasParameters)
                            {
                                var sourceArray = targetItemArray as PapyrusVariableReference;
                                if (sourceArray != null)
                                {
                                    var tempVariableType   = sourceArray.TypeName.Value.Replace("[]", "");
                                    var destinationTempVar = mainProcessor.GetTargetVariable(instruction,
                                                                                             methodRef, out isStructAccess,
                                                                                             tempVariableType);

                                    // "ArrayGetElement " + destinationTempVar + " " + targetItemArray + " " + targetItemIndex;
                                    outputInstructions.Add(
                                        mainProcessor.CreatePapyrusInstruction(
                                            PapyrusOpCodes.ArrayGetElement,
                                            mainProcessor.CreateVariableReference(
                                                PapyrusPrimitiveType.Reference, destinationTempVar),
                                            targetItemArray,
                                            targetItemIndex));
                                }
                            }
                        }
                    }
                    else
                    {
                        // Otherwise we just want to store it somewhere.
                        int destinationVariableIndex;
                        // Get the target variable by finding the next store instruction and returning the variable index.
                        mainProcessor.GetNextStoreLocalVariableInstruction(instruction,
                                                                           out destinationVariableIndex);
                        var destinationVar =
                            mainProcessor.PapyrusMethod.GetVariables()[destinationVariableIndex];

                        // ArrayGetElement targetVariable targetItemArray targetItemIndex
                        outputInstructions.Add(
                            mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.ArrayGetElement,
                                                                   destinationVar,
                                                                   targetItemArray,
                                                                   targetItemIndex)
                            );
                    }
                }
            }
            return(outputInstructions);
        }
コード例 #3
0
        /// <summary>
        /// Parses the instruction.
        /// </summary>
        /// <param name="mainProcessor">The main 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)
        {
            var allVariables = mainProcessor.PapyrusMethod.GetVariables();

            if (InstructionHelper.IsStoreElement(instruction.OpCode.Code))
            {
                var popCount = Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop);
                if (mainProcessor.EvaluationStack.Count >= popCount)
                {
                    var newValue  = mainProcessor.EvaluationStack.Pop();
                    var itemIndex = mainProcessor.EvaluationStack.Pop();
                    var itemArray = mainProcessor.EvaluationStack.Pop();

                    object targetItemIndex = null;
                    object targetItemArray = null;
                    object targetItemValue = null;

                    if (itemIndex.Value is PapyrusVariableReference)
                    {
                        targetItemIndex = itemIndex.Value as PapyrusVariableReference;
                    }
                    else if (itemIndex.Value != null)
                    {
                        targetItemIndex = itemIndex.Value;
                    }

                    if (mainProcessor.PapyrusAssembly.VersionTarget == PapyrusVersionTargets.Skyrim)
                    {
                        if ((targetItemIndex as int?) > 128)
                        {
                            targetItemIndex = 128;
                        }
                    }

                    if (itemArray.Value is PapyrusVariableReference)
                    {
                        targetItemArray = itemArray.Value as PapyrusVariableReference;
                    }

                    if (newValue.Value is PapyrusVariableReference)
                    {
                        targetItemValue = newValue.Value as PapyrusVariableReference;
                    }
                    else if (newValue.Value != null)
                    {
                        targetItemValue = newValue.Value;
                    }


                    return
                        (ArrayUtility.ArrayOf(
                             mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.ArraySetElement,
                                                                    targetItemArray, targetItemIndex,
                                                                    targetItemValue)));
                    //return "ArraySetElement " + tar + " " + oidx + " " + val;
                }
            }

            if (InstructionHelper.IsStoreLocalVariable(instruction.OpCode.Code) ||
                InstructionHelper.IsStoreFieldObject(instruction.OpCode.Code))
            {
                if (instruction.Operand is FieldReference)
                {
                    var fref = instruction.Operand as FieldReference;
                    // if the EvaluationStack.Count == 0
                    // The previous instruction might have been a call that returned a value
                    // Something we did not store...

                    if (mainProcessor.EvaluationStack.Count == 0 &&
                        InstructionHelper.IsCallMethod(instruction.Previous.OpCode.Code))
                    {
                        // If previous was a call, then we should have the evaluation stack with at least one item.
                        // But it seem like we don't... Inject tempvar?
                    }

                    if (mainProcessor.EvaluationStack.Count > 0)
                    {
                        var obj = mainProcessor.EvaluationStack.Pop();

                        var definedField = mainProcessor.PapyrusType.Fields.FirstOrDefault(
                            f => f.Name.Value == "::" + fref.Name.Replace('<', '_').Replace('>', '_'));

                        if (definedField == null)
                        {
                            definedField = mainProcessor.GetDelegateField(fref);
                        }

                        if (mainProcessor.EvaluationStack.Count > 0)
                        {
                            var nextObj = mainProcessor.EvaluationStack.Peek();

                            if (nextObj != null && nextObj.TypeName != null && nextObj.TypeName.Contains("#"))
                            {
                                // Store into Struct field.
                                definedField = nextObj.Value as PapyrusFieldDefinition;
                                var structPropName = fref.Name;
                                mainProcessor.EvaluationStack.Pop();
                                // Just pop it so it does not interfere with any other instructions
                                return
                                    (ArrayUtility.ArrayOf(
                                         mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.StructSet,
                                                                                definedField, // location
                                                                                mainProcessor.CreateVariableReferenceFromName(structPropName),
                                                                                              // Struct Property/Field Name
                                                                                obj.Value     // value
                                                                                )));
                            }
                        }


                        if (definedField != null)
                        {
                            var structRef = obj.Value as PapyrusStructFieldReference;
                            if (structRef != null)
                            {
                                // StructGet -> TempVar
                                // Var <- TempVar

                                var structSource = structRef.StructSource as PapyrusFieldDefinition;
                                var structField  = structRef.StructVariable;

                                var fieldType = GetStructFieldType(asmCollection, structSource, structField);

                                // 1. Create Temp Var
                                bool isStructAccess;
                                var  tempVar = mainProcessor.GetTargetVariable(instruction, null,
                                                                               out isStructAccess,
                                                                               fieldType, true);

                                // 2. StructGet -> tempVar
                                // 3. Assign var <- tempVar
                                return(ArrayUtility.ArrayOf(
                                           mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.StructGet,
                                                                                  mainProcessor.CreateVariableReferenceFromName(tempVar), structSource,
                                                                                  structField),
                                           mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                                  definedField, mainProcessor.CreateVariableReferenceFromName(tempVar))));
                            }
                            if (obj.Value is PapyrusParameterDefinition)
                            {
                                var varRef = obj.Value as PapyrusParameterDefinition;
                                // definedField.FieldVariable = varRef.;

                                // CreatePapyrusInstruction(PapyrusOpCode.Assign, definedField.Name.Value, varRef.Name.Value)
                                return
                                    (ArrayUtility.ArrayOf(
                                         mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                                definedField, varRef)));
                            }
                            if (obj.Value is PapyrusVariableReference)
                            {
                                var varRef = obj.Value as PapyrusVariableReference;
                                // definedField.Value = varRef.Value;
                                definedField.DefaultValue      = varRef;
                                definedField.DefaultValue.Type = PapyrusPrimitiveType.Reference;
                                // CreatePapyrusInstruction(PapyrusOpCode.Assign, definedField.Name.Value, varRef.Name.Value)
                                if (varRef.IsDelegateReference)
                                {
                                    return(new PapyrusInstruction[0]);
                                }
                                return
                                    (ArrayUtility.ArrayOf(
                                         mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                                definedField, varRef)));
                            }
                            //definedField.FieldVariable.Value =
                            //    Utility.TypeValueConvert(definedField.FieldVariable.TypeName.Value, obj.Value);
                            var targetValue = valueTypeConverter.Convert(definedField.DefaultValue.TypeName.Value,
                                                                         obj.Value);

                            return
                                (ArrayUtility.ArrayOf(
                                     mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                            definedField, targetValue)));
                            // definedField.FieldVariable.Value
                            // "Assign " + definedField.Name + " " + definedField.Value;
                        }
                    }
                }
                var    index  = (int)mainProcessor.GetNumericValue(instruction);
                object outVal = null;
                if (index < allVariables.Count)
                {
                    if (mainProcessor.EvaluationStack.Count > 0)
                    {
                        var heapObj = mainProcessor.EvaluationStack.Pop();

                        var structRef = heapObj.Value as PapyrusStructFieldReference;
                        if (structRef != null)
                        {
                            // Grabbing value from struct

                            var structSource = structRef.StructSource as PapyrusFieldDefinition;
                            var structField  = structRef.StructVariable;

                            var fieldType = GetStructFieldType(asmCollection, structSource, structField);

                            // 1. Create Temp Var
                            bool isStructAccess;
                            var  tempVar = mainProcessor.GetTargetVariable(instruction, null,
                                                                           out isStructAccess,
                                                                           fieldType, true);

                            // 2. StructGet -> tempVar
                            // 3. Assign var <- tempVar
                            return(ArrayUtility.ArrayOf(
                                       mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.StructGet,
                                                                              mainProcessor.CreateVariableReferenceFromName(tempVar), structSource,
                                                                              structField),
                                       mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                              allVariables[index],
                                                                              mainProcessor.CreateVariableReferenceFromName(tempVar))));
                        }

                        if (heapObj.Value is PapyrusFieldDefinition)
                        {
                            heapObj.Value = (heapObj.Value as PapyrusFieldDefinition).DefaultValue;
                        }
                        if (heapObj.Value is PapyrusVariableReference)
                        {
                            var varRef = heapObj.Value as PapyrusVariableReference;
                            allVariables[index].Value = allVariables[index].Name.Value;
                            //varRef.Name.Value;
                            // "Assign " + allVariables[(int)index].Name.Value + " " + varRef.Name.Value;
                            return
                                (ArrayUtility.ArrayOf(
                                     mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                            allVariables[index], varRef)));
                        }
                        // allVariables[index].Value
                        outVal = valueTypeConverter.Convert(allVariables[index].TypeName.Value, heapObj.Value);
                    }
                    var valout = outVal; //allVariables[index].Value;


                    //if (valout is string)
                    //{
                    //    stringValue = valout.ToString();
                    //}

                    if (valout is PapyrusFieldDefinition)
                    {
                        return
                            (ArrayUtility.ArrayOf(mainProcessor.CreatePapyrusInstruction(
                                                      PapyrusOpCodes.Assign, allVariables[index], valout as PapyrusFieldDefinition)));
                    }

                    if (valout is PapyrusVariableReference)
                    {
                        return
                            (ArrayUtility.ArrayOf(mainProcessor.CreatePapyrusInstruction(
                                                      PapyrusOpCodes.Assign, allVariables[index], valout as PapyrusVariableReference)));
                    }

                    if (valout is PapyrusParameterDefinition)
                    {
                        return
                            (ArrayUtility.ArrayOf(mainProcessor.CreatePapyrusInstruction(
                                                      PapyrusOpCodes.Assign, allVariables[index], valout as PapyrusParameterDefinition)));
                    }


                    // "Assign " + allVariables[(int)index].Name.Value + " " + valoutStr;

                    if (valout == null)
                    {
                        valout = "None";
                    }

                    if (allVariables[index].IsDelegateReference)
                    {
                        // If this is a delegate reference, then we do not want to assign this value to anything.
                        return(new PapyrusInstruction[0]);
                    }

                    return
                        (ArrayUtility.ArrayOf(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                                     allVariables[index], valout)));
                }
            }
            return(new PapyrusInstruction[0]);
        }
コード例 #4
0
        /// <summary>
        /// Processes the conditional instruction.
        /// </summary>
        /// <param name="mainProcessor">The main instruction processor.</param>
        /// <param name="instruction">The instruction.</param>
        /// <param name="overrideOpCode">The override op code.</param>
        /// <param name="tempVariable">The temporary variable.</param>
        /// <returns></returns>
        public IEnumerable <PapyrusInstruction> Process(
            IClrInstructionProcessor mainProcessor,
            Instruction instruction,
            Code overrideOpCode = Code.Nop,
            string tempVariable = null)
        {
            bool isStructAccess;
            var  output = new List <PapyrusInstruction>();

            //cast = null;

            var heapStack = mainProcessor.EvaluationStack;

            // TODO: GetConditional only applies on Integers and must add support for Float further on.

            var papyrusOpCode =
                Utility.GetPapyrusMathOrEqualityOpCode(
                    overrideOpCode != Code.Nop ? overrideOpCode : instruction.OpCode.Code, false);

            if (heapStack.Count >= 2) //Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop))
            {
                var numeratorObject   = heapStack.Pop();
                var denumeratorObject = heapStack.Pop();
                var vars = mainProcessor.PapyrusMethod.GetVariables();
                int varIndex;

                object numerator;
                object denumerator;


                if (numeratorObject.Value is PapyrusFieldDefinition)
                {
                    numeratorObject.Value = (numeratorObject.Value as PapyrusFieldDefinition).DefaultValue;
                }

                if (denumeratorObject.Value is PapyrusFieldDefinition)
                {
                    denumeratorObject.Value = (denumeratorObject.Value as PapyrusFieldDefinition).DefaultValue;
                }

                if (numeratorObject.Value is PapyrusVariableReference)
                {
                    var varRef      = numeratorObject.Value as PapyrusVariableReference;
                    var refTypeName = varRef.TypeName?.Value;

                    if (refTypeName == null)
                    {
                        refTypeName = "Int";
                    }

                    numerator = varRef;

                    // if not int or string, we need to cast it.
                    if (!refTypeName.ToLower().Equals("int") && !refTypeName.ToLower().Equals("system.int32") &&
                        !refTypeName.ToLower().Equals("system.string") && !refTypeName.ToLower().Equals("string"))
                    {
                        var typeVariable = mainProcessor.GetTargetVariable(instruction, null,
                                                                           out isStructAccess, "Int");
                        output.Add(mainProcessor.CreatePapyrusCastInstruction(typeVariable, varRef));
                        // cast = "Cast " + typeVariable + " " + value1;
                    }
                }
                else if (numeratorObject.Value is FieldReference)
                {
                    numerator =
                        mainProcessor.CreateVariableReferenceFromName(
                            (numeratorObject.Value as FieldReference).Name);
                }
                else
                {
                    numerator = mainProcessor.CreateVariableReference(
                        Utility.GetPrimitiveTypeFromValue(numeratorObject.Value),
                        numeratorObject.Value);
                }

                if (denumeratorObject.Value is PapyrusVariableReference)
                {
                    var varRef      = denumeratorObject.Value as PapyrusVariableReference;
                    var refTypeName = varRef.TypeName.Value;
                    denumerator = varRef;

                    // if not int or string, we need to cast it.
                    if (!refTypeName.ToLower().Equals("int") && !refTypeName.ToLower().Equals("system.int32") &&
                        !refTypeName.ToLower().Equals("system.string") && !refTypeName.ToLower().Equals("string"))
                    {
                        // CAST BOOL TO INT
                        // var typeVariable = GetTargetVariable(instruction, null, "Int");
                        // cast = "Cast " + typeVariable + " " + value2;

                        var typeVariable = mainProcessor.GetTargetVariable(instruction, null,
                                                                           out isStructAccess, "Int");
                        output.Add(mainProcessor.CreatePapyrusCastInstruction(typeVariable, varRef));
                    }
                }
                else if (denumeratorObject.Value is FieldReference)
                {
                    denumerator =
                        mainProcessor.CreateVariableReferenceFromName(
                            (denumeratorObject.Value as FieldReference).Name);
                }
                else
                {
                    denumerator =
                        mainProcessor.CreateVariableReference(
                            Utility.GetPrimitiveTypeFromValue(denumeratorObject.Value), denumeratorObject.Value);
                }

                if (!string.IsNullOrEmpty(tempVariable))
                {
                    output.Add(mainProcessor.CreatePapyrusInstruction(papyrusOpCode,
                                                                      mainProcessor.CreateVariableReferenceFromName(tempVariable), denumerator, numerator));
                    return(output);
                }

                // if (Utility.IsGreaterThan(code) || Utility.IsLessThan(code))
                {
                    var next = instruction.Next;

                    // If the next one is a switch, it most likely
                    // means that we want to apply some mathematical stuff
                    // on our constant value so that we can properly do an equality
                    // comparison.
                    if (InstructionHelper.IsSwitch(next.OpCode.Code))
                    {
                        var newTempVariable = mainProcessor.GetTargetVariable(instruction, null,
                                                                              out isStructAccess, "Int", true);
                        mainProcessor.SwitchConditionalComparer =
                            mainProcessor.CreateVariableReferenceFromName(newTempVariable);
                        mainProcessor.SwitchConditionalComparer.Type     = PapyrusPrimitiveType.Reference;
                        mainProcessor.SwitchConditionalComparer.TypeName =
                            "Int".Ref(mainProcessor.PapyrusAssembly);

                        output.Add(mainProcessor.CreatePapyrusInstruction(papyrusOpCode,
                                                                          mainProcessor.SwitchConditionalComparer, denumerator, numerator));
                        return(output);
                    }

                    while (next != null &&
                           !InstructionHelper.IsStoreLocalVariable(next.OpCode.Code) &&
                           !InstructionHelper.IsStoreFieldObject(next.OpCode.Code) &&
                           !InstructionHelper.IsCallMethod(next.OpCode.Code))
                    {
                        next = next.Next;
                    }

                    if (next != null && next.Operand is MethodReference)
                    {
                        // if none found, create a temp one.
                        var methodRef = next.Operand as MethodReference;

                        var tVar = mainProcessor.CreateTempVariable(
                            methodRef.MethodReturnType.ReturnType.FullName != "System.Void"
                                ? methodRef.MethodReturnType.ReturnType.FullName
                                : "System.int");

                        var targetVar = tVar;

                        mainProcessor.EvaluationStack.Push(new EvaluationStackItem
                        {
                            Value    = tVar.Value,
                            TypeName = tVar.TypeName.Value
                        });

                        output.Add(mainProcessor.CreatePapyrusInstruction(papyrusOpCode, targetVar,
                                                                          denumerator, numerator));
                        return(output);
                    }


                    if (next == null)
                    {
                        // No intentions to store this value into a variable,
                        // Its to be used in a function call.
                        //return "NULLPTR " + denumerator + " " + numerator;
                        return(output);
                    }

                    mainProcessor.SkipToOffset = next.Offset;
                    if (next.Operand is FieldReference)
                    {
                        var field     = mainProcessor.GetFieldFromStfld(next);
                        var structRef = field as PapyrusStructFieldReference;
                        if (structRef != null)
                        {
                            // output.Add(mainInstructionProcessor.CreatePapyrusInstruction(papyrusOpCode, field, denumerator, numerator));
                            // structRef.
                        }
                        else if (field != null)
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(papyrusOpCode, field,
                                                                              denumerator, numerator));
                            return(output);
                            // LastSaughtTypeName = fieldData.TypeName;
                        }

                        //if (field != null)
                        //{
                        //    output.Add(mainInstructionProcessor.CreatePapyrusInstruction(papyrusOpCode, field, denumerator, numerator));
                        //    return output;
                        //    //return field.Name + " " + denumerator + " " + numerator;
                        //}
                    }


                    var numericValue = mainProcessor.GetNumericValue(next);
                    varIndex = (int)numericValue;
                }

                output.Add(mainProcessor.CreatePapyrusInstruction(papyrusOpCode, vars[varIndex], denumerator,
                                                                  numerator));
                //return vars[varIndex].Name + " " + denumerator + " " + numerator;
            }
            else if (mainProcessor.PapyrusCompilerOptions == PapyrusCompilerOptions.Strict)
            {
                throw new StackUnderflowException();
            }
            return(output);
        }