public virtual async Task GenerateWrapperRecordTypeParse(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor locationAccessor,
            Accessor packageAccessor,
            Accessor converterAccessor)
        {
            switch (typeGen.GetFieldData().BinaryOverlayFallback)
            {
            case BinaryGenerationType.Normal:
                fg.AppendLine($"_{typeGen.Name}Location = {locationAccessor};");
                break;

            case BinaryGenerationType.Custom:
                using (var args = new ArgsWrapper(fg,
                                                  $"{typeGen.Name}CustomParse"))
                {
                    args.AddPassArg($"stream");
                    args.AddPassArg($"finalPos");
                    args.AddPassArg($"offset");
                }
                break;

            case BinaryGenerationType.NoGeneration:
            default:
                return;
            }
        }
예제 #2
0
 public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
 {
     if (!await obj.IsMajorRecord())
     {
         return;
     }
     if (!obj.IsTopClass)
     {
         return;
     }
     using (var args = new FunctionWrapper(fg,
                                           $"public static {nameof(IMajorRecordCommon)} {nameof(IDuplicatable.Duplicate)}"))
     {
         //ToDo
         // Modify to getter interface after copy is refactored
         args.Add($"this {obj.ObjectName} item");
         args.Add("Func<FormKey> getNextFormKey");
         args.Add($"IList<({nameof(IMajorRecordCommon)} Record, FormKey OriginalFormKey)>? duplicatedRecords = null");
     }
     using (new BraceWrapper(fg))
     {
         using (var args = new ArgsWrapper(fg,
                                           $"return {obj.CommonClassInstance("item", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.{nameof(IDuplicatable.Duplicate)}"))
         {
             args.AddPassArg("item");
             args.AddPassArg("getNextFormKey");
             args.AddPassArg("duplicatedRecords");
         }
     }
 }
예제 #3
0
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            await base.GenerateInCommonMixin(obj, fg);

            if (!await obj.IsMajorRecord())
            {
                return;
            }
            using (var args = new FunctionWrapper(fg,
                                                  $"public static {obj.ObjectName} Duplicate{obj.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter)}"))
            {
                args.Wheres.AddRange(obj.GenericTypeMaskWheres(LoquiInterfaceType.IGetter, MaskType.Normal, MaskType.NormalGetter));
                args.Add($"this {obj.Interface(obj.GetGenericTypes(MaskType.NormalGetter), getter: true, internalInterface: true)} item");
                args.Add($"{nameof(FormKey)} formKey");
                args.Add($"{obj.Mask(MaskType.Translation)}? copyMask = null");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return {obj.CommonClassInstance("item", LoquiInterfaceType.IGetter, CommonGenerics.Functions, MaskType.NormalGetter)}.Duplicate{obj.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter, MaskType.Translation)}"))
                {
                    args.AddPassArg("item");
                    args.AddPassArg("formKey");
                    args.Add("copyMask: copyMask?.GetCrystal()");
                }
            }
            fg.AppendLine();
        }
예제 #4
0
        private void GenerateCustomBinaryEndCreatePartial(ObjectGeneration obj, FileGeneration fg)
        {
            var data = obj.GetObjectData();

            if (data.CustomBinaryEnd == CustomEnd.Off)
            {
                return;
            }
            if (data.CustomBinaryEnd == CustomEnd.Normal)
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"public static partial void CustomBinaryEndImport"))
                {
                    args.Add($"{ReaderClass} {ReaderMemberName}");
                    args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj");
                }
                using (var args = new FunctionWrapper(fg,
                                                      $"public static void CustomBinaryEndImportPublic"))
                {
                    args.Add($"{ReaderClass} {ReaderMemberName}");
                    args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj");
                }
                using (new BraceWrapper(fg))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"CustomBinaryEndImport"))
                    {
                        args.AddPassArg(ReaderMemberName);
                        args.AddPassArg($"obj");
                    }
                }
            }
        }
예제 #5
0
 protected override async Task GenerateNewSnippet(ObjectGeneration obj, FileGeneration fg)
 {
     if (await obj.IsMajorRecord())
     {
         fg.AppendLine($"var ret = new {obj.Name}();");
     }
     else
     {
         if (obj.TryGetCustomRecordTypeTriggers(out var customLogicTriggers))
         {
             using (var args = new ArgsWrapper(fg,
                                               $"var nextRecord = HeaderTranslation.GetNext{(obj.GetObjectType() == ObjectType.Subrecord ? "Subrecord" : "Record")}Type"))
             {
                 args.Add($"reader: {ReaderMemberName}.Reader");
                 args.Add("contentLength: out var customLen");
             }
             fg.AppendLine("nextRecord = recordTypeConverter.ConvertToCustom(nextRecord);");
             fg.AppendLine("switch (nextRecord.TypeInt)");
             using (new BraceWrapper(fg))
             {
                 foreach (var item in customLogicTriggers)
                 {
                     fg.AppendLine($"case {item.TypeInt}: // {item.Type}");
                 }
                 using (new DepthWrapper(fg))
                 {
                     using (var args = new ArgsWrapper(fg,
                                                       "return CustomRecordTypeTrigger"))
                     {
                         args.Add($"{ReaderMemberName}: {ReaderMemberName}.SpawnWithLength(customLen + {ReaderMemberName}.{nameof(MutagenFrame.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(GameConstants.SubConstants.HeaderLength)})");
                         args.Add("recordType: nextRecord");
                         args.AddPassArg("recordTypeConverter");
                     }
                 }
                 fg.AppendLine("default:");
                 using (new DepthWrapper(fg))
                 {
                     fg.AppendLine("break;");
                 }
             }
         }
         using (var args = new ArgsWrapper(fg,
                                           $"var ret = new {obj.Name}{obj.GetGenericTypes(MaskType.Normal)}"))
         {
             if (obj.GetObjectType() == ObjectType.Mod)
             {
                 args.AddPassArg("modKey");
             }
             if (obj.GetObjectData().GameReleaseOptions != null)
             {
                 args.AddPassArg("release");
             }
         }
         if (obj.GetObjectType() == ObjectType.Mod)
         {
             fg.AppendLine($"{ReaderMemberName}.MetaData.ModKey = modKey;");
         }
     }
 }
        public override async Task GenerateCopyIn(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor frameAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationMaskAccessor)
        {
            var loqui = typeGen as LoquiType;
            var data  = loqui.GetFieldData();

            if (data.MarkerType.HasValue &&
                !data.RecordType.HasValue)
            {
                fg.AppendLine($"frame.Position += frame.{nameof(MutagenFrame.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(GameConstants.SubConstants.HeaderLength)} + contentLength; // Skip marker");
            }
            if (loqui.TargetObjectGeneration != null)
            {
                if (loqui.SetterInterfaceType == LoquiInterfaceType.IGetter)
                {
                    return;
                }
                if (loqui.Singleton)
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"{Loqui.Generation.Utility.Await(this.IsAsync(typeGen, read: true))}{itemAccessor}.{this.Module.CopyInFromPrefix}{ModNickname}"))
                    {
                        args.Add($"frame: {frameAccessor}");
                        args.Add($"recordTypeConverter: null");
                    }
                }
                else
                {
                    if (NeedsHeaderProcessing(loqui))
                    {
                        fg.AppendLine($"frame.Position += frame.{nameof(MutagenFrame.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(GameConstants.SubConstants.HeaderLength)}; // Skip header");
                    }
                    using (var args = new ArgsWrapper(fg,
                                                      $"{itemAccessor} = {loqui.TargetObjectGeneration.Namespace}.{loqui.TypeNameInternal(getter: false, internalInterface: true)}.{this.Module.CreateFromPrefix}{this.Module.ModuleNickname}"))
                    {
                        args.Add($"frame: {frameAccessor}");
                        if (data?.RecordTypeConverter != null &&
                            data.RecordTypeConverter.FromConversions.Count > 0)
                        {
                            args.Add($"recordTypeConverter: {objGen.RegistrationName}.{typeGen.Name}Converter");
                        }
                        else if (await NeedsRecordTypeConverter(loqui))
                        {
                            args.AddPassArg($"recordTypeConverter");
                        }
                    }
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }
 public override async Task GenerateWrapperRecordTypeParse(
     FileGeneration fg,
     ObjectGeneration objGen,
     TypeGeneration typeGen,
     Accessor locationAccessor,
     Accessor packageAccessor,
     Accessor converterAccessor)
 {
     using (var args = new ArgsWrapper(fg,
                                       $"{typeGen.Name}SpecialParse"))
     {
         args.AddPassArg("stream");
         args.AddPassArg("offset");
         args.AddPassArg("type");
         args.AddPassArg("lastParsed");
     }
 }
예제 #8
0
        public override void GenerateTypicalMakeCopy(FileGeneration fg, Accessor retAccessor, Accessor rhsAccessor, Accessor copyMaskAccessor, bool deepCopy, bool doTranslationMask)
        {
            if (this.GetObjectType() != ObjectType.Record)
            {
                base.GenerateTypicalMakeCopy(fg, retAccessor, rhsAccessor, copyMaskAccessor, deepCopy, doTranslationMask: doTranslationMask);
                return;
            }
            switch (this.RefType)
            {
            case LoquiRefType.Direct:
                using (var args = new ArgsWrapper(fg,
                                                  $"{retAccessor}({this.TargetObjectGeneration.ObjectName}){rhsAccessor}.{(deepCopy ? "Deep" : null)}Copy"))
                {
                    if (this.RefType == LoquiRefType.Direct)
                    {
                        if (!doTranslationMask)
                        {
                            args.Add($"copyMask: default(TranslationCrystal)");
                        }
                        else if (deepCopy)
                        {
                            args.Add($"copyMask: {copyMaskAccessor}?.GetSubCrystal({this.IndexEnumInt})");
                        }
                        else
                        {
                            args.Add($"copyMask: {copyMaskAccessor}.Specific");
                        }
                    }
                    args.AddPassArg($"errorMask");
                }
                break;

            case LoquiRefType.Generic:
                if (deepCopy)
                {
                    fg.AppendLine($"{retAccessor}(r.DeepCopy() as {_generic})!;");
                }
                else
                {
                    fg.AppendLine($"{retAccessor}{nameof(LoquiRegistration)}.GetCopyFunc<{_generic}, {_generic}Getter>()({rhsAccessor}, null);");
                }
                break;

            case LoquiRefType.Interface:
                if (deepCopy)
                {
                    fg.AppendLine($"{retAccessor}(r.DeepCopy() as {this.TypeNameInternal(getter: false, internalInterface: true)})!;");
                }
                else
                {
                    fg.AppendLine($"{retAccessor}{nameof(LoquiRegistration)}.GetCopyFunc<{this.TypeName()}, {this.TypeName(getter: true)}>(r.GetType(), typeof({this.TypeName(getter: true)}))({rhsAccessor}, null);");
                }
                break;

            default:
                throw new NotImplementedException();
            }
        }
        public override async Task GenerateCopyIn(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor readerAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationMaskAccessor)
        {
            var data = typeGen.GetFieldData();

            using (var args = new ArgsWrapper(fg,
                                              $"SpecialParse_{typeGen.Name}"))
            {
                args.AddPassArg("item");
                args.AddPassArg("frame");
            }
        }
예제 #10
0
        public override void GenerateCopyIn(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor frameAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationMaskAccessor)
        {
            FormLinkType linkType = typeGen as FormLinkType;

            MaskGenerationUtility.WrapErrorFieldIndexPush(fg,
                                                          () =>
            {
                if (itemAccessor.IsAssignment)
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"{itemAccessor} = {(linkType.FormIDType == FormLinkType.FormIDTypeEnum.Normal ? "FormKey" : "RecordType")}XmlTranslation.Instance.Parse"))
                    {
                        args.AddPassArg("node");
                        args.AddPassArg("errorMask");
                    }
                }
                else
                {
                    using (var args = new FunctionWrapper(fg,
                                                          itemAccessor.Assign($"new {linkType.DirectTypeName(getter: false)}")))
                    {
                        args.Add(subFg =>
                        {
                            using (var subArgs = new FunctionWrapper(subFg,
                                                                     $"FormKeyXmlTranslation.Instance.Parse"))
                            {
                                subArgs.AddPassArg("node");
                                subArgs.AddPassArg("errorMask");
                            }
                        });
                    }
                }
            },
                                                          indexAccessor: typeGen.HasIndex?typeGen.IndexEnumInt: null,
                                                          errorMaskAccessor: errorMaskAccessor,
                                                          doIt: typeGen.HasIndex);
        }
        public override async Task GenerateWrite(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor writerAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationMaskAccessor,
            Accessor converterAccessor)
        {
            var data = typeGen.GetFieldData();

            using (var args = new ArgsWrapper(fg,
                                              $"{objGen.CommonClass(LoquiInterfaceType.ISetter, CommonGenerics.Class)}.SpecialWrite_{typeGen.Name}_Internal"))
            {
                args.AddPassArg("item");
                args.AddPassArg("writer");
            }
        }
예제 #12
0
        public void GenerateFill(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration field,
            Accessor frameAccessor,
            bool isAsync,
            bool useReturnValue)
        {
            var data = field.GetFieldData();
            var returningParseValue = useReturnValue && data.HasTrigger;

            using (var args = new ArgsWrapper(fg,
                                              $"{(returningParseValue ? "return " : null)}{Loqui.Generation.Utility.Await(isAsync)}{this.Module.TranslationCreateClass(field.ObjectGen)}.FillBinary{field.Name}Custom"))
            {
                args.Add($"frame: {(data.HasTrigger ? $"{frameAccessor}.SpawnWithLength(frame.{nameof(MutagenFrame.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(GameConstants.SubConstants.HeaderLength)} + contentLength)" : frameAccessor)}");
                args.AddPassArg("item");
                if (returningParseValue && objGen.GetObjectType() == ObjectType.Subrecord)
                {
                    args.AddPassArg("lastParsed");
                }
            }
        }
예제 #13
0
        public override async Task GenerateWrapperRecordTypeParse(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor locationAccessor,
            Accessor packageAccessor,
            Accessor converterAccessor)
        {
            var fieldData           = typeGen.GetFieldData();
            var returningParseValue = fieldData.HasTrigger;

            using (var args = new ArgsWrapper(fg,
                                              $"{(returningParseValue ? "return " : null)}{(typeGen.Name == null ? typeGen.GetFieldData().RecordType?.ToString() : typeGen.Name)}CustomParse"))
            {
                args.Add("stream");
                args.Add("offset");
                if (returningParseValue && objGen.GetObjectType() == ObjectType.Subrecord)
                {
                    args.AddPassArg("lastParsed");
                }
            }
        }
예제 #14
0
        public override void GenerateForEqualsMask(FileGeneration fg, Accessor accessor, Accessor rhsAccessor, string retAccessor)
        {
            LoquiType loqui = this.SubTypeGeneration as LoquiType;

            if (this.Nullable || loqui != null)
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"ret.{this.Name} = {nameof(GenderedItem)}.{nameof(GenderedItem.EqualityMaskHelper)}"))
                {
                    args.Add($"lhs: {accessor}");
                    args.Add($"rhs: {rhsAccessor}");
                    if (loqui == null)
                    {
                        args.Add($"maskGetter: (l, r, i) => EqualityComparer<{this.SubTypeGeneration.TypeName(getter: true, needsCovariance: true)}{this.SubTypeGeneration.NullChar}>.Default.Equals(l, r)");
                    }
                    else
                    {
                        if (this.ItemNullable)
                        {
                            args.Add($"maskGetter: (l, r, i) => EqualsMaskHelper.EqualsHelper(l, r, (loqLhs, loqRhs, incl) => loqLhs.GetEqualsMask(loqRhs, incl), i)");
                        }
                        else
                        {
                            args.Add("maskGetter: (l, r, i) => l.GetEqualsMask(r, i)");
                        }
                    }
                    args.AddPassArg("include");
                }
            }
            else
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"ret.{this.Name} = new GenderedItem<bool>"))
                {
                    args.Add($"male: {this.SubTypeGeneration.GenerateEqualsSnippet($"{accessor}.Male", $"{rhsAccessor}.Male")}");
                    args.Add($"female: {this.SubTypeGeneration.GenerateEqualsSnippet($"{accessor}.Female", $"{rhsAccessor}.Female")}");
                }
            }
        }
예제 #15
0
        public override void GenerateForAny(FileGeneration fg, TypeGeneration field, Accessor accessor, bool nullCheck, bool indexed)
        {
            if (!field.IntegrateField)
            {
                return;
            }
            GenderedType gendered = field as GenderedType;
            var          isLoqui  = gendered.SubTypeGeneration is LoquiType;

            if (field.Nullable || isLoqui)
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"if ({nameof(GenderedItem)}.{(isLoqui ? nameof(GenderedItem.AnyMask) : nameof(GenderedItem.Any))}",
                                                  suffixLine: ") return true"))
                {
                    args.Add($"{accessor}");
                    args.AddPassArg("eval");
                }
            }
            else
            {
                fg.AppendLine($"if (eval({accessor}{(indexed ? ".Value" : null)}.Male) || eval({accessor}{(indexed ? ".Value" : null)}.Female)) return true;");
            }
        }
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            if (!maskTypes.Applicable(LoquiInterfaceType.ISetter, CommonGenerics.Class))
            {
                return;
            }
            var accessor = new Accessor("obj");

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            var overrideStr = await obj.FunctionOverride(async c => await MajorRecordModule.HasMajorRecords(c, includeBaseClass : false, includeSelf : true) != Case.No);

            using (var args = new FunctionWrapper(fg,
                                                  $"public{overrideStr}void Remove"))
            {
                args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"HashSet<{nameof(FormKey)}> keys");
            }
            using (new BraceWrapper(fg))
            {
                var fgCount = fg.Count;
                foreach (var baseClass in obj.BaseClassTrail())
                {
                    if (await MajorRecordModule.HasMajorRecords(baseClass, includeBaseClass: true, includeSelf: true) != Case.No)
                    {
                        fg.AppendLine($"base.Remove(obj, keys);");
                        break;
                    }
                }
                foreach (var field in obj.IterateFields())
                {
                    switch (field)
                    {
                    case LoquiType _:
                    case ContainerType _:
                    case DictType _:
                        break;

                    default:
                        continue;
                    }

                    FileGeneration fieldFg = new FileGeneration();

                    if (field is LoquiType loqui)
                    {
                        var fieldAccessor = $"{accessor}.{loqui.Name}";
                        if (await MajorRecordModule.HasMajorRecords(loqui.TargetObjectGeneration, includeBaseClass: true, includeSelf: false) != Case.No)
                        {
                            fg.AppendLine($"{fieldAccessor}{loqui.NullChar}.Remove(keys);");
                        }
                        var isMajorRecord = loqui.TargetObjectGeneration != null && await loqui.TargetObjectGeneration.IsMajorRecord();

                        if (isMajorRecord)
                        {
                            fg.AppendLine($"if ({(loqui.Nullable ? $"{fieldAccessor} != null && " : string.Empty)}keys.Contains({fieldAccessor}.FormKey))");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine($"{fieldAccessor} = null;");
                            }
                        }
                    }
                    else if (field is ContainerType cont)
                    {
                        if (!(cont.SubTypeGeneration is LoquiType contLoqui))
                        {
                            continue;
                        }
                        var isMajorRecord = await contLoqui.IsMajorRecord();

                        if (isMajorRecord)
                        {
                            fg.AppendLine($"{accessor}.{field.Name}.Remove(keys);");
                        }
                        if (await MajorRecordModule.HasMajorRecords(contLoqui, includeBaseClass: true, includeSelf: false) != Case.No)
                        {
                            fg.AppendLine($"{accessor}.{field.Name}.ForEach(i => i.Remove(keys));");
                        }
                        if (contLoqui.TargetObjectGeneration?.IsListGroup() ?? false)
                        {
                            fg.AppendLine($"{accessor}.{field.Name}.RemoveWhere(i => i.{contLoqui.TargetObjectGeneration.Fields.FirstOrDefault(f => f is ContainerType).Name}.Count == 0);");
                        }
                    }
                    else if (field is DictType dict)
                    {
                        if (dict.Mode != DictMode.KeyedValue)
                        {
                            continue;
                        }
                        if (!(dict.ValueTypeGen is LoquiType dictLoqui))
                        {
                            continue;
                        }
                        var isMajorRecord = dictLoqui.TargetObjectGeneration != null && await dictLoqui.TargetObjectGeneration.IsMajorRecord();

                        if (isMajorRecord ||
                            await MajorRecordModule.HasMajorRecords(dictLoqui, includeBaseClass: true) != Case.No)
                        {
                            switch (await MajorRecordModule.HasMajorRecords(dictLoqui, includeBaseClass: true))
                            {
                            case Case.Yes:
                            case Case.Maybe:
                                fg.AppendLine($"{accessor}.{field.Name}.Remove(keys);");
                                break;

                            case Case.No:
                            default:
                                break;
                            }
                        }
                    }

                    if (fieldFg.Count > 0)
                    {
                        if (field.Nullable)
                        {
                            fg.AppendLine($"if ({field.NullableAccessor(getter: true, Accessor.FromType(field, accessor.ToString()))})");
                        }
                        using (new BraceWrapper(fg, doIt: field.Nullable))
                        {
                            fg.AppendLines(fieldFg);
                        }
                    }
                }
            }
            fg.AppendLine();

            // Generate base overrides
            foreach (var baseClass in obj.BaseClassTrail())
            {
                if (await MajorRecordModule.HasMajorRecords(baseClass, includeBaseClass: true, includeSelf: true) != Case.No)
                {
                    using (var args = new FunctionWrapper(fg,
                                                          $"public override void Remove"))
                    {
                        args.Add($"{baseClass.Interface(getter: false)} obj");
                        args.Add($"HashSet<{nameof(FormKey)}> keys");
                    }
                    using (new BraceWrapper(fg))
                    {
                        using (var args = new ArgsWrapper(fg,
                                                          "Remove"))
                        {
                            args.Add($"({obj.Interface(getter: false)})obj");
                            args.AddPassArg("keys");
                        }
                    }
                    fg.AppendLine();
                }
            }

            using (var args = new FunctionWrapper(fg,
                                                  $"public{overrideStr}void Remove"))
            {
                args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"HashSet<{nameof(FormKey)}> keys");
                args.Add($"Type type");
                args.Add($"bool throwIfUnknown");
            }
            using (new BraceWrapper(fg))
            {
                var fgCount = fg.Count;
                foreach (var baseClass in obj.BaseClassTrail())
                {
                    if (await MajorRecordModule.HasMajorRecords(baseClass, includeBaseClass: true, includeSelf: true) != Case.No)
                    {
                        fg.AppendLine("base.Remove(obj, type, keys);");
                        break;
                    }
                }

                fg.AppendLine("switch (type.Name)");
                using (new BraceWrapper(fg))
                {
                    var gameCategory = obj.GetObjectData().GameCategory;
                    fg.AppendLine($"case \"{nameof(IMajorRecord)}\":");
                    fg.AppendLine($"case \"{nameof(MajorRecord)}\":");
                    if (gameCategory != null)
                    {
                        fg.AppendLine($"case \"I{gameCategory}MajorRecord\":");
                        fg.AppendLine($"case \"{gameCategory}MajorRecord\":");
                    }
                    fg.AppendLine($"case \"{nameof(IMajorRecordGetter)}\":");
                    if (gameCategory != null)
                    {
                        fg.AppendLine($"case \"I{gameCategory}MajorRecordGetter\":");
                    }
                    using (new DepthWrapper(fg))
                    {
                        fg.AppendLine($"if (!{obj.RegistrationName}.SetterType.IsAssignableFrom(obj.GetType())) return;");
                        fg.AppendLine("this.Remove(obj, keys);");
                        fg.AppendLine("break;");
                    }

                    Dictionary <object, FileGeneration> generationDict = new Dictionary <object, FileGeneration>();
                    foreach (var field in obj.IterateFields())
                    {
                        LoquiType      targetLoqui;
                        FileGeneration fieldGen;
                        if (field is LoquiType loqui)
                        {
                            if (loqui.TargetObjectGeneration.IsListGroup())
                            {
                                continue;
                            }
                            var isMajorRecord = loqui.TargetObjectGeneration != null && await loqui.TargetObjectGeneration.IsMajorRecord();

                            if (!isMajorRecord &&
                                await MajorRecordModule.HasMajorRecords(loqui, includeBaseClass: true) == Case.No)
                            {
                                continue;
                            }

                            if (loqui.TargetObjectGeneration.GetObjectType() == ObjectType.Group)
                            {
                                fieldGen = generationDict.GetOrAdd(loqui.GetGroupTarget());
                            }
                            else
                            {
                                fieldGen = generationDict.GetOrAdd(((object)loqui?.TargetObjectGeneration) ?? loqui);
                            }
                            targetLoqui = loqui;
                        }
                        else if (field is ContainerType cont)
                        {
                            if (!(cont.SubTypeGeneration is LoquiType contLoqui))
                            {
                                continue;
                            }
                            if (contLoqui.RefType == LoquiType.LoquiRefType.Generic)
                            {
                                fieldGen = generationDict.GetOrAdd("default:");
                            }
                            else
                            {
                                fieldGen = generationDict.GetOrAdd(((object)contLoqui?.TargetObjectGeneration) ?? contLoqui);
                            }
                            targetLoqui = contLoqui;
                        }
                        else if (field is DictType dict)
                        {
                            if (dict.Mode != DictMode.KeyedValue)
                            {
                                continue;
                            }
                            if (!(dict.ValueTypeGen is LoquiType dictLoqui))
                            {
                                continue;
                            }
                            if (dictLoqui.RefType == LoquiType.LoquiRefType.Generic)
                            {
                                fieldGen = generationDict.GetOrAdd("default:");
                            }
                            else
                            {
                                fieldGen = generationDict.GetOrAdd(((object)dictLoqui?.TargetObjectGeneration) ?? dictLoqui);
                            }
                            targetLoqui = dictLoqui;
                        }
                        else
                        {
                            continue;
                        }
                        bool applicable = false;
                        switch (targetLoqui.RefType)
                        {
                        case LoquiType.LoquiRefType.Direct:
                            applicable = await targetLoqui.TargetObjectGeneration.IsMajorRecord();

                            break;

                        case LoquiType.LoquiRefType.Interface:
                            applicable = true;
                            break;

                        case LoquiType.LoquiRefType.Generic:
                        default:
                            break;
                        }
                        await ApplyRemovalLines(field, fieldGen, accessor, removeSelf : applicable);
                    }

                    bool doAdditionlDeepLogic = !obj.Name.EndsWith("ListGroup");

                    if (doAdditionlDeepLogic)
                    {
                        LinkInterfaceModule.ObjectMappings.TryGetValue(obj.ProtoGen.Protocol, out var interfs);

                        var deepRecordMapping = await MajorRecordModule.FindDeepRecords(obj);

                        foreach (var deepRec in deepRecordMapping)
                        {
                            FileGeneration deepFg = generationDict.GetOrAdd(deepRec.Key);
                            foreach (var field in deepRec.Value)
                            {
                                var remSelf = false;
                                switch (field)
                                {
                                case ContainerType cont:
                                    if (cont.SubTypeGeneration is LoquiType loqui)
                                    {
                                        switch (loqui.RefType)
                                        {
                                        case LoquiType.LoquiRefType.Direct:
                                            remSelf = loqui.TargetObjectGeneration == deepRec.Key;
                                            break;

                                        case LoquiType.LoquiRefType.Interface:
                                            if (interfs.TryGetValue(loqui.SetterInterface, out var objs))
                                            {
                                                remSelf = objs.Contains(deepRec.Key);
                                            }
                                            break;

                                        case LoquiType.LoquiRefType.Generic:
                                        default:
                                            break;
                                        }
                                    }
                                    break;

                                default:
                                    break;
                                }

                                remSelf &= await deepRec.Key.IsMajorRecord();
                                await ApplyRemovalLines(field, deepFg, accessor, obj : deepRec.Key, removeSelf : remSelf);
                            }
                        }

                        // Generate for major record marker interfaces
                        foreach (var interf in interfs.EmptyIfNull())
                        {
                            FileGeneration             subFg         = new FileGeneration();
                            HashSet <ObjectGeneration> passedObjects = new HashSet <ObjectGeneration>();
                            HashSet <TypeGeneration>   deepObjects   = new HashSet <TypeGeneration>();
                            foreach (var subObj in interf.Value)
                            {
                                var grup = obj.Fields
                                           .WhereCastable <TypeGeneration, GroupType>()
                                           .Where(g => g.GetGroupTarget() == subObj)
                                           .FirstOrDefault();

                                if (grup != null)
                                {
                                    subFg.AppendLine($"Remove({accessor}, keys, typeof({grup.GetGroupTarget().Interface(getter: true)}), throwIfUnknown: throwIfUnknown);");
                                    passedObjects.Add(grup.GetGroupTarget());
                                }
                                else if (deepRecordMapping.TryGetValue(subObj, out var deepRec))
                                {
                                    foreach (var field in deepRec)
                                    {
                                        deepObjects.Add(field);
                                    }
                                }
                            }
                            foreach (var deepObj in deepObjects)
                            {
                                bool remSelf = false;
                                switch (deepObj)
                                {
                                case ContainerType cont:
                                    if (cont.SubTypeGeneration is LoquiType loqui)
                                    {
                                        remSelf = loqui.RefType == LoquiType.LoquiRefType.Interface && loqui.Interface(getter: false) == interf.Key;
                                    }
                                    break;

                                default:
                                    break;
                                }
                                await ApplyRemovalLines(deepObj, subFg, accessor, blackList : passedObjects, removeSelf : remSelf);
                            }
                            if (!subFg.Empty)
                            {
                                var genFg = generationDict.GetOrAdd(new InterfInstr()
                                {
                                    Interf = interf.Key
                                });
                                genFg.AppendLines(subFg);
                            }
                        }

                        foreach (var kv in generationDict)
                        {
                            switch (kv.Key)
                            {
                            case LoquiType loqui:
                                if (loqui.RefType == LoquiType.LoquiRefType.Direct)
                                {
                                    fg.AppendLine($"case \"{loqui.Interface(getter: true)}\":");
                                    fg.AppendLine($"case \"{loqui.Interface(getter: false)}\":");
                                    if (loqui.HasInternalGetInterface)
                                    {
                                        fg.AppendLine($"case \"{loqui.Interface(getter: true, internalInterface: true)}\":");
                                    }
                                    if (loqui.HasInternalSetInterface)
                                    {
                                        fg.AppendLine($"case \"{loqui.Interface(getter: false, internalInterface: true)}\":");
                                    }
                                }
                                else
                                {
                                    continue;
                                }
                                break;

                            case ObjectGeneration targetObj:
                                fg.AppendLine($"case \"{targetObj.ObjectName}\":");
                                fg.AppendLine($"case \"{targetObj.Interface(getter: true)}\":");
                                fg.AppendLine($"case \"{targetObj.Interface(getter: false)}\":");
                                if (targetObj.HasInternalGetInterface)
                                {
                                    fg.AppendLine($"case \"{targetObj.Interface(getter: true, internalInterface: true)}\":");
                                }
                                if (targetObj.HasInternalSetInterface)
                                {
                                    fg.AppendLine($"case \"{targetObj.Interface(getter: false, internalInterface: true)}\":");
                                }
                                break;

                            case InterfInstr interf:
                                fg.AppendLine($"case \"{interf.Interf}\":");
                                fg.AppendLine($"case \"{interf.Interf}Getter\":");
                                break;

                            case string str:
                                if (str != "default:")
                                {
                                    throw new NotImplementedException();
                                }
                                continue;

                            default:
                                throw new NotImplementedException();
                            }
                            using (new DepthWrapper(fg))
                            {
                                fg.AppendLines(kv.Value);
                                fg.AppendLine("break;");
                            }
                        }
                    }

                    fg.AppendLine("default:");
                    using (new DepthWrapper(fg))
                    {
                        if (generationDict.TryGetValue("default:", out var gen))
                        {
                            fg.AppendLines(gen);
                            fg.AppendLine("break;");
                        }
                        else
                        {
                            fg.AppendLine("if (throwIfUnknown)");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("throw new ArgumentException($\"Unknown major record type: {type}\");");
                            }
                            fg.AppendLine($"else");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("break;");
                            }
                        }
                    }
                }
            }
            fg.AppendLine();

            // Generate base overrides
            foreach (var baseClass in obj.BaseClassTrail())
            {
                if (await MajorRecordModule.HasMajorRecords(baseClass, includeBaseClass: true, includeSelf: true) != Case.No)
                {
                    using (var args = new FunctionWrapper(fg,
                                                          $"public override void Remove"))
                    {
                        args.Add($"{baseClass.Interface(getter: false)} obj");
                        args.Add($"HashSet<{nameof(FormKey)}> keys");
                        args.Add($"Type type");
                        args.Add($"bool throwIfUnknown");
                    }
                    using (new BraceWrapper(fg))
                    {
                        using (var args = new ArgsWrapper(fg,
                                                          "Remove"))
                        {
                            args.Add($"({obj.Interface(getter: false)})obj");
                            args.AddPassArg("keys");
                            args.AddPassArg("type");
                            args.AddPassArg("throwIfUnknown");
                        }
                    }
                    fg.AppendLine();
                }
            }
        }
예제 #17
0
        private async Task LoquiTypeHandler(
            FileGeneration fg,
            ObjectGeneration obj,
            Accessor loquiAccessor,
            LoquiType loquiType,
            Action <ArgsWrapper> addGetOrAddArg,
            string generic,
            bool checkType,
            bool includeSelf = true)
        {
            // ToDo
            // Quick hack.  Real solution should use reflection to investigate the interface
            if (loquiType.RefType == LoquiType.LoquiRefType.Interface)
            {
                if (checkType)
                {
                    fg.AppendLine($"if (type.IsAssignableFrom({loquiAccessor}.GetType()))");
                }
                using (new BraceWrapper(fg, doIt: checkType))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"yield return new ModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>"))
                    {
                        args.Add($"modKey: {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}");
                        args.Add($"record: {loquiAccessor}");
                        args.Add($"parent: curContext");
                        addGetOrAddArg(args);
                    }
                }
                return;
            }

            if (includeSelf &&
                loquiType.TargetObjectGeneration != null &&
                await loquiType.TargetObjectGeneration.IsMajorRecord())
            {
                if (checkType)
                {
                    fg.AppendLine($"if (type.IsAssignableFrom({loquiAccessor}.GetType()))");
                }
                using (new BraceWrapper(fg, doIt: checkType))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"yield return new ModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>"))
                    {
                        args.Add($"modKey: {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}");
                        args.Add($"record: {loquiAccessor}");
                        args.Add($"parent: curContext");
                        addGetOrAddArg(args);
                    }
                }
            }
            if (await MajorRecordModule.HasMajorRecords(loquiType, includeBaseClass: true, includeSelf: false) == Case.No)
            {
                return;
            }
            if (obj.IsListGroup())
            {
                return;
            }

            if (obj.IsTopLevelGroup())
            {
                fg.AppendLine($"foreach (var item in {loquiAccessor}.EnumerateMajorRecords({(generic == null ? null : "type, throwIfUnknown: false")}))");
                using (new BraceWrapper(fg))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"yield return new ModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>"))
                    {
                        args.Add($"modKey: {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}");
                        args.Add("record: item");
                        args.Add($"getOrAddAsOverride: (m, r) => m.{loquiType.Name}.GetOrAddAsOverride(({loquiType.GetGroupTarget().Interface(getter: true, internalInterface: true)})r)");
                    }
                }
            }
            else
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"foreach (var item in {loquiType.TargetObjectGeneration.CommonClassInstance(loquiAccessor, LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecordContexts",
                                                  suffixLine: ")")
                {
                    SemiColon = false
                })
                {
                    args.Add($"obj: {loquiAccessor}");
                    args.AddPassArg("linkCache");
                    args.AddPassArg("type");
                    args.Add($"modKey: {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}");
                    args.Add($"parent: {(obj.GetObjectType() == ObjectType.Mod ? "null" : "curContext")}");
                    args.Add("throwIfUnknown: false");
                    addGetOrAddArg(args);
                }
                using (new BraceWrapper(fg))
                {
                    fg.AppendLine("yield return item;");
                }
            }
        }
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"{nameof(FormKey)} key");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();");
                fg.AppendLine("keys.Add(key);");
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"IEnumerable<{nameof(FormKey)}> keys");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.Add("keys: keys.ToHashSet()");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"HashSet<{nameof(FormKey)}> keys");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"{nameof(FormKey)} key");
                args.Add($"{nameof(Type)} type");
                args.Add($"bool throwIfUnknown = true");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();");
                fg.AppendLine("keys.Add(key);");
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"IEnumerable<{nameof(FormKey)}> keys");
                args.Add($"{nameof(Type)} type");
                args.Add($"bool throwIfUnknown = true");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.Add("keys: keys.ToHashSet()");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"HashSet<{nameof(FormKey)}> keys");
                args.Add($"{nameof(Type)} type");
                args.Add($"bool throwIfUnknown = true");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"TMajor record");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();");
                fg.AppendLine("keys.Add(record.FormKey);");
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"IEnumerable<TMajor> records");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.Add("keys: records.Select(m => m.FormKey).ToHashSet()");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"{nameof(FormKey)} key");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();");
                fg.AppendLine("keys.Add(key);");
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"IEnumerable<{nameof(FormKey)}> keys");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.Add("keys: keys.ToHashSet()");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();

            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"HashSet<{nameof(FormKey)}> keys");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("keys");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();
        }
예제 #19
0
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            if (!maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class))
            {
                return;
            }
            await base.GenerateInCommon(obj, fg, maskTypes);

            if (!await obj.IsMajorRecord())
            {
                return;
            }
            using (new RegionWrapper(fg, "Duplicate"))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"public{obj.Virtual()}{obj.Name} Duplicate{obj.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter)}"))
                {
                    args.Wheres.AddRange(obj.GenericTypeMaskWheres(LoquiInterfaceType.IGetter, MaskType.Normal, MaskType.NormalGetter));
                    args.Add($"{obj.Interface(getter: true)} item");
                    args.Add($"{nameof(FormKey)} formKey");
                    args.Add($"TranslationCrystal? copyMask");
                }
                using (new BraceWrapper(fg))
                {
                    if (obj.Abstract)
                    {
                        fg.AppendLine("throw new NotImplementedException();");
                    }
                    else
                    {
                        fg.AppendLine($"var newRec = new {obj.Name}(formKey{(obj.GetObjectData().HasMultipleReleases ? $", default({obj.GetObjectData().GameCategory}Release)" : null)});");
                        fg.AppendLine($"newRec.DeepCopyIn(item, default({nameof(ErrorMaskBuilder)}?), copyMask);");
                        fg.AppendLine("return newRec;");
                    }
                }
                fg.AppendLine();

                foreach (var baseClass in obj.BaseClassTrail())
                {
                    using (var args = new FunctionWrapper(fg,
                                                          $"public override {baseClass.Name} Duplicate{baseClass.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter)}"))
                    {
                        args.Wheres.AddRange(baseClass.GenericTypeMaskWheres(LoquiInterfaceType.IGetter, MaskType.Normal, MaskType.NormalGetter));
                        args.Add($"{baseClass.Interface(getter: true)} item");
                        args.Add($"{nameof(FormKey)} formKey");
                        args.Add($"TranslationCrystal? copyMask");
                    }
                    using (new BraceWrapper(fg))
                    {
                        using (var args = new ArgsWrapper(fg,
                                                          $"return this.Duplicate"))
                        {
                            args.Add($"item: ({obj.Interface(getter: false)})item");
                            args.AddPassArg("formKey");
                            args.AddPassArg("copyMask");
                        }
                    }
                    fg.AppendLine();
                }
            }
        }
        public override async Task GenerateCopyIn(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor nodeAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationMaskAccessor)
        {
            var dict    = typeGen as DictType;
            var data    = dict.GetFieldData();
            var subData = dict.ValueTypeGen.GetFieldData();

            if (!this.Module.TryGetTypeGeneration(dict.ValueTypeGen.GetType(), out var subTransl))
            {
                throw new ArgumentException("Unsupported type generator: " + dict.ValueTypeGen);
            }
            var isAsync = subTransl.IsAsync(dict.ValueTypeGen, read: true);

            var binaryType = GetDictType(dict);

            if (data.MarkerType.HasValue)
            {
                fg.AppendLine("frame.Position += Constants.SUBRECORD_LENGTH + long; // Skip marker");
            }
            else if (binaryType == DictBinaryType.Trigger)
            {
                fg.AppendLine("frame.Position += Constants.SUBRECORD_LENGTH;");
            }

            var term = binaryType == DictBinaryType.EnumMap ? "Dict" : "List";

            using (var args = new ArgsWrapper(fg,
                                              $"{Loqui.Generation.Utility.Await(isAsync)}{this.Namespace}{term}{(isAsync ? "Async" : null)}BinaryTranslation<{dict.ValueTypeGen.TypeName(getter: false)}>.Instance.Parse{(binaryType == DictBinaryType.EnumMap ? $"<{dict.KeyTypeGen.TypeName(false)}>" : null)}",
                                              suffixLine: Loqui.Generation.Utility.ConfigAwait(isAsync)))
            {
                switch (binaryType)
                {
                case DictBinaryType.SubTrigger:
                    args.AddPassArg($"frame");
                    args.Add($"triggeringRecord: {subData.TriggeringRecordSetAccessor}");
                    break;

                case DictBinaryType.Trigger:
                    args.Add($"frame: frame.Spawn(long)");
                    break;

                case DictBinaryType.EnumMap:
                    args.AddPassArg($"frame");
                    break;

                default:
                    throw new NotImplementedException();
                }
                args.Add($"item: {itemAccessor}");
                var subGenTypes = subData.GenerationTypes.ToList();
                var subGen      = this.Module.GetTypeGeneration(dict.ValueTypeGen.GetType());
                if (subGenTypes.Count <= 1 &&
                    subTransl.AllowDirectParse(objGen, typeGen, squashedRepeatedList: false))
                {
                    args.Add($"transl: {subTransl.GetTranslatorInstance(dict.ValueTypeGen, getter: false)}.Parse");
                }
                else if (subGenTypes.Count > 1)
                {
                    args.Add((gen) =>
                    {
                        gen.AppendLine($"transl: (MutagenFrame r, RecordType header{(isAsync ? null : $", out {dict.ValueTypeGen.TypeName(getter: false)} dictSubItem")}) =>");
                        using (new BraceWrapper(gen))
                        {
                            gen.AppendLine("switch (header.Type)");
                            using (new BraceWrapper(gen))
                            {
                                foreach (var item in subGenTypes)
                                {
                                    foreach (var trigger in item.Key)
                                    {
                                        gen.AppendLine($"case \"{trigger.Type}\":");
                                    }
                                    LoquiType targetLoqui   = dict.ValueTypeGen as LoquiType;
                                    LoquiType specificLoqui = item.Value as LoquiType;
                                    using (new DepthWrapper(gen))
                                    {
                                        subGen.GenerateCopyInRet(
                                            fg: gen,
                                            objGen: objGen,
                                            targetGen: dict.ValueTypeGen,
                                            typeGen: item.Value,
                                            readerAccessor: "r",
                                            retAccessor: "return ",
                                            outItemAccessor: new Accessor("dictSubItem"),
                                            translationAccessor: "dictTranslMask",
                                            asyncMode: AsyncMode.Off,
                                            errorMaskAccessor: null,
                                            converterAccessor: null,
                                            inline: true);
                                    }
                                }
                                gen.AppendLine("default:");
                                using (new DepthWrapper(gen))
                                {
                                    gen.AppendLine("throw new NotImplementedException();");
                                }
                            }
                        }
                    });
                }
                else
                {
                    args.Add((gen) =>
                    {
                        LoquiType targetLoqui = dict.ValueTypeGen as LoquiType;
                        subGen.GenerateCopyInRet(
                            fg: gen,
                            objGen: objGen,
                            targetGen: dict.ValueTypeGen,
                            typeGen: targetLoqui,
                            readerAccessor: "r",
                            retAccessor: "transl: ",
                            outItemAccessor: new Accessor("dictSubItem"),
                            translationAccessor: "dictTranslMask",
                            asyncMode: AsyncMode.Off,
                            errorMaskAccessor: null,
                            converterAccessor: null,
                            inline: true);
                    });
                }
            }
        }
        async Task ApplyRemovalLines(
            TypeGeneration field,
            FileGeneration fieldGen,
            Accessor accessor,
            bool removeSelf,
            ObjectGeneration obj = null,
            HashSet <ObjectGeneration> blackList = null)
        {
            if (field is GroupType group)
            {
                if (blackList?.Contains(group.GetGroupTarget()) ?? false)
                {
                    return;
                }
                using (var args = new ArgsWrapper(fieldGen,
                                                  $"obj.{field.Name}.Remove"))
                {
                    args.AddPassArg("type");
                    args.AddPassArg("keys");
                }
            }
            else if (field is LoquiType loqui)
            {
                if (blackList?.Contains(loqui.TargetObjectGeneration) ?? false)
                {
                    return;
                }
                var fieldAccessor = loqui.Nullable ? $"{obj?.ObjectName}{loqui.Name}item" : $"{accessor}.{loqui.Name}";
                if (loqui.TargetObjectGeneration.IsListGroup())
                { // List groups
                    using (var args = new ArgsWrapper(fieldGen,
                                                      $"obj.{field.Name}.Remove"))
                    {
                        args.AddPassArg("type");
                        args.AddPassArg("keys");
                    }
                    return;
                }
                var subFg = new FileGeneration();
                subFg.AppendLine($"{fieldAccessor}.Remove(keys, type, throwIfUnknown);");
                if (loqui.Singleton ||
                    !loqui.Nullable)
                {
                    fieldGen.AppendLines(subFg);
                }
                else
                {
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"if ({accessor}.{loqui.Name} is {{}} {fieldAccessor})");
                        using (new BraceWrapper(fieldGen))
                        {
                            fieldGen.AppendLines(subFg);
                        }
                    }
                }
            }
            else if (field is ContainerType cont)
            {
                if (!(cont.SubTypeGeneration is LoquiType contLoqui))
                {
                    return;
                }
                if (contLoqui.RefType == LoquiType.LoquiRefType.Generic)
                {
                    fieldGen.AppendLine($"foreach (var item in obj.{field.Name})");
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"item.Remove(keys, type, throwIfUnknown: false);");
                    }
                    fieldGen.AppendLine($"obj.{field.Name}.RemoveWhere(i => i.{contLoqui.TargetObjectGeneration.Fields.FirstOrDefault(f => f is ContainerType).Name}.Count == 0);");
                }
                else
                {
                    var isMajorRecord = contLoqui.TargetObjectGeneration != null && await contLoqui.TargetObjectGeneration.IsMajorRecord();

                    if (isMajorRecord ||
                        await MajorRecordModule.HasMajorRecords(contLoqui, includeBaseClass: true) != Case.No)
                    {
                        if (removeSelf)
                        {
                            fieldGen.AppendLine($"obj.{field.Name}.RemoveWhere(i => keys.Contains(i.FormKey));");
                        }
                        switch (await MajorRecordModule.HasMajorRecords(contLoqui, includeBaseClass: true, includeSelf: false))
                        {
                        case Case.Yes:
                        case Case.Maybe:
                            fieldGen.AppendLine($"foreach (var subItem in {accessor}.{field.Name}{(field.Nullable ? ".EmptyIfNull()" : null)})");
                            using (new BraceWrapper(fieldGen))
                            {
                                fieldGen.AppendLine("subItem.Remove(keys, type, throwIfUnknown: false);");
                            }
                            break;

                        case Case.No:
                        default:
                            break;
                        }
                    }
                }
                if (contLoqui.TargetObjectGeneration != null &&
                    contLoqui.TargetObjectGeneration.IsListGroup() &&
                    (await contLoqui.TargetObjectGeneration.GetGroupLoquiType()).TargetObjectGeneration == obj)
                {
                    fieldGen.AppendLine($"{accessor}.{field.Name}.RemoveWhere(i => i.{contLoqui.TargetObjectGeneration.Fields.FirstOrDefault(f => f is ContainerType).Name}.Count == 0);");
                }
            }
            else if (field is DictType dict)
            {
                if (dict.Mode != DictMode.KeyedValue)
                {
                    return;
                }
                if (!(dict.ValueTypeGen is LoquiType dictLoqui))
                {
                    return;
                }
                if (dictLoqui.RefType == LoquiType.LoquiRefType.Generic)
                {
                    fieldGen.AppendLine($"if (type.IsAssignableFrom(typeof({dictLoqui.GenericDef.Name})))");
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"obj.RecordCache.Remove(keys);");
                    }
                    fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.Items)");
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"item.Remove(keys, type, throwIfUnknown: false);");
                    }
                }
                else
                {
                    var isMajorRecord = dictLoqui.TargetObjectGeneration != null && await dictLoqui.TargetObjectGeneration.IsMajorRecord();

                    if (isMajorRecord ||
                        await MajorRecordModule.HasMajorRecords(dictLoqui, includeBaseClass: true) != Case.No)
                    {
                        switch (await MajorRecordModule.HasMajorRecords(dictLoqui, includeBaseClass: true))
                        {
                        case Case.Yes:
                            fieldGen.AppendLine($"foreach (var subItem in {accessor}.{field.Name}.Items)");
                            using (new BraceWrapper(fieldGen))
                            {
                                throw new NotImplementedException();
                            }
                            break;

                        case Case.Maybe:
                            fieldGen.AppendLine($"foreach (var subItem in {accessor}.{field.Name}.Items.WhereCastable<{dictLoqui.TypeName(getter: false)}, {nameof(IMajorRecordEnumerable)}>())");
                            using (new BraceWrapper(fieldGen))
                            {
                                throw new NotImplementedException();
                            }
                            break;

                        case Case.No:
                        default:
                            break;
                        }
                    }
                }
            }
        }
        public override async Task GenerateCopyIn(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor readerAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationAccessor)
        {
            GenderedType gender = typeGen as GenderedType;
            var          data   = typeGen.GetFieldData();

            if (!this.Module.TryGetTypeGeneration(gender.SubTypeGeneration.GetType(), out var subTransl))
            {
                throw new ArgumentException("Unsupported type generator: " + gender.SubTypeGeneration);
            }

            if (data.RecordType.HasValue)
            {
                fg.AppendLine($"{readerAccessor}.Position += {readerAccessor}.{nameof(MutagenBinaryReadStream.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(RecordHeaderConstants.HeaderLength)};");
            }
            else if (data.MarkerType.HasValue && !gender.MarkerPerGender)
            {
                fg.AppendLine($"{readerAccessor}.Position += {readerAccessor}.{nameof(MutagenBinaryReadStream.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(RecordHeaderConstants.HeaderLength)} + contentLength; // Skip marker");
            }

            bool notNull = gender.ItemNullable && !gender.SubTypeGeneration.IsNullable;

            using (var args = new ArgsWrapper(fg,
                                              $"{itemAccessor} = {this.NamespacePrefix}GenderedItemBinaryTranslation.Parse{(gender.MarkerPerGender ? "MarkerPerItem" : null)}<{gender.SubTypeGeneration.TypeName(getter: false, needsCovariance: true)}>"))
            {
                args.AddPassArg($"frame");
                if (gender.MaleMarker.HasValue)
                {
                    args.Add($"maleMarker: {objGen.RecordTypeHeaderName(gender.MaleMarker.Value)}");
                    args.Add($"femaleMarker: {objGen.RecordTypeHeaderName(gender.FemaleMarker.Value)}");
                }
                if (data.MarkerType.HasValue && gender.MarkerPerGender)
                {
                    args.Add($"marker: {objGen.RecordTypeHeaderName(data.MarkerType.Value)}");
                }
                var subData = gender.SubTypeGeneration.GetFieldData();
                if (subData.RecordType.HasValue &&
                    !(gender.SubTypeGeneration is LoquiType))
                {
                    args.Add($"contentMarker: {objGen.RecordTypeHeaderName(subData.RecordType.Value)}");
                }
                LoquiType loqui = gender.SubTypeGeneration as LoquiType;
                if (loqui != null)
                {
                    if (subData?.RecordTypeConverter != null &&
                        subData.RecordTypeConverter.FromConversions.Count > 0)
                    {
                        args.Add($"parseParams: {objGen.RegistrationName}.{typeGen.Name}Converter");
                    }
                }
                if (gender.FemaleConversions != null)
                {
                    args.Add($"femaleRecordConverter: {objGen.RegistrationName}.{typeGen.Name}FemaleConverter");
                }
                if (gender.MaleConversions != null)
                {
                    args.Add($"maleRecordConverter: {objGen.RegistrationName}.{typeGen.Name}MaleConverter");
                }

                bool needsRecordConv = gender.SubTypeGeneration.NeedsRecordConverter();
                if (subTransl.AllowDirectParse(objGen, gender.SubTypeGeneration, false))
                {
                    if (loqui != null)
                    {
                        args.Add($"transl: {loqui.ObjectTypeName}{loqui.GenericTypes(getter: false)}.TryCreateFromBinary");
                    }
                    else
                    {
                        args.Add($"transl: {subTransl.GetTranslatorInstance(gender.SubTypeGeneration, getter: false)}.Parse");
                        if (gender.ItemNullable)
                        {
                            args.Add($"skipMarker: false");
                        }
                    }
                }
                else
                {
                    args.Add(gen =>
                    {
                        gen.AppendLine($"transl: (MutagenFrame r, out {gender.SubTypeGeneration.TypeName(getter: false, needsCovariance: true)} genSubItem{(needsRecordConv ? $", {nameof(RecordTypeConverter)}? conv" : null)}) =>");
                        using (new BraceWrapper(gen))
                        {
                            subTransl.GenerateCopyInRet(
                                fg: gen,
                                objGen: objGen,
                                targetGen: gender.SubTypeGeneration,
                                typeGen: gender.SubTypeGeneration,
                                readerAccessor: "r",
                                translationAccessor: null,
                                retAccessor: "return ",
                                outItemAccessor: new Accessor("genSubItem"),
                                asyncMode: AsyncMode.Off,
                                errorMaskAccessor: "listErrMask",
                                converterAccessor: "conv",
                                inline: false);
                        }
                        if (gender.ItemNullable)
                        {
                            args.Add($"skipMarker: false");
                        }
                    });
                }
                if (notNull)
                {
                    args.Add($"fallback: {gender.SubTypeGeneration.GetDefault(getter: false)}");
                }
            }
        }
        public override async Task GenerateWrapperRecordTypeParse(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor locationAccessor,
            Accessor packageAccessor,
            Accessor converterAccessor)
        {
            LoquiType loqui = typeGen as LoquiType;
            var       data  = loqui.GetFieldData();

            switch (data.BinaryOverlayFallback)
            {
            case BinaryGenerationType.Normal:
                break;

            case BinaryGenerationType.NoGeneration:
                return;

            case BinaryGenerationType.Custom:
                using (var args = new ArgsWrapper(fg,
                                                  $"{typeGen.Name}CustomParse"))
                {
                    args.Add("stream");
                    args.Add("finalPos");
                    args.Add("offset");
                }
                return;

            default:
                throw new NotImplementedException();
            }

            string accessor;

            if (loqui.Singleton ||
                !loqui.Nullable)
            {
                accessor = $"_{typeGen.Name}";
            }
            else
            {
                accessor = typeGen.Name;
            }
            if (data.MarkerType.HasValue)
            {
                fg.AppendLine($"stream.Position += {packageAccessor}.{nameof(BinaryOverlayFactoryPackage.MetaData)}.{nameof(ParsingBundle.Constants)}.SubConstants.HeaderLength; // Skip marker");
            }

            if (!loqui.TargetObjectGeneration.IsTypelessStruct() && (loqui.GetFieldData()?.HasTrigger ?? false))
            {
                fg.AppendLine($"_{typeGen.Name}Location = new {GetLocationObjectString(objGen)}({locationAccessor}, finalPos);");
                var severalSubTypes = data.GenerationTypes
                                      .Select(i => i.Value)
                                      .WhereCastable <TypeGeneration, LoquiType>()
                                      .Where(loqui => !loqui?.TargetObjectGeneration?.Abstract ?? true)
                                      .CountGreaterThan(1);
                if (severalSubTypes)
                {
                    fg.AppendLine($"_{typeGen.Name}Type = type;");
                }
            }
            else
            {
                if (NeedsHeaderProcessing(loqui))
                {
                    fg.AppendLine($"stream.Position += _package.{nameof(BinaryOverlayFactoryPackage.MetaData)}.{nameof(ParsingBundle.Constants)}.SubConstants.HeaderLength;");
                }
                using (var args = new ArgsWrapper(fg,
                                                  $"this.{accessor} = {this.Module.BinaryOverlayClassName(loqui)}.{loqui.TargetObjectGeneration.Name}Factory"))
                {
                    args.Add($"stream: stream");
                    args.Add($"package: {packageAccessor}");
                    if (loqui.TargetObjectGeneration.IsVariableLengthStruct())
                    {
                        args.AddPassArg($"finalPos");
                    }
                    args.Add($"recordTypeConverter: {converterAccessor}");
                }
            }
        }
예제 #24
0
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            await base.GenerateInCommonMixin(obj, fg);

            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IReadOnlyCache<T, FormKey> {nameof(IModGetter.GetTopLevelGroupGetter)}<T>"))
            {
                args.Wheres.Add($"where T : {nameof(IMajorRecordCommonGetter)}");
                args.Add($"this {obj.Interface(getter: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (IReadOnlyCache<T, FormKey>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup<T>"))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  "public static ICache<T, FormKey> GetGroup<T>"))
            {
                args.Wheres.Add($"where T : {nameof(IMajorRecordCommon)}");
                args.Add($"this {obj.Interface(getter: false)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (ICache<T, FormKey>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup<T>"))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static void WriteToBinaryParallel"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"Stream stream");
                args.Add($"{nameof(BinaryWriteParameters)}? param = null");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel"))
                {
                    args.AddPassArg("item");
                    args.AddPassArg("stream");
                    args.Add($"param: param ?? {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)}");
                    args.Add("modKey: item.ModKey");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static void WriteToBinaryParallel"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"string path");
                args.Add($"{nameof(BinaryWriteParameters)}? param = null");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"param ??= {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)};");
                using (var args = new ArgsWrapper(fg,
                                                  $"var modKey = param.{nameof(BinaryWriteParameters.RunMasterMatch)}"))
                {
                    args.Add("mod: item");
                    args.AddPassArg("path");
                }
                if (obj.GetObjectData().UsesStringFiles)
                {
                    fg.AppendLine("bool disposeStrings = param.StringsWriter == null;");
                    fg.AppendLine("param.StringsWriter ??= EnumExt.HasFlag((int)item.ModHeader.Flags, (int)ModHeaderCommonFlag.Localized) ? new StringsWriter(modKey, Path.Combine(Path.GetDirectoryName(path)!, \"Strings\")) : null;");
                }
                fg.AppendLine("using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write))");
                using (new BraceWrapper(fg))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel"))
                    {
                        args.AddPassArg("item");
                        args.AddPassArg("stream");
                        args.Add($"param: param");
                        args.AddPassArg("modKey");
                    }
                }
                if (obj.GetObjectData().UsesStringFiles)
                {
                    fg.AppendLine("if (disposeStrings)");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine("param.StringsWriter?.Dispose();");
                    }
                }
            }
            fg.AppendLine();
        }
예제 #25
0
        async Task ApplyIterationLines(
            ObjectGeneration obj,
            TypeGeneration field,
            FileGeneration fieldGen,
            Accessor accessor,
            bool getter,
            bool hasTarget = false,
            HashSet <ObjectGeneration> blackList = null,
            bool includeSelf = true)
        {
            if (field is GroupType group)
            {
                if (blackList?.Contains(group.GetGroupTarget()) ?? false)
                {
                    return;
                }
                if (!hasTarget)
                {
                    fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.EnumerateMajorRecords(type, throwIfUnknown: throwIfUnknown))");
                    using (new BraceWrapper(fieldGen))
                    {
                        using (var args = new ArgsWrapper(fieldGen,
                                                          $"yield return new ModContext<{obj.Interface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>"))
                        {
                            args.Add("modKey: obj.ModKey");
                            args.Add("record: item");
                            args.Add($"getter: (m, r) => m.{group.Name}.GetOrAddAsOverride(({group.GetGroupTarget().Interface(getter: true, internalInterface: true)})r)");
                        }
                    }
                }
                else
                {
                    fieldGen.AppendLine($"foreach (var groupItem in obj.{field.Name})");
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"foreach (var item in {group.GetGroupTarget().CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class)}.Instance.EnumerateMajorRecordContexts(groupItem, linkCache, type, {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}, {(obj.GetObjectType() == ObjectType.Mod ? "parent: null" : "curContext")}, throwIfUnknown: throwIfUnknown, getter: (m, r) => m.{field.Name}.GetOrAddAsOverride(linkCache.Resolve<{group.GetGroupTarget().Interface(getter: true, internalInterface: true)}>(r.FormKey))))");

                        using (new BraceWrapper(fieldGen))
                        {
                            fieldGen.AppendLine("yield return item;");
                        }
                    }
                }
            }
            else if (field is LoquiType loqui)
            {
                if (blackList?.Contains(loqui.TargetObjectGeneration) ?? false)
                {
                    return;
                }
                var fieldAccessor = loqui.Nullable ? $"{obj.ObjectName}{loqui.Name}item" : $"{accessor}.{loqui.Name}";
                if (loqui.TargetObjectGeneration.IsListGroup())
                { // List groups
                    fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.EnumerateMajorRecordContexts(linkCache, type, {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}, {(obj.GetObjectType() == ObjectType.Mod ? "parent: null" : "curContext")}, throwIfUnknown: throwIfUnknown))");
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine("yield return item;");
                    }
                    return;
                }
                var subFg = new FileGeneration();
                await LoquiTypeHandler(
                    subFg,
                    obj,
                    fieldAccessor,
                    loqui,
                    generic : "TMajor",
                    checkType : false,
                    includeSelf : includeSelf,
                    addGetOrAddArg : (args) =>
                {
                    args.Add(subFg =>
                    {
                        subFg.AppendLine($"getter: (m, r) =>");
                        using (new BraceWrapper(subFg))
                        {
                            subFg.AppendLine($"var baseRec = getter(m, linkCache.Resolve<{obj.Interface(getter: true)}>(obj.FormKey));");
                            subFg.AppendLine($"if (baseRec.{loqui.Name} != null) return baseRec.{loqui.Name};");
                            subFg.AppendLine($"var copy = ({loqui.TypeName()})(({loqui.Interface(getter: true)})r).DeepCopy(ModContextExt.{loqui.TargetObjectGeneration.Name}CopyMask);");
                            subFg.AppendLine($"baseRec.{loqui.Name} = copy;");
                            subFg.AppendLine($"return copy;");
                        }
                    });
                });

                if (subFg.Count == 0)
                {
                    return;
                }
                if (loqui.Singleton ||
                    !loqui.Nullable)
                {
                    fieldGen.AppendLines(subFg);
                }
                else
                {
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"if ({accessor}.{loqui.Name}.TryGet(out var {fieldAccessor}))");
                        using (new BraceWrapper(fieldGen))
                        {
                            fieldGen.AppendLines(subFg);
                        }
                    }
                }
            }
            else if (field is ContainerType cont)
            {
                if (!(cont.SubTypeGeneration is LoquiType contLoqui))
                {
                    return;
                }
                if (contLoqui.RefType == LoquiType.LoquiRefType.Generic)
                {
                    fieldGen.AppendLine($"foreach (var item in obj.{field.Name})");
                    using (new BraceWrapper(fieldGen))
                    {
                        if (await contLoqui.TargetObjectGeneration.IsMajorRecord())
                        {
                            fieldGen.AppendLine($"if (type.IsAssignableFrom(typeof({contLoqui.GenericDef.Name})))");
                            using (new BraceWrapper(fieldGen))
                            {
                                fieldGen.AppendLine($"yield return ({nameof(IMajorRecordCommonGetter)})item;");
                            }
                        }
                        fieldGen.AppendLine($"foreach (var subItem in item.EnumerateMajorRecords(type, throwIfUnknown: throwIfUnknown))");
                        using (new BraceWrapper(fieldGen))
                        {
                            fieldGen.AppendLine($"yield return subItem;");
                        }
                    }
                }
                else if (contLoqui.TargetObjectGeneration?.IsListGroup() ?? false)
                {
                    using (var args = new ArgsWrapper(fieldGen,
                                                      $"foreach (var item in {accessor}.{field.Name}.EnumerateMajorRecordContexts",
                                                      suffixLine: ")")
                    {
                        SemiColon = false
                    })
                    {
                        args.AddPassArg("type");
                        args.Add($"modKey: {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}");
                        args.Add($"parent: {(obj.GetObjectType() == ObjectType.Mod ? "null" : "curContext")}");
                        args.AddPassArg("linkCache");
                        args.Add("throwIfUnknown: false");
                        args.Add("worldspace: obj");
                        args.AddPassArg("getter");
                    }
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine("yield return item;");
                    }
                }
                else
                {
                    var isMajorRecord = contLoqui.TargetObjectGeneration != null && await contLoqui.TargetObjectGeneration.IsMajorRecord();

                    if (isMajorRecord ||
                        await MajorRecordModule.HasMajorRecords(contLoqui, includeBaseClass: true) != Case.No)
                    {
                        switch (await MajorRecordModule.HasMajorRecords(contLoqui, includeBaseClass: true))
                        {
                        case Case.Yes:
                            fieldGen.AppendLine($"foreach (var subItem in {accessor}.{field.Name}{(field.Nullable ? ".EmptyIfNull()" : null)})");
                            using (new BraceWrapper(fieldGen))
                            {
                                await LoquiTypeHandler(
                                    fieldGen,
                                    obj,
                                    $"subItem",
                                    contLoqui,
                                    generic : "TMajor",
                                    checkType : true,
                                    addGetOrAddArg : (args) =>
                                {
                                    args.Add(subFg =>
                                    {
                                        subFg.AppendLine($"getter: (m, r) =>");
                                        using (new BraceWrapper(subFg))
                                        {
                                            subFg.AppendLine($"var copy = ({contLoqui.TypeName()})(({contLoqui.Interface(getter: true)})r).DeepCopy();");
                                            subFg.AppendLine($"getter(m, linkCache.Resolve<{obj.Interface(getter: true)}>(obj.FormKey)).{cont.Name}.Add(copy);");
                                            subFg.AppendLine($"return copy;");
                                        }
                                    });
                                });
                            }
                            break;

                        case Case.Maybe:
                            throw new NotImplementedException();

                        case Case.No:
                        default:
                            break;
                        }
                    }
                }
            }
            else if (field is DictType dict)
            {
                throw new NotImplementedException();
            }
        }
예제 #26
0
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            await base.GenerateInCommonMixin(obj, fg);

            var    objData = obj.GetObjectData();
            string gameReleaseStr;

            if (objData.GameReleaseOptions == null)
            {
                gameReleaseStr = $"{nameof(GameRelease)}.{obj.GetObjectData().GameCategory}";
            }
            else
            {
                gameReleaseStr = $"item.GameRelease";
            }

            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IGroupGetter<T> {nameof(IModGetter.GetTopLevelGroup)}<T>"))
            {
                args.Wheres.Add($"where T : {nameof(IMajorRecordGetter)}");
                args.Add($"this {obj.Interface(getter: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (IGroupGetter<T>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup"))
                {
                    args.AddPassArg("obj");
                    args.Add("type: typeof(T)");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static IGroupGetter {nameof(IModGetter.GetTopLevelGroup)}"))
            {
                args.Add($"this {obj.Interface(getter: true)} obj");
                args.Add("Type type");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (IGroupGetter){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("type");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static IGroup<T> {nameof(IMod.GetTopLevelGroup)}<T>"))
            {
                args.Wheres.Add($"where T : {nameof(IMajorRecord)}");
                args.Add($"this {obj.Interface(getter: false)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (IGroup<T>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup"))
                {
                    args.AddPassArg("obj");
                    args.Add("type: typeof(T)");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static IGroup {nameof(IModGetter.GetTopLevelGroup)}"))
            {
                args.Add($"this {obj.Interface(getter: false)} obj");
                args.Add("Type type");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (IGroup){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("type");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static void WriteToBinaryParallel"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"Stream stream");
                args.Add($"{nameof(BinaryWriteParameters)}? param = null");
                args.Add($"{nameof(ParallelWriteParameters)}? parallelParam = null");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel"))
                {
                    args.AddPassArg("item");
                    args.AddPassArg("stream");
                    args.Add($"parallelParam: parallelParam ?? {nameof(ParallelWriteParameters)}.{nameof(ParallelWriteParameters.Default)}");
                    args.Add($"param: param ?? {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)}");
                    args.Add("modKey: item.ModKey");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static void WriteToBinaryParallel"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"string path");
                args.Add($"{nameof(BinaryWriteParameters)}? param = null");
                args.Add($"{nameof(ParallelWriteParameters)}? parallelParam = null");
                args.Add($"{nameof(IFileSystem)}? fileSystem = null");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"param ??= {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)};");
                fg.AppendLine($"parallelParam ??= {nameof(ParallelWriteParameters)}.{nameof(ParallelWriteParameters.Default)};");
                using (var args = new ArgsWrapper(fg,
                                                  $"var modKey = param.{nameof(BinaryWriteParameters.RunMasterMatch)}"))
                {
                    args.Add("mod: item");
                    args.AddPassArg("path");
                }
                if (obj.GetObjectData().UsesStringFiles)
                {
                    fg.AppendLine($"param.StringsWriter ??= EnumExt.HasFlag((int)item.ModHeader.Flags, (int)ModHeaderCommonFlag.Localized) ? new StringsWriter({gameReleaseStr}, modKey, Path.Combine(Path.GetDirectoryName(path)!, \"Strings\"), {nameof(MutagenEncodingProvider)}.{nameof(MutagenEncodingProvider.Instance)}) : null;");
                    fg.AppendLine("bool disposeStrings = param.StringsWriter != null;");
                }
                fg.AppendLine("using (var stream = fileSystem.GetOrDefault().FileStream.Create(path, FileMode.Create, FileAccess.Write))");
                using (new BraceWrapper(fg))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel"))
                    {
                        args.AddPassArg("item");
                        args.AddPassArg("stream");
                        args.AddPassArg("parallelParam");
                        args.Add($"param: param");
                        args.AddPassArg("modKey");
                    }
                }
                if (obj.GetObjectData().UsesStringFiles)
                {
                    fg.AppendLine("if (disposeStrings)");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine("param.StringsWriter?.Dispose();");
                    }
                }
            }
            fg.AppendLine();
        }
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            var    needsCatch = obj.GetObjectType() == ObjectType.Mod;
            string catchLine  = needsCatch ? ".Catch(e => throw RecordException.Enrich(e, obj.ModKey))" : string.Empty;
            string enderSemi  = needsCatch ? string.Empty : ";";

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords",
                                                  suffixLine: catchLine))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<TMajor> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
                args.Wheres.Add($"where TMajor : class, IMajorRecordCommonGetter");
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
                args.Add($"bool throwIfUnknown = true");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => (TMajor)m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
                args.Add($"Type type");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => ({nameof(IMajorRecordCommonGetter)})m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommon)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumerateMajorRecords",
                                                  suffixLine: catchLine))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<TMajor> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Wheres.Add($"where TMajor : class, IMajorRecordCommon");
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumerateMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.Add("type: typeof(TMajor)");
                    args.Add("throwIfUnknown: true");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => (TMajor)m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommon)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"Type? type");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumeratePotentiallyTypedMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => ({nameof(IMajorRecordCommon)})m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();
        }
예제 #28
0
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            bool getter = maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class);

            if (!getter)
            {
                return;
            }
            var accessor = new Accessor("obj");

            if (obj.Abstract)
            {
                return;
            }
            if (obj.GetObjectType() == ObjectType.Group)
            {
                return;
            }
            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            var overrideStr = await obj.FunctionOverride(async c => await MajorRecordModule.HasMajorRecords(c, includeBaseClass : false, includeSelf : true) != Case.No);

            using (var args = new FunctionWrapper(fg,
                                                  $"public{overrideStr}IEnumerable<IModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>> EnumerateMajorRecordContexts"))
            {
                args.Add($"{obj.Interface(getter: getter, internalInterface: true)} obj");
                args.Add($"{nameof(ILinkCache)} linkCache");
                args.Add($"Type type");
                if (obj.GetObjectType() != ObjectType.Mod)
                {
                    args.Add($"{nameof(ModKey)} modKey");
                    args.Add($"IModContext? parent");
                }
                args.Add($"bool throwIfUnknown");
                if (obj.GetObjectType() == ObjectType.Record)
                {
                    args.Add($"Func<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, {obj.Interface(getter: true)}, {obj.Interface(getter: false)}> getter");
                }
            }
            using (new BraceWrapper(fg))
            {
                if (obj.GetObjectType() == ObjectType.Record)
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"var curContext = new ModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}>"))
                    {
                        args.Add($"{(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}");
                        args.Add("record: obj");
                        args.AddPassArg("getter");
                        args.AddPassArg("parent");
                    }
                }
                var fgCount = fg.Count;
                fg.AppendLine("switch (type.Name)");
                using (new BraceWrapper(fg))
                {
                    var gameCategory = obj.GetObjectData().GameCategory;
                    Dictionary <object, FileGeneration> generationDict = new Dictionary <object, FileGeneration>();
                    foreach (var field in obj.IterateFields())
                    {
                        FileGeneration fieldGen;
                        if (field is LoquiType loqui)
                        {
                            if (loqui.TargetObjectGeneration.IsListGroup())
                            {
                                continue;
                            }
                            var isMajorRecord = loqui.TargetObjectGeneration != null && await loqui.TargetObjectGeneration.IsMajorRecord();

                            if (!isMajorRecord &&
                                await MajorRecordModule.HasMajorRecords(loqui, includeBaseClass: true) == Case.No)
                            {
                                continue;
                            }

                            if (loqui.TargetObjectGeneration.GetObjectType() == ObjectType.Group)
                            {
                                fieldGen = generationDict.GetOrAdd(loqui.GetGroupTarget());
                            }
                            else
                            {
                                fieldGen = generationDict.GetOrAdd(((object)loqui?.TargetObjectGeneration) ?? loqui);
                            }
                        }
                        else if (field is ContainerType cont)
                        {
                            if (!(cont.SubTypeGeneration is LoquiType contLoqui))
                            {
                                continue;
                            }
                            if (contLoqui.RefType == LoquiType.LoquiRefType.Generic)
                            {
                                fieldGen = generationDict.GetOrAdd("default:");
                            }
                            else
                            {
                                fieldGen = generationDict.GetOrAdd(((object)contLoqui?.TargetObjectGeneration) ?? contLoqui);
                            }
                        }
                        else if (field is DictType dict)
                        {
                            if (dict.Mode != DictMode.KeyedValue)
                            {
                                continue;
                            }
                            if (!(dict.ValueTypeGen is LoquiType dictLoqui))
                            {
                                continue;
                            }
                            if (dictLoqui.RefType == LoquiType.LoquiRefType.Generic)
                            {
                                fieldGen = generationDict.GetOrAdd("default:");
                            }
                            else
                            {
                                fieldGen = generationDict.GetOrAdd(((object)dictLoqui?.TargetObjectGeneration) ?? dictLoqui);
                            }
                        }
                        else
                        {
                            continue;
                        }
                        await ApplyIterationLines(obj, field, fieldGen, accessor, getter);
                    }

                    bool doAdditionlDeepLogic = obj.Name != "ListGroup";

                    if (doAdditionlDeepLogic)
                    {
                        var deepRecordMapping = await MajorRecordModule.FindDeepRecords(obj);

                        foreach (var deepRec in deepRecordMapping)
                        {
                            FileGeneration deepFg = generationDict.GetOrAdd(deepRec.Key);
                            foreach (var field in deepRec.Value)
                            {
                                await ApplyIterationLines(obj, field, deepFg, accessor, getter, hasTarget : true, includeSelf : false);
                            }
                        }

                        HashSet <string> blackList = new HashSet <string>();
                        foreach (var kv in generationDict)
                        {
                            switch (kv.Key)
                            {
                            case LoquiType loqui:
                                if (loqui.RefType == LoquiType.LoquiRefType.Generic)
                                {
                                    // Handled in default case
                                    continue;
                                }
                                else
                                {
                                    fg.AppendLine($"case \"{loqui.Interface(getter: true)}\":");
                                    fg.AppendLine($"case \"{loqui.Interface(getter: false)}\":");
                                    if (loqui.HasInternalGetInterface)
                                    {
                                        fg.AppendLine($"case \"{loqui.Interface(getter: true, internalInterface: true)}\":");
                                    }
                                    if (loqui.HasInternalSetInterface)
                                    {
                                        fg.AppendLine($"case \"{loqui.Interface(getter: false, internalInterface: true)}\":");
                                    }
                                    if (loqui.RefType == LoquiType.LoquiRefType.Interface)
                                    {
                                        blackList.Add(loqui.SetterInterface);
                                    }
                                }
                                break;

                            case ObjectGeneration targetObj:
                                fg.AppendLine($"case \"{targetObj.ObjectName}\":");
                                fg.AppendLine($"case \"{targetObj.Interface(getter: true)}\":");
                                fg.AppendLine($"case \"{targetObj.Interface(getter: false)}\":");
                                if (targetObj.HasInternalGetInterface)
                                {
                                    fg.AppendLine($"case \"{targetObj.Interface(getter: true, internalInterface: true)}\":");
                                }
                                if (targetObj.HasInternalSetInterface)
                                {
                                    fg.AppendLine($"case \"{targetObj.Interface(getter: false, internalInterface: true)}\":");
                                }
                                break;

                            case string str:
                                if (str != "default:")
                                {
                                    throw new NotImplementedException();
                                }
                                continue;

                            default:
                                throw new NotImplementedException();
                            }
                            using (new DepthWrapper(fg))
                            {
                                fg.AppendLines(kv.Value);
                                fg.AppendLine("yield break;");
                            }
                        }

                        // Generate for major record marker interfaces
                        if (LinkInterfaceModule.ObjectMappings.TryGetValue(obj.ProtoGen.Protocol, out var interfs))
                        {
                            foreach (var interf in interfs)
                            {
                                if (blackList.Contains(interf.Key))
                                {
                                    continue;
                                }
                                FileGeneration             subFg         = new FileGeneration();
                                HashSet <ObjectGeneration> passedObjects = new HashSet <ObjectGeneration>();
                                HashSet <TypeGeneration>   deepObjects   = new HashSet <TypeGeneration>();
                                foreach (var subObj in interf.Value)
                                {
                                    var grup = obj.Fields
                                               .WhereCastable <TypeGeneration, GroupType>()
                                               .Where(g => g.GetGroupTarget() == subObj)
                                               .FirstOrDefault();

                                    if (grup != null)
                                    {
                                        subFg.AppendLine($"foreach (var item in EnumerateMajorRecordContexts({accessor}, linkCache, typeof({grup.GetGroupTarget().Interface(getter: true)}), throwIfUnknown: throwIfUnknown))");
                                        using (new BraceWrapper(subFg))
                                        {
                                            subFg.AppendLine("yield return item;");
                                        }
                                        passedObjects.Add(grup.GetGroupTarget());
                                    }
                                    else if (deepRecordMapping.TryGetValue(subObj, out var deepRec))
                                    {
                                        foreach (var field in deepRec)
                                        {
                                            deepObjects.Add(field);
                                        }
                                    }
                                }
                                foreach (var deepObj in deepObjects)
                                {
                                    await ApplyIterationLines(obj, deepObj, subFg, accessor, getter, blackList : passedObjects, hasTarget : true, includeSelf : false);
                                }
                                if (!subFg.Empty)
                                {
                                    fg.AppendLine($"case \"{interf.Key}\":");
                                    fg.AppendLine($"case \"{interf.Key}Getter\":");
                                    using (new BraceWrapper(fg))
                                    {
                                        fg.AppendLines(subFg);
                                        fg.AppendLine("yield break;");
                                    }
                                }
                            }
                        }
                    }

                    fg.AppendLine("default:");
                    using (new DepthWrapper(fg))
                    {
                        if (generationDict.TryGetValue("default:", out var gen))
                        {
                            fg.AppendLines(gen);
                            fg.AppendLine("yield break;");
                        }
                        else
                        {
                            fg.AppendLine("if (throwIfUnknown)");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("throw new ArgumentException($\"Unknown major record type: {type}\");");
                            }
                            fg.AppendLine($"else");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("yield break;");
                            }
                        }
                    }
                }
            }
            fg.AppendLine();
        }
예제 #29
0
        private void GenerateWriteParallel(ObjectGeneration obj, FileGeneration fg)
        {
            LoquiType groupInstance     = null;
            LoquiType listGroupInstance = null;
            var       objData           = obj.GetObjectData();

            fg.AppendLine("const int CutCount = 100;");
            using (var args = new FunctionWrapper(fg,
                                                  "public static void WriteParallel"))
            {
                args.Add($"{obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"Stream stream");
                args.Add($"{nameof(BinaryWriteParameters)} param");
                args.Add($"ModKey modKey");
            }
            using (new BraceWrapper(fg))
            {
                string gameConstantsStr;
                if (objData.GameReleaseOptions == null)
                {
                    gameConstantsStr = $"{nameof(GameConstants)}.{obj.GetObjectData().GameCategory}";
                }
                else
                {
                    fg.AppendLine($"var gameConstants = {nameof(GameConstants)}.Get(item.{ReleaseEnumName(obj)}.ToGameRelease());");
                    gameConstantsStr = $"gameConstants";
                }
                fg.AppendLine($"var bundle = new {nameof(WritingBundle)}({gameConstantsStr});");
                fg.AppendLine($"var writer = new MutagenWriter(stream, bundle);");
                using (var args = new ArgsWrapper(fg,
                                                  $"{nameof(ModHeaderWriteLogic)}.{nameof(ModHeaderWriteLogic.WriteHeader)}"))
                {
                    args.AddPassArg("param");
                    args.AddPassArg("writer");
                    args.Add("mod: item");
                    args.Add("modHeader: item.ModHeader.DeepCopy()");
                    args.AddPassArg("modKey");
                }

                int groupCount = obj.IterateFields()
                                 .Select(f => f as LoquiType)
                                 .Where(l => l != null)
                                 .Where(l => l.TargetObjectGeneration?.GetObjectData().ObjectType == ObjectType.Group)
                                 .Count();

                fg.AppendLine($"Stream[] outputStreams = new Stream[{groupCount}];");
                fg.AppendLine($"List<Action> toDo = new List<Action>();");
                int i = 0;
                foreach (var field in obj.IterateFields())
                {
                    if (!(field is LoquiType loqui))
                    {
                        continue;
                    }
                    if (loqui.TargetObjectGeneration?.GetObjectData().ObjectType != ObjectType.Group)
                    {
                        continue;
                    }
                    if (loqui.TargetObjectGeneration.Name == "ListGroup")
                    {
                        listGroupInstance = loqui;
                    }
                    else
                    {
                        groupInstance = loqui;
                    }
                    if (loqui.GetGroupTarget().GetObjectData().CustomBinaryEnd == CustomEnd.Off &&
                        loqui.TargetObjectGeneration.Name != "ListGroup")
                    {
                        fg.AppendLine($"toDo.Add(() => WriteGroupParallel(item.{field.Name}, writer.MetaData.MasterReferences!, {i}{(objData.GameReleaseOptions == null ? null : ", gameConstants")}, outputStreams{(objData.UsesStringFiles ? ", param.StringsWriter" : null)}));");
                    }
                    else
                    {
                        fg.AppendLine($"toDo.Add(() => Write{field.Name}Parallel(item.{field.Name}, writer.MetaData.MasterReferences!, {i}{(objData.GameReleaseOptions == null ? null : ", gameConstants")}, outputStreams));");
                    }
                    i++;
                }
                fg.AppendLine("Parallel.Invoke(toDo.ToArray());");
                using (var args = new ArgsWrapper(fg,
                                                  $"{nameof(UtilityTranslation)}.{nameof(UtilityTranslation.CompileStreamsInto)}"))
                {
                    args.Add("outputStreams.NotNull()");
                    args.Add("stream");
                }
            }
            fg.AppendLine();

            if (groupInstance != null)
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"public static void WriteGroupParallel<T>"))
                {
                    args.Add("IGroupGetter<T> group");
                    args.Add($"{nameof(MasterReferenceReader)} masters");
                    args.Add("int targetIndex");
                    if (objData.GameReleaseOptions != null)
                    {
                        args.Add($"{nameof(GameConstants)} gameConstants");
                    }
                    args.Add("Stream[] streamDepositArray");
                    if (objData.UsesStringFiles)
                    {
                        args.Add($"{nameof(StringsWriter)}? stringsWriter");
                    }
                    args.Wheres.AddRange(groupInstance.TargetObjectGeneration.GenerateWhereClauses(LoquiInterfaceType.IGetter, groupInstance.TargetObjectGeneration.Generics));
                }
                using (new BraceWrapper(fg))
                {
                    string gameConstantsStr;
                    if (objData.GameReleaseOptions == null)
                    {
                        gameConstantsStr = $"{nameof(GameConstants)}.{obj.GetObjectData().GameCategory}";
                    }
                    else
                    {
                        gameConstantsStr = "gameConstants";
                    }
                    fg.AppendLine("if (group.RecordCache.Count == 0) return;");
                    fg.AppendLine($"var cuts = group.Cut(CutCount).ToArray();");
                    fg.AppendLine($"Stream[] subStreams = new Stream[cuts.Length + 1];");
                    fg.AppendLine($"byte[] groupBytes = new byte[{gameConstantsStr}.GroupConstants.HeaderLength];");
                    fg.AppendLine($"BinaryPrimitives.WriteInt32LittleEndian(groupBytes.AsSpan(), RecordTypes.GRUP.TypeInt);");
                    fg.AppendLine($"var groupByteStream = new MemoryStream(groupBytes);");
                    fg.AppendLine($"using (var stream = new MutagenWriter(groupByteStream, {gameConstantsStr}, dispose: false))");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine($"stream.Position += 8;");
                        fg.AppendLine($"GroupBinaryWriteTranslation.WriteEmbedded<T>(group, stream);");
                    }
                    fg.AppendLine($"subStreams[0] = groupByteStream;");
                    fg.AppendLine($"Parallel.ForEach(cuts, (cutItems, state, counter) =>");
                    using (new BraceWrapper(fg)
                    {
                        AppendSemicolon = true, AppendParenthesis = true
                    })
                    {
                        fg.AppendLine($"{nameof(MemoryTributary)} trib = new {nameof(MemoryTributary)}();");
                        fg.AppendLine($"var bundle = new {nameof(WritingBundle)}({gameConstantsStr})");
                        using (var prop = new PropertyCtorWrapper(fg))
                        {
                            prop.Add($"{nameof(WritingBundle.MasterReferences)} = masters");
                            if (objData.UsesStringFiles)
                            {
                                prop.Add($"{nameof(WritingBundle.StringsWriter)} = stringsWriter");
                            }
                        }
                        fg.AppendLine($"using (var stream = new MutagenWriter(trib, bundle, dispose: false))");
                        using (new BraceWrapper(fg))
                        {
                            fg.AppendLine($"foreach (var item in cutItems)");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine($"item.WriteToBinary(stream);");
                            }
                        }
                        fg.AppendLine($"subStreams[(int)counter + 1] = trib;");
                    }
                    fg.AppendLine($"UtilityTranslation.CompileSetGroupLength(subStreams, groupBytes);");
                    fg.AppendLine($"streamDepositArray[targetIndex] = new CompositeReadStream(subStreams, resetPositions: true);");
                }
                fg.AppendLine();
            }
        }
예제 #30
0
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            var    needsCatch = obj.GetObjectType() == ObjectType.Mod;
            string catchLine  = needsCatch ? ".Catch(e => throw RecordException.Factory(e, obj.ModKey))" : string.Empty;
            string enderSemi  = needsCatch ? string.Empty : ";";

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<IModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, TSetter, TGetter>> EnumerateMajorRecordContexts{obj.GetGenericTypes(MaskType.Normal, new string[] { "TSetter", "TGetter" })}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
                args.Wheres.Add($"where TSetter : class, IMajorRecordCommon, TGetter");
                args.Wheres.Add($"where TGetter : class, IMajorRecordCommonGetter");
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
                args.Add($"{nameof(ILinkCache)} linkCache");
                args.Add($"bool throwIfUnknown = true");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecordContexts"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("linkCache");
                    args.Add("type: typeof(TGetter)");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => m.AsType<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, {nameof(IMajorRecordCommon)}, {nameof(IMajorRecordCommonGetter)}, TSetter, TGetter>()){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<IModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>> EnumerateMajorRecordContexts{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
                args.Add($"{nameof(ILinkCache)} linkCache");
                args.Add($"Type type");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecordContexts"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("linkCache");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
            }
            fg.AppendLine();
        }