/// <summary>
 /// Processes the specified 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>
 /// <exception cref="System.NotImplementedException"></exception>
 public IEnumerable <PapyrusInstruction> Process(
     IClrInstructionProcessor mainProcessor,
     IReadOnlyCollection <PapyrusAssemblyDefinition> asmCollection, Instruction instruction,
     MethodDefinition targetMethod, TypeDefinition type)
 {
     throw new NotImplementedException();
 }
Пример #2
0
        /// <summary>
        /// Ensures the parameter types.
        /// </summary>
        /// <param name="mainInstructionProcessor">The main instruction processor.</param>
        /// <param name="parameters">The parameters.</param>
        /// <param name="papyrusParams">The papyrus parameters.</param>
        /// <returns></returns>
        public IEnumerable <PapyrusVariableReference> EnsureParameterTypes(IClrInstructionProcessor mainInstructionProcessor, Collection <ParameterDefinition> parameters,
                                                                           List <PapyrusVariableReference> papyrusParams)
        {
            var varRefs = new List <PapyrusVariableReference>();
            var i       = 0;

            foreach (var p in parameters)
            {
                var papyrusReturnType = Utility.GetPapyrusReturnType(p.ParameterType);
                if (p.ParameterType.IsValueType &&
                    Utility.PapyrusValueTypeToString(papyrusParams[i].Type) != papyrusReturnType &&
                    papyrusParams[i].Type != PapyrusPrimitiveType.Reference)
                {
                    papyrusParams[i].TypeName = papyrusReturnType.Ref(mainInstructionProcessor.PapyrusAssembly);
                    papyrusParams[i].Type     = Utility.GetPrimitiveTypeFromType(p.ParameterType);
                    papyrusParams[i].Value    = valueTypeConverter.Convert(papyrusReturnType, papyrusParams[i].Value);
                    varRefs.Add(papyrusParams[i]);
                }
                else
                {
                    varRefs.Add(papyrusParams[i]);
                }
                i++;
            }

            return(varRefs);
        }
Пример #3
0
 public PapyrusDotNetApp(string[] args,
                         IUserInterface ui,
                         IClrInstructionProcessor instructorProcessor,
                         INameConventionResolver nameResolver)
 {
     this.args = args;
     this.ui   = ui;
     this.instructorProcessor = instructorProcessor;
     this.nameResolver        = nameResolver;
 }
Пример #4
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="Clr2PapyrusConverter" /> class.
 /// </summary>
 /// <param name="userInterface"></param>
 /// <param name="instructionProcessor">The instruction processor.</param>
 /// <param name="processorOptions"></param>
 public Clr2PapyrusConverter(
     IUserInterface userInterface,
     IClrInstructionProcessor instructionProcessor,
     PapyrusCompilerOptions processorOptions)
 {
     attributeReader           = new PapyrusAttributeReader(new PapyrusValueTypeConverter());
     this.userInterface        = userInterface;
     this.instructionProcessor = instructionProcessor;
     this.processorOptions     = processorOptions;
     delegateFinder            = new DelegateFinder();
 }
Пример #5
0
        /// <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);
        }
        /// <summary>
        /// Processes the specified instruction.
        /// </summary>
        /// <param name="mainProcessor">The main instruction processor.</param>
        /// <param name="instruction">The instruction.</param>
        /// <param name="methodRef">The method reference.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public List <PapyrusInstruction> Process(
            IClrInstructionProcessor mainProcessor,
            Instruction instruction, MethodReference methodRef,
            List <object> parameters)
        {
            // BUG: We are always concating the string with itself, ex: temp0 = temp0 + "val"; - This works if the instruction isnt looped.
            var output = new List <PapyrusInstruction>();
            // Equiviliant Papyrus: StrCat <output_destination> <val1> <val2>
            // Make sure we have a temp variable if necessary
            bool isStructAccess;
            var  destinationVariable = mainProcessor.GetTargetVariable(instruction, methodRef,
                                                                       out isStructAccess);

            for (var i = 0; i < parameters.Count; i++)
            {
                var stackItem = parameters[i] as EvaluationStackItem;
                if (stackItem != null)
                {
                    var fieldVar  = stackItem.Value as PapyrusFieldDefinition;
                    var paramVar  = stackItem.Value as PapyrusParameterDefinition;
                    var targetVar = stackItem.Value as PapyrusVariableReference;
                    if (targetVar != null)
                    {
                        if (!stackItem.TypeName.ToLower().Contains("string"))
                        {
                            output.Add(mainProcessor.CreatePapyrusCastInstruction(destinationVariable,
                                                                                  targetVar));
                        }

                        if (i == 0)
                        // Is First? Then we just want to assign the destinationVariable with the target value
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable), targetVar));
                        }
                        else
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Strcat,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              targetVar));
                        }
                    }
                    else if (paramVar != null)
                    {
                        if (!stackItem.TypeName.ToLower().Contains("string"))
                        {
                            output.Add(mainProcessor.CreatePapyrusCastInstruction(destinationVariable,
                                                                                  mainProcessor.CreateVariableReferenceFromName(paramVar.Name.Value)));
                        }

                        if (i == 0)
                        // Is First? Then we just want to assign the destinationVariable with the target value
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable), paramVar));
                        }
                        else
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Strcat,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              paramVar));
                        }
                    }
                    else if (fieldVar != null)
                    {
                        if (!stackItem.TypeName.ToLower().Contains("string"))
                        {
                            output.Add(mainProcessor.CreatePapyrusCastInstruction(destinationVariable,
                                                                                  mainProcessor.CreateVariableReferenceFromName(fieldVar.Name.Value)));
                        }

                        if (i == 0)
                        // Is First? Then we just want to assign the destinationVariable with the target value
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable), fieldVar));
                        }
                        else
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Strcat,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              fieldVar));
                        }
                    }
                    else
                    {
                        var value      = stackItem.Value;
                        var newTempVar = false;
                        if (!stackItem.TypeName.ToLower().Contains("string"))
                        {
                            // First, get a new temp variable of type string.
                            // This new temp variable will be used for casting the source object into a string.
                            value = mainProcessor.GetTargetVariable(instruction, methodRef,
                                                                    out isStructAccess, "String", true);

                            // Create a new temp variable that we use to assign our source object to.
                            // this is so we avoid doing ex: cast ::temp0 55
                            // and instead we do: cast ::temp0 ::temp1
                            var valueToCastTemp = mainProcessor.GetTargetVariable(instruction, methodRef,
                                                                                  out isStructAccess, stackItem.TypeName, true);
                            var valueToCast =
                                mainProcessor.CreateVariableReference(
                                    Utility.GetPrimitiveTypeFromValue(stackItem.Value),
                                    stackItem.Value);

                            // Assign our newly created tempvalue with our object.
                            // ex: assign ::temp1 55
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    valueToCastTemp),
                                                                              valueToCast));

                            // Cast the new ::temp1 to ::temp0 (equivilant to .ToString())
                            output.Add(mainProcessor.CreatePapyrusCastInstruction((string)value,
                                                                                  mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                        valueToCastTemp)));
                            newTempVar = true;

                            // Make sure that our newly ::temp1 is used when concating the string.
                            value = valueToCastTemp;
                        }

                        if (i == 0)
                        // Is First? Then we just want to assign the destinationVariable with the target value
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Assign,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              mainProcessor.CreateVariableReference(newTempVar
                                    ? PapyrusPrimitiveType.Reference
                                    : PapyrusPrimitiveType.String, value)));
                        }
                        else
                        {
                            output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Strcat,
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              mainProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference,
                                                                                                                    destinationVariable),
                                                                              mainProcessor.CreateVariableReference(newTempVar
                                    ? PapyrusPrimitiveType.Reference
                                    : PapyrusPrimitiveType.String, value)));
                        }
                    }
                }
            }

            // TODO: In case we want to concat more strings together or call a method using this new value
            // we will have to use the targetVariable above and push it back into the stack. (Or do we...?)
            return(output);
        }
Пример #7
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);
        }
Пример #8
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]);
        }
Пример #9
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="targetType">Type of the target.</param>
        /// <returns></returns>
        /// <exception cref="StackUnderflowException"></exception>
        public IEnumerable <PapyrusInstruction> Process(
            IClrInstructionProcessor mainProcessor,
            IReadOnlyCollection <PapyrusAssemblyDefinition> asmCollection,
            Instruction instruction,
            MethodDefinition targetMethod,
            TypeDefinition targetType)
        {
            bool isStructAccess;
            var  structGets = new List <PapyrusInstruction>();

            this.papyrusAssemblyCollection = asmCollection;
            var processInstruction = new List <PapyrusInstruction>();
            var stack = mainProcessor.EvaluationStack;

            currentInstruction = instruction;
            var methodRef = instruction.Operand as MethodReference;

            if (methodRef != null)
            {
                if (methodRef.FullName.ToLower().Contains("system.void") &&
                    methodRef.FullName.ToLower().Contains(".ctor"))
                {
                    return(new PapyrusInstruction[0]);
                }

                // What we need:
                // 1. Call Location (The name of the type that has this method)
                // 2. Method Name (The name of the method, duh)
                // 3. Method Parameters (The parameters that we need to pass to the method)
                // 4. Destination Variable (The variable needed to store the return value of the method)
                //      - Destination Variable must always exist, the difference between a function returning a object
                //        and a void, is that we "assign" the destination to a ::nonevar temp variable of type None (void)

                var name       = methodRef.FullName;
                var itemsToPop = instruction.OpCode.StackBehaviourPop == StackBehaviour.Varpop
                    ? methodRef.Parameters.Count
                    : Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop);

                if (stack.Count < itemsToPop)
                {
                    if (mainProcessor.PapyrusCompilerOptions == PapyrusCompilerOptions.Strict)
                    {
                        throw new StackUnderflowException(targetMethod, instruction);
                    }
                    return(processInstruction);
                }

                // Check if the current invoked Method is inside the same instance of this type
                // by checking if it is using "this.Method(params);" << "this."...
                var isThisCall     = false;
                var isStaticCall   = false;
                var callerLocation = "";
                var parameters     = new List <object>();

                if (methodRef.HasThis)
                {
                    callerLocation = "self";
                    isThisCall     = true;
                }

                for (var paramIndex = 0; paramIndex < itemsToPop; paramIndex++)
                {
                    var parameter = stack.Pop();
                    if (parameter.IsThis && stack.Count > methodRef.Parameters.Count ||
                        methodRef.CallingConvention == MethodCallingConvention.ThisCall)
                    {
                        isThisCall     = true;
                        callerLocation = "self"; // Location: 'self' is the same as 'this'
                    }
                    parameters.Insert(0, parameter);
                }

                var methodDefinition = mainProcessor.TryResolveMethodReference(methodRef);
                if (methodDefinition != null)
                {
                    isStaticCall = methodDefinition.IsStatic;
                }

                if (methodDefinition != null && methodDefinition.IsConstructor)
                {
                    return(processInstruction);
                }

                if (methodDefinition == null)
                {
                    isStaticCall = name.Contains("::");
                }

                if (isStaticCall)
                {
                    callerLocation = name.Split("::")[0];
                }

                if (callerLocation.Contains("."))
                {
                    callerLocation = callerLocation.Split('.').LastOrDefault();
                }

                if (methodRef.Name.ToLower().Contains("concat"))
                {
                    processInstruction.AddRange(mainProcessor.ProcessStringConcat(instruction, methodRef,
                                                                                  parameters));
                }
                else if (methodRef.Name.ToLower().Contains("op_equal") ||
                         methodRef.Name.ToLower().Contains("op_inequal"))
                {
                    // TODO: Add Equality comparison

                    mainProcessor.InvertedBranch = methodRef.Name.ToLower().Contains("op_inequal");

                    if (!InstructionHelper.IsStore(instruction.Next.OpCode.Code))
                    {
                        mainProcessor.SkipToOffset = instruction.Next.Offset;
                        return(processInstruction);
                    }
                    // EvaluationStack.Push(new EvaluationStackItem { IsMethodCall = true, Value = methodRef, TypeName = methodRef.ReturnType.FullName });

                    processInstruction.AddRange(mainProcessor.ProcessConditionalInstruction(instruction,
                                                                                            Code.Ceq));
                }
                else
                {
                    if (methodRef.Name.ToLower().StartsWith("get_") || methodRef.Name.ToLower().StartsWith("set_"))
                    {
                        processInstruction.AddRange(ProcessPropertyAccess(mainProcessor, instruction, methodRef, methodDefinition,
                                                                          parameters));

                        return(processInstruction);
                    }


                    if (isStaticCall)
                    {
                        var destinationVariable = mainProcessor.GetTargetVariable(instruction, methodRef,
                                                                                  out isStructAccess);
                        {
                            processInstruction.Add(CreatePapyrusCallInstruction(mainProcessor, PapyrusOpCodes.Callstatic, methodRef,
                                                                                callerLocation,
                                                                                destinationVariable, parameters, out structGets));
                            processInstruction.InsertRange(processInstruction.Count - 1, structGets);
                            return(processInstruction);
                        }
                    }
                    if (isThisCall)
                    {
                        var isDelegateInvoke = false;
                        if (stack.Count > 0)
                        {
                            var next   = stack.Peek().Value;
                            var varRef = next as PapyrusVariableReference;
                            if (varRef != null && varRef.IsDelegateReference)
                            {
                                isDelegateInvoke = true;
                            }
                        }

                        var destinationVariable = mainProcessor.GetTargetVariable(instruction, methodRef,
                                                                                  out isStructAccess);

                        if (isDelegateInvoke)
                        {
                            var targetDelegate           = stack.Pop().Value as PapyrusVariableReference;
                            var targetDelegateMethodName = targetDelegate.DelegateInvokeReference;

                            // In case we are invoking a delegate from inside a delegate then we need to find the
                            // reference to the previous delegate method and use that one instead.
                            var target = InstructionHelper.FindPreviousInstruction(instruction,
                                                                                   InstructionHelper.IsLoadMethodRef);
                            if (target != null && target.Operand is MethodReference)
                            {
                                methodRef = target.Operand as MethodReference;
                                targetDelegateMethodName = methodRef.Name;
                            }

                            processInstruction.Add(CreatePapyrusCallInstruction(mainProcessor, PapyrusOpCodes.Callmethod, methodRef,
                                                                                callerLocation, destinationVariable, parameters, out structGets,
                                                                                targetDelegateMethodName));
                            processInstruction.InsertRange(processInstruction.Count - 1, structGets);
                        }
                        else
                        {
                            if (isStructAccess)
                            {
                                var structRef =
                                    stack.Pop().Value as PapyrusStructFieldReference;
                                if (structRef != null)
                                {
                                    // (Call and Assign Temp then do StructSet using Temp)

                                    // Call and Assign return value to temp
                                    processInstruction.Add(CreatePapyrusCallInstruction(mainProcessor, PapyrusOpCodes.Callmethod,
                                                                                        methodRef,
                                                                                        callerLocation,
                                                                                        destinationVariable, parameters, out structGets));

                                    // StructSet
                                    processInstruction.Add(
                                        mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.StructSet,
                                                                               structRef.StructSource, structRef.StructVariable,
                                                                               mainProcessor.CreateVariableReferenceFromName(destinationVariable)));

                                    // Skip next instruction as it should be stfld and we already store the field here.
                                    mainProcessor.SkipNextInstruction = true;
                                }
                            }
                            else
                            {
                                processInstruction.Add(CreatePapyrusCallInstruction(mainProcessor, PapyrusOpCodes.Callmethod, methodRef,
                                                                                    callerLocation,
                                                                                    destinationVariable, parameters, out structGets));
                                processInstruction.InsertRange(processInstruction.Count - 1, structGets);
                            }
                        }
                        return(processInstruction);
                    }
                }
            }
            return(processInstruction);
        }
Пример #10
0
        /// <summary>
        /// Creates a papyrus call instruction.
        /// </summary>
        /// <param name="mainInstructionProcessor">The main instruction processor.</param>
        /// <param name="callOpCode">The call op code.</param>
        /// <param name="methodRef">The method reference.</param>
        /// <param name="callerLocation">The caller location.</param>
        /// <param name="destinationVariable">The destination variable.</param>
        /// <param name="parameters">The parameters.</param>
        /// <param name="structGets">The structure gets.</param>
        /// <param name="methodName">Name of the method.</param>
        /// <returns></returns>
        public PapyrusInstruction CreatePapyrusCallInstruction(
            IClrInstructionProcessor mainInstructionProcessor,
            PapyrusOpCodes callOpCode, MethodReference methodRef,
            string callerLocation, string destinationVariable, List <object> parameters,
            out List <PapyrusInstruction> structGets, string methodName = null)
        {
            structGets = new List <PapyrusInstruction>();

            var inst = new PapyrusInstruction {
                OpCode = callOpCode
            };

            var param = parameters.ToArray();

            for (var index = 0; index < param.Length; index++)
            {
                var p = param[index];
                PapyrusStructFieldReference structRef = null;
                var evalItem = p as EvaluationStackItem;

                if (evalItem != null)
                {
                    structRef = evalItem.Value as PapyrusStructFieldReference;
                }
                if (structRef == null)
                {
                    structRef = p as PapyrusStructFieldReference;
                }
                if (structRef != null)
                {
                    var structSource = structRef.StructSource as PapyrusFieldDefinition;
                    var structField  = structRef.StructVariable;

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

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

                    param[index] = mainInstructionProcessor.CreateVariableReferenceFromName(tempVar);

                    // 2. StructGet -> tempVar
                    // 3. Assign var <- tempVar
                    structGets.Add(mainInstructionProcessor.CreatePapyrusInstruction(
                                       PapyrusOpCodes.StructGet,
                                       mainInstructionProcessor.CreateVariableReferenceFromName(tempVar), structSource,
                                       structField));
                }
            }

            methodName = methodName ?? methodRef.Name;

            if (callOpCode == PapyrusOpCodes.Callstatic)
            {
                inst.Arguments.AddRange(mainInstructionProcessor.ParsePapyrusParameters(new object[]
                {
                    mainInstructionProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference, callerLocation),
                    mainInstructionProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference, methodName),
                    mainInstructionProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference, destinationVariable)
                }));
            }
            else
            {
                inst.Arguments.AddRange(mainInstructionProcessor.ParsePapyrusParameters(new object[]
                {
                    mainInstructionProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference, methodName),
                    mainInstructionProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference, callerLocation),
                    mainInstructionProcessor.CreateVariableReference(PapyrusPrimitiveType.Reference, destinationVariable)
                }));
            }
            inst.OperandArguments.AddRange(EnsureParameterTypes(mainInstructionProcessor, methodRef.Parameters,
                                                                mainInstructionProcessor.ParsePapyrusParameters(param)));
            inst.Operand = methodRef;
            return(inst);
        }
Пример #11
0
        private IEnumerable <PapyrusInstruction> ProcessPropertyAccess(IClrInstructionProcessor mainInstructionProcessor, Instruction instruction, MethodReference methodRef,
                                                                       MethodDefinition methodDefinition,
                                                                       List <object> parameters)
        {
            bool isStructAccess;
            var  instructions = new List <PapyrusInstruction>();

            if (methodRef is MethodDefinition)
            {
                methodDefinition = methodRef as MethodDefinition;
            }

            // If the property access is from outside the same class (Property exists outside the calling class)
            if (methodDefinition == null && methodRef != null)
            {
                var type               = methodRef.DeclaringType;
                var methodType         = methodRef.Name.Remove(3);
                var targetPropertyName = methodRef.Name.Substring(4);

                if (methodType == "set")
                {
                    var param            = parameters;
                    var stack            = mainInstructionProcessor.EvaluationStack;
                    var locationVariable = stack.Pop().Value;
                    instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropSet,
                                                                                       mainInstructionProcessor.CreateVariableReferenceFromName(targetPropertyName),
                                                                                       locationVariable,
                                                                                       param.First()
                                                                                       ));
                }
                else if (methodType == "get")
                {
                    var stack               = mainInstructionProcessor.EvaluationStack;
                    var locationVariable    = stack.Pop().Value;
                    var destinationVariable = mainInstructionProcessor.GetTargetVariable(instruction, methodRef,
                                                                                         out isStructAccess);

                    if (isStructAccess)
                    {
                        var structRef =
                            mainInstructionProcessor.EvaluationStack.Pop().Value as PapyrusStructFieldReference;
                        if (structRef != null)
                        {
                            // (Get Property Value and Assign Temp then do StructSet using Temp)
                            instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropGet,
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName(targetPropertyName),
                                                                                               locationVariable,
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName(destinationVariable)
                                                                                               ));

                            // StructSet
                            instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.StructSet,
                                                                                               structRef.StructSource, structRef.StructVariable,
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName(destinationVariable)));

                            // Skip next instruction as it should be stfld and we already store the field here.
                            mainInstructionProcessor.SkipNextInstruction = true;
                        }
                    }
                    else
                    {
                        instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropGet,
                                                                                           mainInstructionProcessor.CreateVariableReferenceFromName(targetPropertyName),
                                                                                           locationVariable,
                                                                                           mainInstructionProcessor.CreateVariableReferenceFromName(destinationVariable)
                                                                                           ));
                    }
                }
                else
                {
                    throw new InvalidPropertyAccessException();
                }
                return(instructions);
            }

            // Property Access within same class (Property exists within the same class)
            if (methodDefinition != null)
            {
                var targetPropertyName = methodRef.Name.Substring(4);

                var matchingProperty = mainInstructionProcessor.PapyrusType.Properties.FirstOrDefault(
                    p => (p.SetMethod != null && p.SetMethod.Name.Value.ToLower().Equals(methodRef.Name.ToLower())) ||
                    (p.GetMethod != null && p.GetMethod.Name.Value.ToLower().Equals(methodRef.Name.ToLower())) ||
                    p.Name.Value.ToLower() == targetPropertyName.ToLower());
                if (matchingProperty != null)
                {
                    if (methodDefinition.IsSetter)
                    {
                        var param      = parameters;
                        var firstParam = param.First();
                        PapyrusStructFieldReference structRef = null;
                        var eva1 = firstParam as PapyrusStructFieldReference;
                        var eval = firstParam as EvaluationStackItem;
                        if (eval != null)
                        {
                            structRef = eval.Value as PapyrusStructFieldReference;
                        }
                        if (eva1 != null)
                        {
                            structRef = eva1;
                        }

                        if (structRef != null)
                        {
                            // Create Temp Var

                            // StructGet -> TempVar
                            // PropSet TempVar

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

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

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

                            // 2. StructGet -> tempVar
                            // 3. Assign var <- tempVar
                            instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(
                                                 PapyrusOpCodes.StructGet,
                                                 mainInstructionProcessor.CreateVariableReferenceFromName(tempVar), structSource,
                                                 structField));

                            instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropSet,
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName(matchingProperty.Name.Value),
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName("self"),
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName(tempVar)
                                                                                               ));
                        }
                        else
                        {
                            instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropSet,
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName(matchingProperty.Name.Value),
                                                                                               mainInstructionProcessor.CreateVariableReferenceFromName("self"),
                                                                                               firstParam
                                                                                               ));
                        }
                    }
                    else if (methodDefinition.IsGetter)
                    {
                        var destinationVariable = mainInstructionProcessor.GetTargetVariable(instruction, methodRef,
                                                                                             out isStructAccess);
                        var locationVariable = mainInstructionProcessor.CreateVariableReferenceFromName("self");
                        var targetProperty   =
                            mainInstructionProcessor.CreateVariableReferenceFromName(matchingProperty.Name.Value);
                        if (isStructAccess)
                        {
                            var structRef =
                                mainInstructionProcessor.EvaluationStack.Pop().Value as PapyrusStructFieldReference;
                            if (structRef != null)
                            {
                                // (Get Property Value and Assign Temp then do StructSet using Temp)
                                instructions.Add(
                                    mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropGet,
                                                                                      targetProperty,
                                                                                      locationVariable,
                                                                                      mainInstructionProcessor.CreateVariableReferenceFromName(destinationVariable)
                                                                                      ));

                                // StructSet
                                instructions.Add(
                                    mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.StructSet,
                                                                                      structRef.StructSource, structRef.StructVariable,
                                                                                      mainInstructionProcessor.CreateVariableReferenceFromName(destinationVariable)));

                                // Skip next instruction as it should be stfld and we already store the field here.
                                mainInstructionProcessor.SkipNextInstruction = true;
                            }
                        }
                        else
                        {
                            var dest = mainInstructionProcessor.CreateVariableReferenceFromName(destinationVariable);
                            instructions.Add(mainInstructionProcessor.CreatePapyrusInstruction(PapyrusOpCodes.PropGet,
                                                                                               targetProperty,
                                                                                               locationVariable,
                                                                                               dest
                                                                                               ));

                            if (InstructionHelper.NextInstructionIs(instruction, InstructionHelper.IsConditional))
                            {
                                mainInstructionProcessor.EvaluationStack.Push(new EvaluationStackItem
                                {
                                    Value    = dest,
                                    TypeName = Utility.GetPapyrusReturnType(methodRef.ReturnType)
                                });
                            }
                        }
                    }
                }
            }
            return(instructions);
        }
Пример #12
0
        /// <summary>
        /// Processes the specified 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)
        {
            var output = new List <PapyrusInstruction>();

            if (Utility.IsVoid(targetMethod.ReturnType))
            {
                output.Add(PapyrusReturnNone());
                return(output);
            }

            if (mainProcessor.EvaluationStack.Count >=
                Utility.GetStackPopCount(instruction.OpCode.StackBehaviourPop))
            {
                var topValue = mainProcessor.EvaluationStack.Pop();
                if (topValue.Value is PapyrusVariableReference)
                {
                    var variable = topValue.Value as PapyrusVariableReference;
                    // return "Return " + variable.Name;

                    output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Return, variable));
                    // PapyrusReturnVariable(variable.Name)

                    return(output);
                }
                if (topValue.Value is PapyrusFieldDefinition)
                {
                    var variable = topValue.Value as PapyrusFieldDefinition;
                    // return "Return " + variable.Name;
                    output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Return, variable));
                    return(output);
                }
                if (Utility.IsConstantValue(topValue.Value))
                {
                    var val = topValue.Value;

                    var typeName = topValue.TypeName;
                    var newValue = valueTypeConverter.Convert(typeName, val);
                    var papyrusVariableReference = new PapyrusVariableReference
                    {
                        TypeName = StringExtensions.Ref(typeName, mainProcessor.PapyrusAssembly),
                        Value    = newValue,
                        Type     = Utility.GetPapyrusPrimitiveType(typeName)
                    };
                    {
                        output.Add(mainProcessor.CreatePapyrusInstruction(PapyrusOpCodes.Return,
                                                                          papyrusVariableReference));
                        return(output);
                    }
                }
            }
            else
            {
                output.Add(PapyrusReturnNone());
                return(output);
            }
            return(output);
        }
        /// <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);
        }