Exemplo n.º 1
0
        async Task ApplyIterationLines(
            ObjectGeneration obj,
            TypeGeneration field,
            FileGeneration fieldGen,
            Accessor accessor,
            bool getter,
            bool hasTarget = false,
            HashSet <ObjectGeneration> blackList = null,
            bool includeSelf = true)
        {
            if (field is GroupType group)
            {
                if (blackList?.Contains(group.GetGroupTarget()) ?? false)
                {
                    return;
                }
                if (!hasTarget)
                {
                    fieldGen.AppendLine($"foreach (var item in obj.{field.Name}.EnumerateMajorRecords(type, throwIfUnknown: throwIfUnknown))");
                    using (new BraceWrapper(fieldGen))
                    {
                        using (var args = new ArgsWrapper(fieldGen,
                                                          $"yield return new ModContext<{obj.Interface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>"))
                        {
                            args.Add("modKey: obj.ModKey");
                            args.Add("record: item");
                            args.Add($"getter: (m, r) => m.{group.Name}.GetOrAddAsOverride(({group.GetGroupTarget().Interface(getter: true, internalInterface: true)})r)");
                        }
                    }
                }
                else
                {
                    fieldGen.AppendLine($"foreach (var groupItem in obj.{field.Name})");
                    using (new BraceWrapper(fieldGen))
                    {
                        fieldGen.AppendLine($"foreach (var item in {group.GetGroupTarget().CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class)}.Instance.EnumerateMajorRecordContexts(groupItem, linkCache, type, {(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}, {(obj.GetObjectType() == ObjectType.Mod ? "parent: null" : "curContext")}, throwIfUnknown: throwIfUnknown, getter: (m, r) => m.{field.Name}.GetOrAddAsOverride(linkCache.Resolve<{group.GetGroupTarget().Interface(getter: true, internalInterface: true)}>(r.FormKey))))");

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

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

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

                        case Case.Maybe:
                            throw new NotImplementedException();

                        case Case.No:
                        default:
                            break;
                        }
                    }
                }
            }
            else if (field is DictType dict)
            {
                throw new NotImplementedException();
            }
        }
        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;
                        }
                    }
                }
            }
        }