public PapyrusFieldEditorViewModel(IEnumerable <string> availableTypes, PapyrusFieldDefinition fieldToEdit = null) : base(availableTypes) { this.fieldToEdit = fieldToEdit; if (fieldToEdit != null) { Name = fieldToEdit.Name.Value; if (fieldToEdit.DefaultValue != null) { if (fieldToEdit.DefaultValue.Value != null) { DefaultValue = fieldToEdit.DefaultValue.Value; } } if (fieldToEdit.TypeName.Contains("[]")) { IsArray = true; } var ft = fieldToEdit.TypeName.ToLower(); ft = ft.Replace("[]", ""); SelectedType = TypeReferences.FirstOrDefault(t => t.ToString().ToLower() == ft); if (SelectedType == null) { SelectedType = fieldToEdit.TypeName.ToLower(); } } }
private void WriteFieldDefinition(PapyrusFieldDefinition field) { pexWriter.Write(field.Name); pexWriter.Write(field.TypeName); pexWriter.Write(field.UserFlags); WriteValueReference(field.DefaultValue); pexWriter.Write(field.Flags); }
private IEnumerable <PapyrusFieldDefinition> CreateFields(TypeDefinition type, PapyrusAssemblyDefinition pex) { var fields = new List <PapyrusFieldDefinition>(); var delegateFields = delegatePairDefinition.DelegateMethodFieldPair.SelectMany(i => i.Value).ToList(); var typeFields = new List <FieldDefinition>(); typeFields.AddRange(delegateFields); typeFields.AddRange(type.Fields); foreach (var field in typeFields) { var papyrusFriendlyName = "::" + field.Name.Replace("::", "").Replace('<', '_').Replace('>', '_'); // Only for the VariableReference var fieldName = field.Name; if (delegateFields.Contains(field)) { var method = Utility.GetKeyByValue(delegatePairDefinition.DelegateMethodFieldPair, field); papyrusFriendlyName = "::" + method.Name + "_" + papyrusFriendlyName.Replace("::", ""); fieldName = papyrusFriendlyName; } var properties = attributeReader.ReadPapyrusAttributes(field); var fieldType = Utility.GetPapyrusReturnType(field.FieldType, type); if (EnumDefinitions.Any(i => i.FullName == field.FieldType.FullName)) { fieldType = "Int"; } var nameRef = papyrusFriendlyName.Ref(pex); var papyrusFieldDefinition = new PapyrusFieldDefinition(pex, null, fieldName, fieldType) { DefaultValue = new PapyrusVariableReference { Name = nameRef, TypeName = fieldType.Ref(pex), Value = nameRef.Value, Type = PapyrusPrimitiveType.Reference }, UserFlags = properties.UserFlagsValue }; fields.Add(papyrusFieldDefinition); } return(fields); }
private PapyrusFieldDefinition ReadFieldDefinition(PapyrusAssemblyDefinition asm, PapyrusTypeDefinition declaringType) { var fd = new PapyrusFieldDefinition(asm, declaringType); // Field Definition fd.Name = pexReader.ReadStringRef(); fd.TypeName = pexReader.ReadString(); fd.UserFlags = pexReader.ReadInt32(); { // Type Reference fd.DefaultValue = ReadValueReference(asm, fd.TypeName); } fd.Flags = pexReader.ReadByte(); //== 1; return(fd); }
private string GetStructFieldType(IReadOnlyCollection <PapyrusAssemblyDefinition> papyrusAssemblyCollection, PapyrusFieldDefinition structSource, PapyrusVariableReference structField) { foreach (var a in papyrusAssemblyCollection) { foreach (var t in a.Types) { foreach (var s in t.NestedTypes) { var name = structSource.TypeName.Split('#').LastOrDefault(); if (s.Name.Value.ToLower() == name.ToLower()) { var targetField = s.Fields.FirstOrDefault(f => f.Name.Value == "::" + structField.Name.Value); if (targetField != null) { return(targetField.TypeName); } } } } } return("none"); }
/// <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); }
private void WriteDocumentedField(PapyrusFieldDefinition field) { WriteFieldDefinition(field); pexWriter.Write(field.Documentation); }