/// <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); }
/// <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); }