Exemple #1
0
        public static async Task <bool> IsMajorRecord(this ObjectGeneration objGen)
        {
            if (objGen.GetObjectType() != ObjectType.Record)
            {
                return(false);
            }
            if (objGen.Name == "MajorRecord")
            {
                return(true);
            }
            await Task.WhenAll(objGen.BaseClassTrail().Select(bo => bo.LoadingCompleteTask.Task));

            return(objGen.BaseClassTrail().Any(bo => bo.Name == "MajorRecord"));
        }
        public bool HasAsyncRecords(ObjectGeneration obj, bool self)
        {
            IEnumerable <ObjectGeneration> enumer = obj.BaseClassTrail();

            if (self)
            {
                enumer = enumer.And(obj);
            }
            return(enumer
                   .SelectMany(o => GetRecordTypeFields(o))
                   .Any(t =>
            {
                if (this.TryGetTypeGeneration(t.GetType(), out var gen))
                {
                    return gen.IsAsync(t, read: true);
                }
                return false;
            }));
        }
Exemple #3
0
 public static async Task <bool> GetNeedsMasters(this ObjectGeneration objGen)
 {
     if (objGen.GetObjectType() == ObjectType.Group)
     {
         return(true);
     }
     foreach (var field in objGen.IterateFields())
     {
         if (field is FormKeyType)
         {
             return(true);
         }
         if (field is FormIDType)
         {
             return(true);
         }
         if (field is ContainerType cont)
         {
             if (cont.SubTypeGeneration is LoquiType loqui &&
                 (loqui.TargetObjectGeneration == null || await loqui.TargetObjectGeneration.GetNeedsMasters()))
             {
                 return(true);
             }
         }
         if (field is DictType dict)
         {
             if (dict.ValueTypeGen is LoquiType loqui &&
                 (loqui.TargetObjectGeneration == null || await loqui.TargetObjectGeneration.GetNeedsMasters()))
             {
                 return(true);
             }
         }
     }
     foreach (var baseObj in objGen.BaseClassTrail())
     {
         if (await baseObj.GetNeedsMasters())
         {
             return(true);
         }
     }
     return(false);
 }
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            if (maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class))
            {
                fg.AppendLine($"public IEnumerable<{nameof(IFormLinkGetter)}> GetContainedFormLinks({obj.Interface(getter: true)} obj)");
                using (new BraceWrapper(fg))
                {
                    foreach (var baseClass in obj.BaseClassTrail())
                    {
                        if (await HasLinks(baseClass, includeBaseClass: true) != Case.No)
                        {
                            fg.AppendLine("foreach (var item in base.GetContainedFormLinks(obj))");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("yield return item;");
                            }
                            break;
                        }
                    }
                    var startCount = fg.Count;
                    foreach (var field in obj.IterateFields(nonIntegrated: true))
                    {
                        if (field is FormLinkType formLink)
                        {
                            if (field.Nullable)
                            {
                                fg.AppendLine($"if (obj.{field.Name}.{formLink.FormIDTypeString}.HasValue)");
                                using (new BraceWrapper(fg))
                                {
                                    fg.AppendLine($"yield return {nameof(FormLinkInformation)}.{nameof(FormLinkInformation.Factory)}(obj.{field.Name});");
                                }
                            }
                            else if (formLink.FormIDType == FormLinkType.FormIDTypeEnum.Normal)
                            {
                                fg.AppendLine($"yield return {nameof(FormLinkInformation)}.{nameof(FormLinkInformation.Factory)}(obj.{field.Name});");
                            }
                        }
                        else if (field is FormKeyType formKey &&
                                 obj.Name != "MajorRecord")
                        {
                            if (field.Nullable)
                            {
                                fg.AppendLine($"if (obj.{field.Name} != null)");
                                using (new BraceWrapper(fg))
                                {
                                    fg.AppendLine($"yield return {nameof(FormLinkInformation)}.{nameof(FormLinkInformation.Factory)}(obj.{field.Name}.AsLink<I{obj.ProtoGen.Protocol.Namespace}MajorRecordGetter>());");
                                }
                            }
                            else
                            {
                                fg.AppendLine($"yield return {nameof(FormLinkInformation)}.{nameof(FormLinkInformation.Factory)}(obj.{field.Name}.AsLink<I{obj.ProtoGen.Protocol.Namespace}MajorRecordGetter>());");
                            }
                        }
                        else if (field is LoquiType loqui)
                        {
                            Case subLinkCase;
                            if (loqui.TargetObjectGeneration != null)
                            {
                                subLinkCase = await HasLinks(loqui, includeBaseClass : true);
                            }
                            else
                            {
                                subLinkCase = Case.Maybe;
                            }
                            if (subLinkCase == Case.No)
                            {
                                continue;
                            }
                            var doBrace = true;
                            var access  = $"obj.{field.Name}";
                            if (subLinkCase == Case.Maybe)
                            {
                                fg.AppendLine($"if (obj.{field.Name} is {nameof(IFormLinkContainerGetter)} {field.Name}linkCont)");
                                access = $"{field.Name}linkCont";
                            }
                            else if (loqui.Nullable)
                            {
                                fg.AppendLine($"if (obj.{field.Name} is {{}} {field.Name}Items)");
                                access = $"{field.Name}Items";
                            }
                            else
                            {
                                doBrace = false;
                            }
                            using (new BraceWrapper(fg, doIt: doBrace))
                            {
                                fg.AppendLine($"foreach (var item in {access}.{nameof(IFormLinkContainerGetter.ContainedFormLinks)})");
                                using (new BraceWrapper(fg))
                                {
                                    fg.AppendLine($"yield return item;");
                                }
                            }
                        }
                        else if (field is WrapperType cont)
                        {
                            var access = $"obj.{field.Name}";
                            if (field.Nullable)
                            {
                                access = $"{field.Name}Item";
                            }

                            FileGeneration subFg = new FileGeneration();
                            if (cont.SubTypeGeneration is LoquiType contLoqui &&
                                await HasLinks(contLoqui, includeBaseClass: true) != Case.No)
                            {
                                string filterNulls = cont is GenderedType && ((GenderedType)cont).ItemNullable ? ".NotNull()" : null;
                                var    linktype    = await HasLinks(contLoqui, includeBaseClass : true);

                                if (linktype != Case.No)
                                {
                                    switch (linktype)
                                    {
                                    case Case.Yes:
                                        subFg.AppendLine($"foreach (var item in {access}{filterNulls}.SelectMany(f => f.{nameof(IFormLinkContainerGetter.ContainedFormLinks)}))");
                                        break;

                                    case Case.Maybe:
                                        subFg.AppendLine($"foreach (var item in {access}{filterNulls}.WhereCastable<{contLoqui.TypeName(getter: true)}, {nameof(IFormLinkContainerGetter)}>()");
                                        using (new DepthWrapper(subFg))
                                        {
                                            subFg.AppendLine($".SelectMany((f) => f.{nameof(IFormLinkContainerGetter.ContainedFormLinks)}))");
                                        }
                                        break;

                                    default:
                                        throw new NotImplementedException();
                                    }
                                }
                            }
                            else if (cont.SubTypeGeneration is FormLinkType formIDType &&
                                     formIDType.FormIDType == FormLinkType.FormIDTypeEnum.Normal)
                            {
                                string filterNulls = cont is GenderedType && ((GenderedType)cont).ItemNullable ? ".NotNull()" : null;
                                subFg.AppendLine($"foreach (var item in {access}{filterNulls})");
                            }
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            bool getter = maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class);
            bool setter = maskTypes.Applicable(LoquiInterfaceType.ISetter, CommonGenerics.Class);

            if (!getter && !setter)
            {
                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}IEnumerable<{nameof(IMajorRecordCommon)}{(getter ? "Getter" : null)}> EnumerateMajorRecords"))
            {
                args.Add($"{obj.Interface(getter: getter, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                if (setter)
                {
                    fg.AppendLine($"foreach (var item in {obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class)}.Instance.EnumerateMajorRecords(obj))");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine($"yield return (item as {nameof(IMajorRecordCommon)})!;");
                    }
                }
                else
                {
                    var fgCount = fg.Count;
                    foreach (var baseClass in obj.BaseClassTrail())
                    {
                        if (await MajorRecordModule.HasMajorRecords(baseClass, includeBaseClass: true, includeSelf: true) != Case.No)
                        {
                            fg.AppendLine("foreach (var item in base.EnumerateMajorRecords(obj))");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("yield return item;");
                            }
                            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 isMajorRecord = loqui.TargetObjectGeneration != null && await loqui.TargetObjectGeneration.IsMajorRecord();

                            if (isMajorRecord ||
                                await MajorRecordModule.HasMajorRecords(loqui, includeBaseClass: true) != Case.No)
                            {
                                var subFg         = new FileGeneration();
                                var fieldAccessor = loqui.Nullable ? $"{loqui.Name}item" : $"{accessor}.{loqui.Name}";
                                await LoquiTypeHandler(subFg, fieldAccessor, loqui, generic : null, checkType : false);

                                if (subFg.Count == 0)
                                {
                                    continue;
                                }
                                if (loqui.Singleton ||
                                    !loqui.Nullable)
                                {
                                    fieldFg.AppendLines(subFg);
                                }
                                else
                                {
                                    fieldFg.AppendLine($"if ({accessor}.{loqui.Name}.TryGet(out var {loqui.Name}item))");
                                    using (new BraceWrapper(fieldFg))
                                    {
                                        fieldFg.AppendLines(subFg);
                                    }
                                }
                            }
                        }
                        else if (field is ContainerType cont)
                        {
                            if (!(cont.SubTypeGeneration is LoquiType contLoqui))
                            {
                                continue;
                            }
                            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:
                                    fieldFg.AppendLine($"foreach (var subItem in {accessor}.{field.Name}{(field.Nullable ? ".EmptyIfNull()" : null)})");
                                    using (new BraceWrapper(fieldFg))
                                    {
                                        await LoquiTypeHandler(fieldFg, $"subItem", contLoqui, generic : null, checkType : false);
                                    }
                                    break;

                                case Case.Maybe:
                                    fieldFg.AppendLine($"foreach (var subItem in {accessor}.{field.Name}{(field.Nullable ? ".EmptyIfNull()" : null)}.WhereCastable<{contLoqui.TypeName(getter: false)}, {(getter ? nameof(IMajorRecordGetterEnumerable) : nameof(IMajorRecordEnumerable))}>())");
                                    using (new BraceWrapper(fieldFg))
                                    {
                                        await LoquiTypeHandler(fieldFg, $"subItem", contLoqui, generic : null, checkType : false);
                                    }
                                    break;

                                case Case.No:
                                default:
                                    break;
                                }
                            }
                        }
                        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:
                                    fieldFg.AppendLine($"foreach (var subItem in {accessor}.{field.Name}.Items)");
                                    using (new BraceWrapper(fieldFg))
                                    {
                                        await LoquiTypeHandler(fieldFg, $"subItem", dictLoqui, generic : null, checkType : false);
                                    }
                                    break;

                                case Case.Maybe:
                                    fieldFg.AppendLine($"foreach (var subItem in {accessor}.{field.Name}.Items.WhereCastable<{dictLoqui.TypeName(getter: false)}, {(getter ? nameof(IMajorRecordGetterEnumerable) : nameof(IMajorRecordEnumerable))}>())");
                                    using (new BraceWrapper(fieldFg))
                                    {
                                        await LoquiTypeHandler(fieldFg, $"subItem", dictLoqui, generic : null, checkType : false);
                                    }
                                    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);
                            }
                        }
                    }
                    if (fgCount == fg.Count)
                    {
                        fg.AppendLine("yield 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 IEnumerable<{nameof(IMajorRecordCommon)}{(getter ? "Getter" : null)}> EnumerateMajorRecords"))
                    {
                        args.Add($"{baseClass.Interface(getter: getter)} obj");
                    }
                    using (new BraceWrapper(fg))
                    {
                        using (var args = new ArgsWrapper(fg,
                                                          "EnumerateMajorRecords"))
                        {
                            args.Add($"({obj.Interface(getter: getter)})obj");
                        }
                    }
                    fg.AppendLine();
                }
            }

            using (var args = new FunctionWrapper(fg,
                                                  $"public{overrideStr}IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumeratePotentiallyTypedMajorRecords"))
            {
                args.Add($"{obj.Interface(getter: getter, internalInterface: true)} obj");
                args.Add($"Type? type");
                args.Add($"bool throwIfUnknown");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine("if (type == null) return EnumerateMajorRecords(obj);");
                fg.AppendLine("return EnumerateMajorRecords(obj, type, throwIfUnknown);");
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public{overrideStr}IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords"))
            {
                args.Add($"{obj.Interface(getter: getter, internalInterface: true)} obj");
                args.Add($"Type type");
                args.Add($"bool throwIfUnknown");
            }
            using (new BraceWrapper(fg))
            {
                if (setter)
                {
                    fg.AppendLine($"foreach (var item in {obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class)}.Instance.EnumerateMajorRecords(obj, type, throwIfUnknown))");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine("yield return item;");
                    }
                }
                else
                {
                    var fgCount = fg.Count;
                    foreach (var baseClass in obj.BaseClassTrail())
                    {
                        if (await MajorRecordModule.HasMajorRecords(baseClass, includeBaseClass: true, includeSelf: true) != Case.No)
                        {
                            fg.AppendLine("foreach (var item in base.EnumerateMajorRecords<TMajor>(obj))");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("yield return item;");
                            }
                            break;
                        }
                    }

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

                        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(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(field, deepFg, accessor, getter, targetObj : deepRec.Key);
                                }
                            }

                            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 EnumerateMajorRecords({accessor}, 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(deepObj, subFg, accessor, getter, blackList : passedObjects);
                                    }
                                    if (!subFg.Empty)
                                    {
                                        fg.AppendLine($"case \"{interf.Key}\":");
                                        using (new BraceWrapper(fg))
                                        {
                                            fg.AppendLine($"if (!{obj.RegistrationName}.SetterType.IsAssignableFrom(obj.GetType())) yield break;");
                                            fg.AppendLines(subFg);
                                            fg.AppendLine("yield break;");
                                        }
                                        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();

            // 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 IEnumerable<TMajor> EnumerateMajorRecords<TMajor>"))
                    {
                        args.Add($"{baseClass.Interface(getter: getter)} obj");
                        args.Wheres.Add($"where TMajor : {nameof(IMajorRecordCommon)}{(getter ? "Getter" : null)}");
                    }
                    using (new BraceWrapper(fg))
                    {
                        using (var args = new ArgsWrapper(fg,
                                                          "EnumerateMajorRecords<TMajor>"))
                        {
                            args.Add($"({obj.Interface(getter: getter)})obj");
                        }
                    }
                    fg.AppendLine();
                }
            }
        }
Exemple #6
0
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            if (!maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class))
            {
                return;
            }
            fg.AppendLine($"public IEnumerable<{nameof(FormKey)}> GetLinkFormKeys({obj.Interface(getter: true)} obj)");
            using (new BraceWrapper(fg))
            {
                foreach (var baseClass in obj.BaseClassTrail())
                {
                    if (await HasLinks(baseClass, includeBaseClass: true) != LinkCase.No)
                    {
                        fg.AppendLine("foreach (var item in base.GetLinkFormKeys(obj))");
                        using (new BraceWrapper(fg))
                        {
                            fg.AppendLine("yield return item;");
                        }
                        break;
                    }
                }
                foreach (var field in obj.IterateFields())
                {
                    if (field is FormLinkType formLink)
                    {
                        if (field.HasBeenSet)
                        {
                            fg.AppendLine($"if (obj.{field.Name}.FormKey.TryGet(out var {field.Name}Key))");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine($"yield return {field.Name}Key;");
                            }
                        }
                        else if (formLink.FormIDType == FormLinkType.FormIDTypeEnum.Normal)
                        {
                            fg.AppendLine($"yield return obj.{field.Name}.FormKey;");
                        }
                    }
                    else if (field is LoquiType loqui)
                    {
                        LinkCase subLinkCase;
                        if (loqui.TargetObjectGeneration != null)
                        {
                            subLinkCase = await HasLinks(loqui, includeBaseClass : true);
                        }
                        else
                        {
                            subLinkCase = LinkCase.Maybe;
                        }
                        if (subLinkCase == LinkCase.No)
                        {
                            continue;
                        }
                        var doBrace = true;
                        var access  = $"obj.{field.Name}";
                        if (subLinkCase == LinkCase.Maybe)
                        {
                            fg.AppendLine($"if (obj.{field.Name} is {nameof(ILinkedFormKeyContainer)} {field.Name}linkCont)");
                            access = $"{field.Name}linkCont";
                        }
                        else if (loqui.HasBeenSet)
                        {
                            fg.AppendLine($"if (obj.{field.Name}.TryGet(out var {field.Name}Items))");
                            access = $"{field.Name}Items";
                        }
                        else
                        {
                            doBrace = false;
                        }
                        using (new BraceWrapper(fg, doIt: doBrace))
                        {
                            fg.AppendLine($"foreach (var item in {access}.{nameof(ILinkedFormKeyContainer.LinkFormKeys)})");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine($"yield return item;");
                            }
                        }
                    }
                    else if (field is ContainerType cont)
                    {
                        var access = $"obj.{field.Name}";
                        if (field.HasBeenSet)
                        {
                            access = $"{field.Name}Item";
                        }

                        FileGeneration subFg = new FileGeneration();
                        if (cont.SubTypeGeneration is LoquiType contLoqui &&
                            await HasLinks(contLoqui, includeBaseClass: true) != LinkCase.No)
                        {
                            var linktype = await HasLinks(contLoqui, includeBaseClass : true);

                            if (linktype != LinkCase.No)
                            {
                                switch (linktype)
                                {
                                case LinkCase.Yes:
                                    subFg.AppendLine($"foreach (var item in {access}.SelectMany(f => f.{nameof(ILinkedFormKeyContainer.LinkFormKeys)}))");
                                    break;

                                case LinkCase.Maybe:
                                    subFg.AppendLine($"foreach (var item in {access}.WhereCastable<{contLoqui.TypeName(getter: true)}, {nameof(ILinkedFormKeyContainer)}> ()");
                                    using (new DepthWrapper(subFg))
                                    {
                                        subFg.AppendLine($".SelectMany((f) => f.{nameof(ILinkedFormKeyContainer.LinkFormKeys)}))");
                                    }
                                    break;

                                default:
                                    throw new NotImplementedException();
                                }
                            }
                        }
                        else if (cont.SubTypeGeneration is FormLinkType formIDType &&
                                 formIDType.FormIDType == FormLinkType.FormIDTypeEnum.Normal)
                        {
                            subFg.AppendLine($"foreach (var item in {access}.Select(f => f.FormKey))");
                        }
Exemple #7
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();
                }
            }
        }
        private void GenerateRead(ObjectGeneration obj, FileGeneration fg)
        {
            var param = new XmlReadGenerationParameters()
            {
                Obj          = obj,
                Accessor     = "this",
                FG           = fg,
                Field        = null,
                Name         = "Root",
                XmlNodeName  = "root",
                XmlGen       = this,
                MaskAccessor = "mask"
            };

            if (!obj.Abstract)
            {
                fg.AppendLine($"public static {obj.ObjectName} CreateFromXML(XElement root)");
                using (new BraceWrapper(fg))
                {
                    fg.AppendLine($"var ret = new {obj.Name}();");
                    fg.AppendLine($"NoggXmlTranslation<{obj.Name}, {obj.GetErrorMaskItemString()}>.Instance.CopyIn(");
                    using (new DepthWrapper(fg))
                    {
                        fg.AppendLine($"root: root,");
                        fg.AppendLine($"item: ret,");
                        fg.AppendLine($"doMasks: false,");
                        fg.AppendLine($"mask: out {obj.GetErrorMaskItemString()} errorMask,");
                        fg.AppendLine($"cmds: null);");
                    }
                    fg.AppendLine("return ret;");
                }
                fg.AppendLine();

                fg.AppendLine($"public static {obj.ObjectName} CreateFromXML(XElement root, out {obj.GetErrorMaskItemString()} errorMask)");
                using (new BraceWrapper(fg))
                {
                    fg.AppendLine($"var ret = new {obj.Name}();");
                    fg.AppendLine($"NoggXmlTranslation<{obj.Name}, {obj.GetErrorMaskItemString()}>.Instance.CopyIn(");
                    using (new DepthWrapper(fg))
                    {
                        fg.AppendLine($"root: root,");
                        fg.AppendLine($"item: ret,");
                        fg.AppendLine($"doMasks: true,");
                        fg.AppendLine($"mask: out errorMask,");
                        fg.AppendLine($"cmds: null);");
                    }
                    fg.AppendLine("return ret;");
                }
                fg.AppendLine();
            }

            if (obj is StructGeneration)
            {
                return;
            }
            fg.AppendLine("public" + obj.FunctionOverride + "void CopyInFromXML(XElement root, NotifyingFireParameters? cmds = null)");
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"NoggXmlTranslation<{obj.Name}, {obj.GetErrorMaskItemString()}>.Instance.CopyIn(");
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($"root: root,");
                    fg.AppendLine($"item: this,");
                    fg.AppendLine($"doMasks: false,");
                    fg.AppendLine($"mask: out {obj.GetErrorMaskItemString()} errorMask,");
                    fg.AppendLine($"cmds: cmds);");
                }
            }
            fg.AppendLine();

            fg.AppendLine($"public virtual void CopyInFromXML(XElement root, out {obj.GetErrorMaskItemString()} errorMask, NotifyingFireParameters? cmds = null)");
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"NoggXmlTranslation<{obj.Name}, {obj.GetErrorMaskItemString()}>.Instance.CopyIn(");
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($"root: root,");
                    fg.AppendLine($"item: this,");
                    fg.AppendLine($"doMasks: true,");
                    fg.AppendLine($"mask: out errorMask,");
                    fg.AppendLine($"cmds: cmds);");
                }
            }
            fg.AppendLine();

            foreach (var baseClass in obj.BaseClassTrail())
            {
                fg.AppendLine("public override void CopyInFromXML(XElement root, out " + baseClass.GetErrorMaskItemString() + " errorMask, NotifyingFireParameters? cmds = null)");
                using (new BraceWrapper(fg))
                {
                    fg.AppendLine($"var ret = new {obj.GetErrorMaskItemString()}();");
                    fg.AppendLine("errorMask = ret;");
                    fg.AppendLine("CopyInFromXML_Internal(root, ret, cmds: cmds);");
                }
                fg.AppendLine();
            }
        }
        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();
                }
            }
        }
        protected override async Task GenerateWriteSnippet(ObjectGeneration obj, FileGeneration fg)
        {
            var data = obj.GetObjectData();

            if (obj.HasLoquiBaseObject)
            {
                var firstBase = obj.BaseClassTrail().FirstOrDefault();
                if (firstBase != null)
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"{TranslationWriteClass(firstBase)}.Instance.Write"))
                    {
                        args.AddPassArg($"item");
                        args.AddPassArg(WriterMemberName);
                    }
                }
            }

            foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.FalseAndInclude, nonIntegrated: true))
            {
                var fieldData = field.GetFieldData();
                if (field.Derivative && fieldData.Binary != BinaryGenerationType.Custom)
                {
                    continue;
                }
                switch (fieldData.Binary)
                {
                case BinaryGenerationType.Normal:
                    break;

                case BinaryGenerationType.NoGeneration:
                    continue;

                case BinaryGenerationType.Custom:
                    CustomLogic.GenerateWrite(
                        fg: fg,
                        obj: obj,
                        field: field,
                        writerAccessor: WriterMemberName);
                    continue;

                default:
                    throw new NotImplementedException();
                }
                if (!this.TryGetTypeGeneration(field.GetType(), out var generator))
                {
                    throw new ArgumentException("Unsupported type generator: " + field);
                }

                if (!generator.ShouldGenerateWrite(field))
                {
                    return;
                }
                if (fieldData.Binary == BinaryGenerationType.NoGeneration)
                {
                    return;
                }

                await generator.GenerateWrite(
                    fg : fg,
                    objGen : obj,
                    typeGen : field,
                    writerAccessor : WriterMemberName,
                    itemAccessor : Accessor.FromType(field, "item"),
                    translationAccessor : null,
                    errorMaskAccessor : null,
                    converterAccessor : null);
            }
        }
        protected override async Task GenerateCopyInSnippet(ObjectGeneration obj, FileGeneration fg, Accessor accessor)
        {
            if (obj.HasLoquiBaseObject && obj.BaseClassTrail().Any((b) => HasEmbeddedFields(b)))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"base.{CopyInFromPrefix}{ModuleNickname}"))
                {
                    args.AddPassArg("item");
                    args.AddPassArg(ReaderMemberName);
                }
            }
            int breakIndex = 0;

            foreach (var field in obj.IterateFields(
                         nonIntegrated: true,
                         expandSets: SetMarkerType.ExpandSets.False))
            {
                if (field is SetMarkerType)
                {
                    continue;
                }
                if (field is CustomLogic logic && logic.IsRecordType)
                {
                    continue;
                }
                var fieldData = field.GetFieldData();
                if (fieldData.HasTrigger)
                {
                    continue;
                }
                if (fieldData.Binary == BinaryGenerationType.NoGeneration)
                {
                    continue;
                }
                if (field.Derivative && fieldData.Binary != BinaryGenerationType.Custom)
                {
                    continue;
                }
                if (!field.Enabled)
                {
                    continue;
                }
                if (!this.TryGetTypeGeneration(field.GetType(), out var generator))
                {
                    if (!field.IntegrateField)
                    {
                        continue;
                    }
                    throw new ArgumentException("Unsupported type generator: " + field);
                }
                if (field.Nullable)
                {
                    fg.AppendLine($"if (frame.Complete) return;");
                }

                if (field is BreakType)
                {
                    fg.AppendLine("if (frame.Complete)");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine($"item.{VersioningModule.VersioningFieldName} |= {obj.Name}.{VersioningModule.VersioningEnumName}.Break{breakIndex++};");
                        fg.AppendLine("return;");
                    }
                    continue;
                }
                await GenerateFillSnippet(obj, fg, field, generator, "frame");
            }
        }