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(); } }
async Task ApplyIterationLines( TypeGeneration field, FileGeneration fieldGen, Accessor accessor, bool getter, ObjectGeneration targetObj = null, HashSet <ObjectGeneration> blackList = null) { if (field is GroupType group) { if (blackList?.Contains(group.GetGroupTarget()) ?? false) { return; } fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.EnumerateMajorRecords(type, throwIfUnknown: throwIfUnknown))"); 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 ? $"{targetObj?.ObjectName}{loqui.Name}item" : $"{accessor}.{loqui.Name}"; if (loqui.TargetObjectGeneration.GetObjectType() == ObjectType.Group) { // List groups fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.EnumerateMajorRecords(type, throwIfUnknown: throwIfUnknown))"); using (new BraceWrapper(fieldGen)) { fieldGen.AppendLine("yield return item;"); } return; } var subFg = new FileGeneration(); await LoquiTypeHandler(subFg, fieldAccessor, loqui, generic : "TMajor", checkType : false, targetObj : targetObj); 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 { 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, $"subItem", contLoqui, generic : "TMajor", checkType : true); } break; case Case.Maybe: fieldGen.AppendLine($"foreach (var subItem in {accessor}.{field.Name}{(field.Nullable ? ".EmptyIfNull()" : null)}.Where(i => i.GetType() == type))"); using (new BraceWrapper(fieldGen)) { await LoquiTypeHandler(fieldGen, $"subItem", contLoqui, generic : "TMajor", checkType : true); } break; case Case.No: default: break; } } } } 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($"var assignable = type.IsAssignableFrom(typeof({dictLoqui.GenericDef.Name}));"); fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.Items)"); using (new BraceWrapper(fieldGen)) { fieldGen.AppendLine($"if (assignable)"); using (new BraceWrapper(fieldGen)) { fieldGen.AppendLine($"yield return item;"); } fieldGen.AppendLine($"foreach (var subItem in item.EnumerateMajorRecords(type, throwIfUnknown: false))"); using (new BraceWrapper(fieldGen)) { fieldGen.AppendLine($"yield return subItem;"); } } } 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)) { await LoquiTypeHandler(fieldGen, $"subItem", dictLoqui, generic : "TMajor", checkType : false); } break; case Case.Maybe: fieldGen.AppendLine($"foreach (var subItem in {accessor}.{field.Name}.Items.WhereCastable<{dictLoqui.TypeName(getter: false)}, {(getter ? nameof(IMajorRecordGetterEnumerable) : nameof(IMajorRecordEnumerable))}>())"); using (new BraceWrapper(fieldGen)) { await LoquiTypeHandler(fieldGen, $"subItem", dictLoqui, generic : "TMajor", checkType : false); } break; case Case.No: default: break; } } } } }
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; } } } } }