private async Task GenerateForRecord(ObjectGeneration obj, FileGeneration fg) { if (!obj.IsTopClass) { return; } using (var args = new FunctionWrapper(fg, $"public{obj.FunctionOverride()}async Task WriteToXmlFolder")) { args.Add("DirectoryPath dir"); args.Add("string name"); args.Add("XElement node"); args.Add("int counter"); args.Add($"ErrorMaskBuilder? errorMask"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, "this.WriteToXml")) { args.Add("node: node"); args.Add("errorMask: errorMask"); args.Add("translationMask: null"); } } }
private void GenerateCustomBinaryEndCreatePartial(ObjectGeneration obj, FileGeneration fg) { var data = obj.GetObjectData(); if (data.CustomBinaryEnd == CustomEnd.Off) { return; } if (data.CustomBinaryEnd == CustomEnd.Normal) { using (var args = new ArgsWrapper(fg, $"public static partial void CustomBinaryEndImport")) { args.Add($"{ReaderClass} {ReaderMemberName}"); args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj"); } using (var args = new FunctionWrapper(fg, $"public static void CustomBinaryEndImportPublic")) { args.Add($"{ReaderClass} {ReaderMemberName}"); args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"CustomBinaryEndImport")) { args.AddPassArg(ReaderMemberName); args.AddPassArg($"obj"); } } } }
public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg) { if (!await obj.IsMajorRecord()) { return; } if (!obj.IsTopClass) { return; } using (var args = new FunctionWrapper(fg, $"public static {nameof(IMajorRecordCommon)} {nameof(IDuplicatable.Duplicate)}")) { //ToDo // Modify to getter interface after copy is refactored args.Add($"this {obj.ObjectName} item"); args.Add("Func<FormKey> getNextFormKey"); args.Add($"IList<({nameof(IMajorRecordCommon)} Record, FormKey OriginalFormKey)>? duplicatedRecords = null"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return {obj.CommonClassInstance("item", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.{nameof(IDuplicatable.Duplicate)}")) { args.AddPassArg("item"); args.AddPassArg("getNextFormKey"); args.AddPassArg("duplicatedRecords"); } } }
public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg) { await base.GenerateInCommonMixin(obj, fg); if (!await obj.IsMajorRecord()) { return; } using (var args = new FunctionWrapper(fg, $"public static {obj.ObjectName} Duplicate{obj.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter)}")) { args.Wheres.AddRange(obj.GenericTypeMaskWheres(LoquiInterfaceType.IGetter, MaskType.Normal, MaskType.NormalGetter)); args.Add($"this {obj.Interface(obj.GetGenericTypes(MaskType.NormalGetter), getter: true, internalInterface: true)} item"); args.Add($"{nameof(FormKey)} formKey"); args.Add($"{obj.Mask(MaskType.Translation)}? copyMask = null"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return {obj.CommonClassInstance("item", LoquiInterfaceType.IGetter, CommonGenerics.Functions, MaskType.NormalGetter)}.Duplicate{obj.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter, MaskType.Translation)}")) { args.AddPassArg("item"); args.AddPassArg("formKey"); args.Add("copyMask: copyMask?.GetCrystal()"); } } fg.AppendLine(); }
public static void GenerateWritePartialMethods( FileGeneration fg, ObjectGeneration obj, TypeGeneration field, bool isAsync) { using (var args = new FunctionWrapper(fg, $"public static partial void WriteBinary{field.Name}Custom{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, defs: obj.Generics)); args.SemiColon = true; args.Add($"{nameof(MutagenWriter)} writer"); args.Add($"{obj.Interface(getter: true, internalInterface: true)} item"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static void WriteBinary{field.Name}{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, defs: obj.Generics)); args.Add($"{nameof(MutagenWriter)} writer"); args.Add($"{obj.Interface(getter: true, internalInterface: true)} item"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"WriteBinary{field.Name}Custom")) { args.Add("writer: writer"); args.Add("item: item"); } } fg.AppendLine(); }
public static void GenerateCreatePartialMethods( FileGeneration fg, ObjectGeneration obj, TypeGeneration field, bool isAsync, bool useReturnValue) { var fieldData = field.GetFieldData(); var returningParseResult = useReturnValue && fieldData.HasTrigger; if (!isAsync) { using (var args = new FunctionWrapper(fg, $"public static partial {(returningParseResult ? nameof(ParseResult) : "void")} FillBinary{field.Name}Custom") { SemiColon = true }) { args.Add($"{nameof(MutagenFrame)} frame"); args.Add($"{obj.Interface(getter: false, internalInterface: true)} item"); if (returningParseResult && obj.GetObjectType() == ObjectType.Subrecord) { args.Add($"{nameof(PreviousParse)} lastParsed"); } } fg.AppendLine(); } }
private void GenerateGetGroup(ObjectGeneration obj, FileGeneration fg) { using (var args = new FunctionWrapper(fg, "public object GetGroup")) { args.Add($"{obj.Interface(getter: true)} obj"); args.Add("Type type"); } using (new BraceWrapper(fg)) { fg.AppendLine("switch (type.Name)"); using (new BraceWrapper(fg)) { foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration?.GetObjectData().ObjectType != ObjectType.Group) { continue; } if (!loqui.TryGetSpecificationAsObject("T", out var subObj)) { throw new ArgumentException(); } fg.AppendLine($"case \"{subObj.Name}\":"); fg.AppendLine($"case \"{subObj.Interface(getter: true)}\":"); fg.AppendLine($"case \"{subObj.Interface(getter: false)}\":"); if (subObj.HasInternalGetInterface) { fg.AppendLine($"case \"{subObj.Interface(getter: true, internalInterface: true)}\":"); } if (subObj.HasInternalSetInterface) { fg.AppendLine($"case \"{subObj.Interface(getter: false, internalInterface: true)}\":"); } using (new DepthWrapper(fg)) { if (loqui.TargetObjectGeneration.Name.EndsWith("ListGroup")) { fg.AppendLine($"return obj.{field.Name}.Records;"); } else { fg.AppendLine($"return obj.{field.Name};"); } } } fg.AppendLine("default:"); using (new DepthWrapper(fg)) { fg.AppendLine("throw new ArgumentException($\"Unknown major record type: {type}\");"); } } } fg.AppendLine(); }
public override async Task GenerateInClass(ObjectGeneration obj, FileGeneration fg) { await base.GenerateInClass(obj, fg); if (WantsTryCreateFromBinary(obj)) { using (var args = new FunctionWrapper(fg, "public static bool TryCreateFromBinary")) { foreach (var(API, Public) in this.MainAPI.ReaderAPI.IterateAPI( obj, TranslationDirection.Reader, new APILine(OutItemKey, $"out {obj.ObjectName} item"))) { if (Public) { args.Add(API.Result); } } } using (new BraceWrapper(fg)) { fg.AppendLine($"var startPos = {ReaderMemberName}.Position;"); using (var args = new ArgsWrapper(fg, $"item = CreateFromBinary")) { args.Add(this.MainAPI.PassArgs(obj, TranslationDirection.Reader)); } fg.AppendLine($"return startPos != {ReaderMemberName}.Position;"); } } await GenerateBinaryOverlayCreates(obj, fg); }
public override async Task FinalizeGeneration(ProtocolGeneration proto) { await base.FinalizeGeneration(proto); if (proto.Protocol.Namespace != "All") { return; } await Task.WhenAll(proto.Gen.Protocols.Values.SelectMany(p => p.ObjectGenerationsByID.Values.Select(o => o.LoadingCompleteTask.Task))); FileGeneration fg = new FileGeneration(); foreach (var modObj in mods) { fg.AppendLine($"using Mutagen.Bethesda.{modObj.ProtoGen.Protocol.Namespace};"); } fg.AppendLine($"using Mutagen.Bethesda.Environments;"); fg.AppendLine($"using Mutagen.Bethesda.Plugins.Cache;"); fg.AppendLine(); using (new NamespaceWrapper(fg, "Mutagen.Bethesda", fileScoped: false)) { using (var c = new ClassWrapper(fg, "GameEnvironmentMixIn")) { c.Static = true; } using (new BraceWrapper(fg)) { foreach (var modObj in mods) { var relStr = modObj.GetObjectData().HasMultipleReleases ? $"{modObj.GetObjectData().GameCategory}Release gameRelease" : string.Empty; var retType = $"IGameEnvironmentState<I{modObj.Name}, I{modObj.Name}Getter>"; using (var args = new FunctionWrapper(fg, $"public static {retType} {modObj.ProtoGen.Protocol.Namespace}")) { args.Add($"this {nameof(GameEnvironment)} env"); if (modObj.GetObjectData().HasMultipleReleases) { args.Add(modObj.GetObjectData().HasMultipleReleases ? $"{modObj.GetObjectData().GameCategory}Release gameRelease" : string.Empty); } args.Add($"{nameof(LinkCachePreferences)}? linkCachePrefs = null"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return env.Construct<I{modObj.Name}, I{modObj.Name}Getter>({(modObj.GetObjectData().HasMultipleReleases ? "gameRelease.ToGameRelease()" : $"GameRelease.{modObj.ProtoGen.Protocol.Namespace}")}, linkCachePrefs);");
public static void GenerateCreatePartialMethods( FileGeneration fg, ObjectGeneration obj, TypeGeneration field, bool isAsync) { if (!isAsync) { using (var args = new FunctionWrapper(fg, $"public static partial void FillBinary{field.Name}Custom") { SemiColon = true }) { args.Add($"{nameof(MutagenFrame)} frame"); args.Add($"{obj.Interface(getter: false, internalInterface: true)} item"); } fg.AppendLine(); } }
public static void GenerateConverterMember(FileGeneration fg, ObjectGeneration objGen, RecordTypeConverter recordTypeConverter, string nickName) { if (recordTypeConverter == null || recordTypeConverter.FromConversions.Count == 0) { return; } using (var args = new ArgsWrapper(fg, $"public static RecordTypeConverter {nickName}Converter = new RecordTypeConverter")) { foreach (var conv in recordTypeConverter.FromConversions) { args.Add((gen) => { using (var args2 = new FunctionWrapper(gen, "new KeyValuePair<RecordType, RecordType>")) { args2.Add($"new RecordType(\"{conv.Key.Type}\")"); args2.Add($"new RecordType(\"{conv.Value.Type}\")"); } }); } } }
public override void GenerateCopyIn( FileGeneration fg, ObjectGeneration objGen, TypeGeneration typeGen, Accessor frameAccessor, Accessor itemAccessor, Accessor errorMaskAccessor, Accessor translationMaskAccessor) { FormLinkType linkType = typeGen as FormLinkType; MaskGenerationUtility.WrapErrorFieldIndexPush(fg, () => { if (itemAccessor.IsAssignment) { using (var args = new ArgsWrapper(fg, $"{itemAccessor} = {(linkType.FormIDType == FormLinkType.FormIDTypeEnum.Normal ? "FormKey" : "RecordType")}XmlTranslation.Instance.Parse")) { args.AddPassArg("node"); args.AddPassArg("errorMask"); } } else { using (var args = new FunctionWrapper(fg, itemAccessor.Assign($"new {linkType.DirectTypeName(getter: false)}"))) { args.Add(subFg => { using (var subArgs = new FunctionWrapper(subFg, $"FormKeyXmlTranslation.Instance.Parse")) { subArgs.AddPassArg("node"); subArgs.AddPassArg("errorMask"); } }); } } }, indexAccessor: typeGen.HasIndex?typeGen.IndexEnumInt: null, errorMaskAccessor: errorMaskAccessor, doIt: typeGen.HasIndex); }
public override async Task GenerateInClass(ObjectGeneration obj, FileGeneration fg) { if (obj.GetObjectData().ObjectType != ObjectType.Mod) { return; } var objData = obj.GetObjectData(); // Game release member if (objData.GameReleaseOptions != null) { fg.AppendLine($"public {ReleaseEnumName(obj)} {ReleaseEnumName(obj)} {{ get; }}"); fg.AppendLine($"public override {nameof(GameRelease)} GameRelease => {ReleaseEnumName(obj)}.ToGameRelease();"); } else { fg.AppendLine($"public override {nameof(GameRelease)} GameRelease => {nameof(GameRelease)}.{obj.GetObjectData().GameCategory};"); } // Interfaces fg.AppendLine($"IReadOnlyCache<T, {nameof(FormKey)}> {nameof(IModGetter)}.{nameof(IModGetter.GetTopLevelGroupGetter)}<T>() => this.{nameof(IModGetter.GetTopLevelGroupGetter)}<T>();"); fg.AppendLine($"ICache<T, {nameof(FormKey)}> {nameof(IMod)}.{nameof(IMod.GetGroup)}<T>() => this.GetGroup<T>();"); fg.AppendLine($"void IModGetter.WriteToBinary(string path, {nameof(BinaryWriteParameters)}? param) => this.WriteToBinary(path, importMask: null, param: param);"); fg.AppendLine($"void IModGetter.WriteToBinaryParallel(string path, {nameof(BinaryWriteParameters)}? param) => this.WriteToBinaryParallel(path, param);"); fg.AppendLine($"IMask<bool> {nameof(IEqualsMask)}.{nameof(IEqualsMask.GetEqualsMask)}(object rhs, EqualsMaskHelper.Include include = EqualsMaskHelper.Include.OnlyFailures) => {obj.MixInClassName}.GetEqualsMask(this, ({obj.Interface(getter: true, internalInterface: true)})rhs, include);"); // Localization enabled member if (obj.GetObjectData().UsesStringFiles) { fg.AppendLine($"public override bool CanUseLocalization => true;"); fg.AppendLine($"public override bool UsingLocalization"); using (new BraceWrapper(fg)) { fg.AppendLine($"get => this.ModHeader.Flags.HasFlag({obj.GetObjectData().GameCategory}ModHeader.HeaderFlag.Localized);"); fg.AppendLine($"set => this.ModHeader.Flags.SetFlag({obj.GetObjectData().GameCategory}ModHeader.HeaderFlag.Localized, value);"); } } else { fg.AppendLine($"public override bool CanUseLocalization => false;"); fg.AppendLine($"public override bool UsingLocalization"); using (new BraceWrapper(fg)) { fg.AppendLine("get => false;"); fg.AppendLine("set => throw new ArgumentException(\"Tried to set localization flag on unsupported mod type\");"); } } // Master references member fg.AppendLine($"[DebuggerBrowsable(DebuggerBrowsableState.Never)]"); fg.AppendLine($"IList<MasterReference> IMod.MasterReferences => this.ModHeader.MasterReferences;"); fg.AppendLine($"[DebuggerBrowsable(DebuggerBrowsableState.Never)]"); fg.AppendLine($"IReadOnlyList<IMasterReferenceGetter> IModGetter.MasterReferences => this.ModHeader.MasterReferences;"); // NextObjectID member fg.AppendLine($"[DebuggerBrowsable(DebuggerBrowsableState.Never)]"); fg.AppendLine($"uint IMod.NextFormID"); using (new BraceWrapper(fg)) { fg.AppendLine($"get => this.ModHeader.Stats.NextFormID;"); fg.AppendLine($"set => this.ModHeader.Stats.NextFormID = value;"); } fg.AppendLine($"[DebuggerBrowsable(DebuggerBrowsableState.Never)]"); fg.AppendLine($"uint IModGetter.NextFormID => this.ModHeader.Stats.NextFormID;"); using (var args = new FunctionWrapper(fg, $"public {obj.Name}")) { args.Add($"{nameof(ModKey)} modKey"); if (objData.GameReleaseOptions != null) { args.Add($"{ReleaseEnumName(obj)} release"); } } using (new DepthWrapper(fg)) { fg.AppendLine(": base(modKey)"); } using (new BraceWrapper(fg)) { fg.AppendLine("this.ModHeader.Stats.NextFormID = GetDefaultInitialNextFormID();"); if (objData.GameReleaseOptions != null) { fg.AppendLine($"this.{ReleaseEnumName(obj)} = release;"); } await obj.GenerateInitializer(fg); fg.AppendLine($"CustomCtor();"); } using (var args = new FunctionWrapper(fg, "public void AddRecords")) { args.Add($"{obj.Name} rhsMod"); args.Add($"GroupMask? mask = null"); } using (new BraceWrapper(fg)) { foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group) { continue; } fg.AppendLine($"if (mask?.{field.Name} ?? true)"); using (new BraceWrapper(fg)) { if (loqui.TargetObjectGeneration.Name == "Group") { fg.AppendLine($"this.{field.Name}.RecordCache.Set(rhsMod.{field.Name}.RecordCache.Items);"); } else { fg.AppendLine($"if (rhsMod.{field.Name}.Records.Count > 0)"); using (new BraceWrapper(fg)) { fg.AppendLine("throw new NotImplementedException(\"Cell additions need implementing\");"); } } } } } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public Dictionary<FormKey, {nameof(IMajorRecordCommon)}> CopyInDuplicate")) { args.Add($"{obj.Name} rhs"); args.Add($"GroupMask? mask = null"); } using (new BraceWrapper(fg)) { fg.AppendLine($"var duppedRecords = new List<({nameof(IMajorRecordCommon)} Record, FormKey OriginalFormKey)>();"); foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group) { continue; } var dictGroup = loqui.TargetObjectGeneration.Name == "Group"; fg.AppendLine($"if (mask?.{field.Name} ?? true)"); using (new BraceWrapper(fg)) { fg.AppendLine($"this.{field.Name}.{(dictGroup ? "RecordCache" : "Records")}.{(dictGroup ? "Set" : "AddRange")}("); using (new DepthWrapper(fg)) { fg.AppendLine($"rhs.{field.Name}.Records"); using (new DepthWrapper(fg)) { fg.AppendLine($".Select(i => i.Duplicate(this.GetNextFormKey, duppedRecords))"); fg.AppendLine($".Cast<{loqui.GetGroupTarget().Name}>());"); } } } } fg.AppendLine($"var router = new Dictionary<FormKey, {nameof(IMajorRecordCommon)}>();"); fg.AppendLine($"router.Set(duppedRecords.Select(dup => new KeyValuePair<FormKey, {nameof(IMajorRecordCommon)}>(dup.OriginalFormKey, dup.Record)));"); fg.AppendLine($"var mapping = new Dictionary<FormKey, FormKey>();"); fg.AppendLine($"var package = this.{nameof(ILinkCacheExt.ToImmutableLinkCache)}();"); fg.AppendLine("foreach (var rec in router.Values)"); using (new BraceWrapper(fg)) { fg.AppendLine($"rec.RemapLinks(mapping);"); } fg.AppendLine($"return router;"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, "public override void SyncRecordCount")) { } using (new BraceWrapper(fg)) { fg.AppendLine("this.ModHeader.Stats.NumRecords = GetRecordCount();"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, "public uint GetRecordCount")) { } using (new BraceWrapper(fg)) { fg.AppendLine("uint count = (uint)this.EnumerateMajorRecords().Count();"); foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group) { continue; } if (loqui.TargetObjectGeneration.Name == "ListGroup") { fg.AppendLine($"count += {field.Name}.Records.Count > 0 ? 1 : default(uint);"); } else { fg.AppendLine($"count += {field.Name}.RecordCache.Count > 0 ? 1 : default(uint);"); } } fg.AppendLine("GetCustomRecordCount((customCount) => count += customCount);"); fg.AppendLine("return count;"); } fg.AppendLine(); fg.AppendLine("partial void GetCustomRecordCount(Action<uint> setter);"); fg.AppendLine(); await base.GenerateInClass(obj, fg); }
public override async Task GenerateInVoid(ObjectGeneration obj, FileGeneration fg) { if (obj.GetObjectType() != ObjectType.Mod) { return; } using (new NamespaceWrapper(fg, obj.Namespace)) { var objData = obj.GetObjectData(); fg.AppendLine("public class GroupMask"); using (new BraceWrapper(fg)) { foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration == null) { continue; } if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group) { continue; } fg.AppendLine($"public bool {loqui.Name};"); } fg.AppendLine("public GroupMask()"); using (new BraceWrapper(fg)) { } fg.AppendLine("public GroupMask(bool defaultValue)"); using (new BraceWrapper(fg)) { foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration == null) { continue; } if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group) { continue; } fg.AppendLine($"{loqui.Name} = defaultValue;"); } } } fg.AppendLine(); fg.AppendLine($"public interface I{obj.Name}DisposableGetter : {obj.Interface(getter: true, internalInterface: true)}, IModDisposeGetter"); using (new BraceWrapper(fg)) { } fg.AppendLine(); if (objData.GameReleaseOptions != null) { using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Different game release versions a {ModName(obj)} mod can have"); } fg.AppendLine($"public enum {ReleaseEnumName(obj)}"); using (new BraceWrapper(fg)) { using (var comma = new CommaWrapper(fg)) { foreach (var opt in objData.GameReleaseOptions) { comma.Add($"{opt} = {(int)opt}"); } } } fg.AppendLine(); using (var c = new ClassWrapper(fg, $"{ReleaseEnumName(obj)}Ext")) { c.Static = true; } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"public static {nameof(GameRelease)} ToGameRelease")) { args.Add($"this {ReleaseEnumName(obj)} release"); } using (new BraceWrapper(fg)) { fg.AppendLine("return release switch"); using (new BraceWrapper(fg) { AppendSemicolon = true }) { using (var comma = new CommaWrapper(fg)) { foreach (var item in objData.GameReleaseOptions) { comma.Add($"{ReleaseEnumName(obj)}.{item} => {nameof(GameRelease)}.{item}"); } comma.Add("_ => throw new ArgumentException()"); } } } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static {ReleaseEnumName(obj)} To{ReleaseEnumName(obj)}")) { args.Add($"this {nameof(GameRelease)} release"); } using (new BraceWrapper(fg)) { fg.AppendLine("return release switch"); using (new BraceWrapper(fg) { AppendSemicolon = true }) { using (var comma = new CommaWrapper(fg)) { foreach (var item in objData.GameReleaseOptions) { comma.Add($"{nameof(GameRelease)}.{item} => {ReleaseEnumName(obj)}.{item}"); } comma.Add("_ => throw new ArgumentException()"); } } } } } } }
public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg) { await base.GenerateInCommonMixin(obj, fg); if (obj.GetObjectType() != ObjectType.Mod) { return; } using (var args = new FunctionWrapper(fg, $"public static IReadOnlyCache<T, FormKey> {nameof(IModGetter.GetTopLevelGroupGetter)}<T>")) { args.Wheres.Add($"where T : {nameof(IMajorRecordCommonGetter)}"); args.Add($"this {obj.Interface(getter: true)} obj"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return (IReadOnlyCache<T, FormKey>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup<T>")) { args.AddPassArg("obj"); } } fg.AppendLine(); using (var args = new FunctionWrapper(fg, "public static ICache<T, FormKey> GetGroup<T>")) { args.Wheres.Add($"where T : {nameof(IMajorRecordCommon)}"); args.Add($"this {obj.Interface(getter: false)} obj"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return (ICache<T, FormKey>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup<T>")) { args.AddPassArg("obj"); } } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static void WriteToBinaryParallel")) { args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item"); args.Add($"Stream stream"); args.Add($"{nameof(BinaryWriteParameters)}? param = null"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel")) { args.AddPassArg("item"); args.AddPassArg("stream"); args.Add($"param: param ?? {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)}"); args.Add("modKey: item.ModKey"); } } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static void WriteToBinaryParallel")) { args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item"); args.Add($"string path"); args.Add($"{nameof(BinaryWriteParameters)}? param = null"); } using (new BraceWrapper(fg)) { fg.AppendLine($"param ??= {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)};"); using (var args = new ArgsWrapper(fg, $"var modKey = param.{nameof(BinaryWriteParameters.RunMasterMatch)}")) { args.Add("mod: item"); args.AddPassArg("path"); } if (obj.GetObjectData().UsesStringFiles) { fg.AppendLine("bool disposeStrings = param.StringsWriter == null;"); fg.AppendLine("param.StringsWriter ??= EnumExt.HasFlag((int)item.ModHeader.Flags, (int)ModHeaderCommonFlag.Localized) ? new StringsWriter(modKey, Path.Combine(Path.GetDirectoryName(path)!, \"Strings\")) : null;"); } fg.AppendLine("using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write))"); using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel")) { args.AddPassArg("item"); args.AddPassArg("stream"); args.Add($"param: param"); args.AddPassArg("modKey"); } } if (obj.GetObjectData().UsesStringFiles) { fg.AppendLine("if (disposeStrings)"); using (new BraceWrapper(fg)) { fg.AppendLine("param.StringsWriter?.Dispose();"); } } } fg.AppendLine(); }
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(); } } }
public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg) { if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } var needsCatch = obj.GetObjectType() == ObjectType.Mod; string catchLine = needsCatch ? ".Catch(e => throw RecordException.Enrich(e, obj.ModKey))" : string.Empty; string enderSemi = needsCatch ? string.Empty : ";"; fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics)); args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords", suffixLine: catchLine)) { args.AddPassArg("obj"); } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<TMajor> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics)); args.Wheres.Add($"where TMajor : class, IMajorRecordCommonGetter"); args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj"); args.Add($"bool throwIfUnknown = true"); } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords")) { args.AddPassArg("obj"); args.Add("type: typeof(TMajor)"); args.AddPassArg("throwIfUnknown"); } using (new DepthWrapper(fg)) { fg.AppendLine($".Select(m => (TMajor)m){enderSemi}"); if (needsCatch) { fg.AppendLine($"{catchLine};"); } } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}")) { args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj"); args.Add($"Type type"); args.Add($"bool throwIfUnknown = true"); args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics)); } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords")) { args.AddPassArg("obj"); args.AddPassArg("type"); args.AddPassArg("throwIfUnknown"); } using (new DepthWrapper(fg)) { fg.AppendLine($".Select(m => ({nameof(IMajorRecordCommonGetter)})m){enderSemi}"); if (needsCatch) { fg.AppendLine($"{catchLine};"); } } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<{nameof(IMajorRecordCommon)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumerateMajorRecords", suffixLine: catchLine)) { args.AddPassArg("obj"); } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<TMajor> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Wheres.Add($"where TMajor : class, IMajorRecordCommon"); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumerateMajorRecords")) { args.AddPassArg("obj"); args.Add("type: typeof(TMajor)"); args.Add("throwIfUnknown: true"); } using (new DepthWrapper(fg)) { fg.AppendLine($".Select(m => (TMajor)m){enderSemi}"); if (needsCatch) { fg.AppendLine($"{catchLine};"); } } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<{nameof(IMajorRecordCommon)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}")) { args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"Type? type"); args.Add($"bool throwIfUnknown = true"); args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumeratePotentiallyTypedMajorRecords")) { args.AddPassArg("obj"); args.AddPassArg("type"); args.AddPassArg("throwIfUnknown"); } using (new DepthWrapper(fg)) { fg.AppendLine($".Select(m => ({nameof(IMajorRecordCommon)})m){enderSemi}"); if (needsCatch) { fg.AppendLine($"{catchLine};"); } } } fg.AppendLine(); }
public override async Task FinalizeGeneration(ProtocolGeneration proto) { if (proto.Protocol.Namespace.Equals("All") || proto.Protocol.Namespace.Equals("Bethesda")) { return; } FileGeneration fg = new FileGeneration(); fg.AppendLine("using System.Collections.Generic;"); fg.AppendLine("using Mutagen.Bethesda.Plugins.Order;"); fg.AppendLine("using Mutagen.Bethesda.Cache.Implementations;"); fg.AppendLine(); using (var n = new NamespaceWrapper(fg, proto.DefaultNamespace)) { var setterName = $"I{proto.Protocol.Namespace}Mod"; var getterName = $"I{proto.Protocol.Namespace}ModGetter"; var generic = $"<{setterName}, {getterName}>"; using (var c = new ClassWrapper(fg, "LinkCacheMixIns")) { c.Static = true; } using (new BraceWrapper(fg)) { using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a Link Cache using a single mod as its link target. <br/>"); comment.Summary.AppendLine($"Modification of the target Mod is not safe. Internal caches can become incorrect if "); comment.Summary.AppendLine($"modifications occur on content already cached."); comment.Parameters.GetOrAdd("mod").AppendLine("Mod to construct the package relative to"); comment.Return.AppendLine($"LinkPackage attached to given mod"); } using (var args = new FunctionWrapper(fg, $"public static ImmutableModLinkCache{generic} ToImmutableLinkCache")) { args.Add($"this {getterName} mod"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return mod.ToImmutableLinkCache{generic}();"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a Link Cache using a single mod as its link target. Mod is allowed to be modified afterwards, but"); comment.Summary.AppendLine($"this comes at a performance cost of not allowing much caching to be done. If the mod is not expected to"); comment.Summary.AppendLine($"be modified afterwards, use ImmutableModLinkCache instead.<br/>"); comment.Parameters.GetOrAdd("mod").AppendLine("Mod to construct the package relative to"); comment.Return.AppendLine($"LinkPackage attached to given mod"); } using (var args = new FunctionWrapper(fg, $"public static MutableModLinkCache{generic} ToMutableLinkCache")) { args.Add($"this {getterName} mod"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return mod.ToMutableLinkCache{generic}();"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a new linking package relative to a load order.<br/>"); comment.Summary.AppendLine($"Will resolve links to the highest overriding mod containing the record being sought. <br/>"); comment.Summary.AppendLine($"Modification of the target LoadOrder, or Mods on the LoadOrder is not safe. Internal caches can become"); comment.Summary.AppendLine($"incorrect if modifications occur on content already cached."); comment.Parameters.GetOrAdd("loadOrder").AppendLine("LoadOrder to construct the package relative to"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static ImmutableLoadOrderLinkCache{generic} ToImmutableLinkCache")) { args.Add($"this ILoadOrderGetter<{getterName}> loadOrder"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return loadOrder.ToImmutableLinkCache{generic}();"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a new linking package relative to a load order.<br/>"); comment.Summary.AppendLine($"Will resolve links to the highest overriding mod containing the record being sought. <br/>"); comment.Summary.AppendLine($"Modification of the target LoadOrder, or Mods on the LoadOrder is not safe. Internal caches can become"); comment.Summary.AppendLine($"incorrect if modifications occur on content already cached."); comment.Parameters.GetOrAdd("loadOrder").AppendLine("LoadOrder to construct the package relative to"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static ImmutableLoadOrderLinkCache{generic} ToImmutableLinkCache")) { args.Add($"this ILoadOrderGetter<IModListingGetter<{getterName}>> loadOrder"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return loadOrder.ToImmutableLinkCache{generic}();"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a new linking package relative to a load order.<br/>"); comment.Summary.AppendLine($"Will resolve links to the highest overriding mod containing the record being sought. <br/>"); comment.Summary.AppendLine($"Modification of the target LoadOrder, or Mods on the LoadOrder is not safe. Internal caches can become"); comment.Summary.AppendLine($"incorrect if modifications occur on content already cached."); comment.Parameters.GetOrAdd("loadOrder").AppendLine("LoadOrder to construct the package relative to"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static ImmutableLoadOrderLinkCache{generic} ToImmutableLinkCache")) { args.Add($"this IEnumerable<IModListingGetter<{getterName}>> loadOrder"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return loadOrder.ToImmutableLinkCache{generic}();"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a new linking package relative to a load order.<br/>"); comment.Summary.AppendLine($"Will resolve links to the highest overriding mod containing the record being sought. <br/>"); comment.Summary.AppendLine($"Modification of the target LoadOrder, or Mods on the LoadOrder is not safe. Internal caches can become"); comment.Summary.AppendLine($"incorrect if modifications occur on content already cached."); comment.Parameters.GetOrAdd("loadOrder").AppendLine("LoadOrder to construct the package relative to"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static ImmutableLoadOrderLinkCache{generic} ToImmutableLinkCache")) { args.Add($"this IEnumerable<{getterName}> loadOrder"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return loadOrder.ToImmutableLinkCache{generic}();"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a mutable load order link cache by combining an existing immutable load order cache,"); comment.Summary.AppendLine($"plus a set of mods to be put at the end of the load order and allow to be mutable."); comment.Parameters.GetOrAdd("immutableBaseCache").AppendLine("LoadOrderCache to use as the immutable base"); comment.Parameters.GetOrAdd("mutableMods").AppendLine("Set of mods to place at the end of the load order, which are allowed to be modified afterwards"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static MutableLoadOrderLinkCache{generic} ToMutableLinkCache")) { args.Add($"this ILoadOrderGetter<{getterName}> immutableBaseCache"); args.Add($"params {setterName}[] mutableMods"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return immutableBaseCache.ToMutableLinkCache{generic}(mutableMods);"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a mutable load order link cache by combining an existing immutable load order cache,"); comment.Summary.AppendLine($"plus a set of mods to be put at the end of the load order and allow to be mutable."); comment.Parameters.GetOrAdd("immutableBaseCache").AppendLine("LoadOrderCache to use as the immutable base"); comment.Parameters.GetOrAdd("mutableMods").AppendLine("Set of mods to place at the end of the load order, which are allowed to be modified afterwards"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static MutableLoadOrderLinkCache{generic} ToMutableLinkCache")) { args.Add($"this ILoadOrderGetter<IModListingGetter<{getterName}>> immutableBaseCache"); args.Add($"params {setterName}[] mutableMods"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return immutableBaseCache.ToMutableLinkCache{generic}(mutableMods);"); } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Creates a mutable load order link cache by combining an existing immutable load order cache,"); comment.Summary.AppendLine($"plus a set of mods to be put at the end of the load order and allow to be mutable."); comment.Parameters.GetOrAdd("immutableBaseCache").AppendLine("LoadOrderCache to use as the immutable base"); comment.Parameters.GetOrAdd("mutableMods").AppendLine("Set of mods to place at the end of the load order, which are allowed to be modified afterwards"); comment.Return.AppendLine($"LinkPackage attached to given LoadOrder"); } using (var args = new FunctionWrapper(fg, $"public static MutableLoadOrderLinkCache{generic} ToMutableLinkCache")) { args.Add($"this IEnumerable<{getterName}> immutableBaseCache"); args.Add($"params {setterName}[] mutableMods"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return immutableBaseCache.ToMutableLinkCache{generic}(mutableMods);"); } fg.AppendLine(); } } var path = Path.Combine(proto.DefFileLocation.FullName, $"LinkCacheMixIns{Loqui.Generation.Constants.AutogeneratedMarkerString}.cs"); fg.Generate(path); proto.GeneratedFiles.Add(path, ProjItemType.Compile); }
protected override void FillPublicElement(ObjectGeneration obj, FileGeneration fg) { using (var args = new FunctionWrapper(fg, $"public static void FillPublicElement{ModuleNickname}")) { args.Add($"{obj.Interface(getter: false, internalInterface: true)} item"); args.Add($"XElement {XmlTranslationModule.XElementLine.GetParameterName(obj)}"); args.Add("string name"); args.Add($"ErrorMaskBuilder? errorMask"); args.Add($"{nameof(TranslationCrystal)}? translationMask"); } using (new BraceWrapper(fg)) { fg.AppendLine("switch (name)"); using (new BraceWrapper(fg)) { bool isInRange = false; foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.FalseAndInclude, nonIntegrated: true)) { if (field is DataType set) { foreach (var subField in set.IterateFieldsWithMeta()) { if (subField.Field.Derivative) { continue; } if (subField.Field.ReadOnly) { continue; } if (!subField.Field.IntegrateField) { continue; } if (!this.TryGetTypeGeneration(subField.Field.GetType(), out var generator)) { throw new ArgumentException("Unsupported type generator: " + subField.Field); } fg.AppendLine($"case \"{subField.Field.Name}\":"); using (new DepthWrapper(fg)) { if (generator.ShouldGenerateCopyIn(subField.Field)) { generator.GenerateCopyIn( fg: fg, objGen: obj, typeGen: subField.Field, nodeAccessor: XmlTranslationModule.XElementLine.GetParameterName(obj).Result, itemAccessor: Accessor.FromType(subField.Field, "item"), translationMaskAccessor: "translationMask", errorMaskAccessor: $"errorMask"); } HandleDataTypeParsing(obj, fg, set, subField, ref isInRange); fg.AppendLine("break;"); } } } else if (field.IntegrateField) { if (field.Derivative) { continue; } if (field.ReadOnly) { continue; } if (!this.TryGetTypeGeneration(field.GetType(), out var generator)) { throw new ArgumentException("Unsupported type generator: " + field); } fg.AppendLine($"case \"{field.Name}\":"); using (new DepthWrapper(fg)) { if (generator.ShouldGenerateCopyIn(field)) { generator.GenerateCopyIn( fg: fg, objGen: obj, typeGen: field, nodeAccessor: XmlTranslationModule.XElementLine.GetParameterName(obj).Result, itemAccessor: Accessor.FromType(field, "item"), translationMaskAccessor: "translationMask", errorMaskAccessor: $"errorMask"); } fg.AppendLine("break;"); } } } fg.AppendLine("default:"); using (new DepthWrapper(fg)) { if (obj.HasLoquiBaseObject) { using (var args = new ArgsWrapper(fg, $"{this.TranslationCreateClass(obj.BaseClass)}.FillPublicElement{ModuleNickname}")) { args.Add("item: item"); args.Add($"{XmlTranslationModule.XElementLine.GetParameterName(obj)}: {XmlTranslationModule.XElementLine.GetParameterName(obj)}"); args.Add("name: name"); args.Add("errorMask: errorMask"); if (this.TranslationMaskParameter) { args.Add($"translationMask: translationMask"); } } } fg.AppendLine("break;"); } } } fg.AppendLine(); }
public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes) { if (!maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class)) { return; } await base.GenerateInCommon(obj, fg, maskTypes); if (!await obj.IsMajorRecord()) { return; } using (new RegionWrapper(fg, "Duplicate")) { using (var args = new FunctionWrapper(fg, $"public{obj.Virtual()}{obj.Name} Duplicate{obj.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter)}")) { args.Wheres.AddRange(obj.GenericTypeMaskWheres(LoquiInterfaceType.IGetter, MaskType.Normal, MaskType.NormalGetter)); args.Add($"{obj.Interface(getter: true)} item"); args.Add($"{nameof(FormKey)} formKey"); args.Add($"TranslationCrystal? copyMask"); } using (new BraceWrapper(fg)) { if (obj.Abstract) { fg.AppendLine("throw new NotImplementedException();"); } else { fg.AppendLine($"var newRec = new {obj.Name}(formKey{(obj.GetObjectData().HasMultipleReleases ? $", default({obj.GetObjectData().GameCategory}Release)" : null)});"); fg.AppendLine($"newRec.DeepCopyIn(item, default({nameof(ErrorMaskBuilder)}?), copyMask);"); fg.AppendLine("return newRec;"); } } fg.AppendLine(); foreach (var baseClass in obj.BaseClassTrail()) { using (var args = new FunctionWrapper(fg, $"public override {baseClass.Name} Duplicate{baseClass.GetGenericTypes(MaskType.Normal, MaskType.NormalGetter)}")) { args.Wheres.AddRange(baseClass.GenericTypeMaskWheres(LoquiInterfaceType.IGetter, MaskType.Normal, MaskType.NormalGetter)); args.Add($"{baseClass.Interface(getter: true)} item"); args.Add($"{nameof(FormKey)} formKey"); args.Add($"TranslationCrystal? copyMask"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return this.Duplicate")) { args.Add($"item: ({obj.Interface(getter: false)})item"); args.AddPassArg("formKey"); args.AddPassArg("copyMask"); } } fg.AppendLine(); } } }
public override async Task FinalizeGeneration(ProtocolGeneration proto) { if (proto.Protocol.Namespace.Equals("Bethesda")) { return; } var objData = proto.ObjectGenerationsByID.Values.FirstOrDefault()?.GetObjectData(); if (objData == null) { return; } var relString = objData.HasMultipleReleases ? "release.ToGameRelease()" : $"{nameof(GameRelease)}.{proto.Protocol.Namespace}"; FileGeneration fg = new FileGeneration(); fg.AppendLine("using System.Collections.Generic;"); fg.AppendLine($"using Mutagen.Bethesda.Plugins;"); fg.AppendLine($"using Mutagen.Bethesda.Plugins.Implicit;"); fg.AppendLine($"using Mutagen.Bethesda.{proto.Protocol.Namespace};"); fg.AppendLine(); using (var n = new NamespaceWrapper(fg, "Mutagen.Bethesda")) { using (var c = new ClassWrapper(fg, "ImplicitsMixIn")) { c.Static = true; } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"public static IReadOnlyCollection<ModKey> {proto.Protocol.Namespace}")) { args.Add($"this ImplicitBaseMasters _"); if (objData.HasMultipleReleases) { args.Add($"{objData.GameCategory}Release release"); } } using (new BraceWrapper(fg)) { fg.AppendLine($"return Implicits.Get({relString}).BaseMasters;"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static IReadOnlyCollection<ModKey> {proto.Protocol.Namespace}")) { args.Add($"this ImplicitListings _"); if (objData.HasMultipleReleases) { args.Add($"{objData.GameCategory}Release release"); } } using (new BraceWrapper(fg)) { fg.AppendLine($"return Implicits.Get({relString}).Listings;"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static IReadOnlyCollection<FormKey> {proto.Protocol.Namespace}")) { args.Add($"this ImplicitRecordFormKeys _"); if (objData.HasMultipleReleases) { args.Add($"{objData.GameCategory}Release release"); } } using (new BraceWrapper(fg)) { fg.AppendLine($"return Implicits.Get({relString}).RecordFormKeys;"); } } } var path = Path.Combine(proto.DefFileLocation.FullName, $"../ImplicitsMixIn{Loqui.Generation.Constants.AutogeneratedMarkerString}.cs"); fg.Generate(path); proto.GeneratedFiles.Add(path, ProjItemType.Compile); }
private async Task GenerateForMod(ObjectGeneration obj, FileGeneration fg) { using (var args = new FunctionWrapper(fg, $"public static Task<{obj.Name}> CreateFromXmlFolder")) { args.Add("DirectoryPath dir"); args.Add("ModKey modKey"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, "return CreateFromXmlFolder")) { args.Add("dir: dir"); args.Add("modKey: modKey"); args.Add("errorMask: null"); } } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static async Task<({obj.Name} Mod, {obj.Mask(MaskType.Error)} ErrorMask)> CreateFromXmlFolderWithErrorMask")) { args.Add("DirectoryPath dir"); args.Add("ModKey modKey"); } using (new BraceWrapper(fg)) { fg.AppendLine("ErrorMaskBuilder? errorMaskBuilder = new ErrorMaskBuilder();"); using (var args = new ArgsWrapper(fg, "var ret = await CreateFromXmlFolder")) { args.Add("dir: dir"); args.Add("modKey: modKey"); args.Add("errorMask: errorMaskBuilder"); } fg.AppendLine($"var errorMask = {obj.Mask(MaskType.Error)}.Factory(errorMaskBuilder);"); fg.AppendLine("return (ret, errorMask);"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public static async Task<{obj.Name}> CreateFromXmlFolder")) { args.Add("DirectoryPath dir"); args.Add("ModKey modKey"); args.Add("ErrorMaskBuilder? errorMask"); } using (new BraceWrapper(fg)) { fg.AppendLine($"var item = new {obj.Name}(modKey);"); fg.AppendLine($"var tasks = new List<Task>();"); foreach (var field in obj.IterateFields()) { if (field.GetFieldData().CustomFolder) { using (var args = new ArgsWrapper(fg, $"tasks.Add(Task.Run(() => item.CreateFromXmlFolder{field.Name}", suffixLine: "))")) { args.Add("dir: dir"); args.Add($"name: nameof({field.Name})"); args.Add($"index: (int){field.IndexEnumName}"); args.Add($"errorMask: errorMask"); } continue; } if (!(field is LoquiType loqui)) { throw new ArgumentException(); } switch (loqui.TargetObjectGeneration.GetObjectType()) { case ObjectType.Record: using (var args = new ArgsWrapper(fg, $"item.{field.Name}.CopyInFromXml")) { args.Add($"path: Path.Combine(dir.Path, \"{field.Name}.xml\")"); args.Add($"errorMask: errorMask"); args.Add($"translationMask: null"); } break; case ObjectType.Group: if (!loqui.TryGetSpecificationAsObject("T", out var subObj)) { continue; } using (var args = new ArgsWrapper(fg, $"tasks.Add(Task.Run(() => item.{field.Name}.CreateFromXmlFolder<{subObj.Name}>", suffixLine: "))")) { args.Add($"dir: dir"); args.Add($"name: nameof({field.Name})"); args.Add($"errorMask: errorMask"); args.Add($"index: (int){field.IndexEnumName}"); } break; default: break; } } fg.AppendLine("await Task.WhenAll(tasks);"); fg.AppendLine("return item;"); } fg.AppendLine(); using (var args = new FunctionWrapper(fg, $"public async Task<{obj.Mask(MaskType.Error)}?> WriteToXmlFolder")) { args.Add("DirectoryPath dir"); args.Add("bool doMasks = true"); } using (new BraceWrapper(fg)) { fg.AppendLine($"ErrorMaskBuilder? errorMaskBuilder = null;"); fg.AppendLine("dir.Create();"); fg.AppendLine("using (new FolderCleaner(dir, FolderCleaner.CleanType.AccessTime))"); using (new BraceWrapper(fg)) { fg.AppendLine($"var tasks = new List<Task>();"); foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { throw new ArgumentException(); } if (field.GetFieldData().CustomFolder) { using (var args = new ArgsWrapper(fg, $"tasks.Add(Task.Run(() => WriteToXmlFolder{field.Name}", suffixLine: "))")) { args.Add("dir: dir"); args.Add($"name: nameof({field.Name})");; args.Add($"index: (int){field.IndexEnumName}"); args.Add($"errorMask: errorMaskBuilder"); } continue; } switch (loqui.TargetObjectGeneration.GetObjectType()) { case ObjectType.Record: using (var args = new ArgsWrapper(fg, $"tasks.Add(Task.Run(() => this.{field.Name}.WriteToXml", suffixLine: "))")) { args.Add($"path: Path.Combine(dir.Path, \"{field.Name}.xml\")"); args.Add($"errorMask: errorMaskBuilder"); args.Add($"translationMask: null"); } break; case ObjectType.Group: ObjectGeneration subObj; if (field is GroupType group) { if (!group.TryGetSpecificationAsObject("T", out subObj)) { continue; } using (var args = new ArgsWrapper(fg, $"tasks.Add(Task.Run(() => {field.Name}.WriteToXmlFolder<{subObj.Name}, {subObj.Mask(MaskType.Error)}>", suffixLine: "))")) { args.Add($"dir: dir.Path"); args.Add($"name: nameof({field.Name})"); args.Add($"errorMask: errorMaskBuilder"); args.Add($"index: (int){field.IndexEnumName}"); } } else { using (var args = new ArgsWrapper(fg, $"tasks.Add(Task.Run(() => {field.Name}.WriteToXmlFolder", suffixLine: "))")) { args.Add($"dir: dir.Path"); args.Add($"name: nameof({field.Name})"); args.Add($"errorMask: errorMaskBuilder"); args.Add($"index: (int){field.IndexEnumName}"); } } break; default: break; } } fg.AppendLine("await Task.WhenAll(tasks);"); } fg.AppendLine("return null;"); } }
public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg) { if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"{nameof(FormKey)} key"); } using (new BraceWrapper(fg)) { fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();"); fg.AppendLine("keys.Add(key);"); using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"IEnumerable<{nameof(FormKey)}> keys"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.Add("keys: keys.ToHashSet()"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"HashSet<{nameof(FormKey)}> keys"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"{nameof(FormKey)} key"); args.Add($"{nameof(Type)} type"); args.Add($"bool throwIfUnknown = true"); } using (new BraceWrapper(fg)) { fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();"); fg.AppendLine("keys.Add(key);"); using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); args.AddPassArg("type"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"IEnumerable<{nameof(FormKey)}> keys"); args.Add($"{nameof(Type)} type"); args.Add($"bool throwIfUnknown = true"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.Add("keys: keys.ToHashSet()"); args.AddPassArg("type"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"HashSet<{nameof(FormKey)}> keys"); args.Add($"{nameof(Type)} type"); args.Add($"bool throwIfUnknown = true"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); args.AddPassArg("type"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"TMajor record"); args.Add($"bool throwIfUnknown = true"); args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}"); } using (new BraceWrapper(fg)) { fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();"); fg.AppendLine("keys.Add(record.FormKey);"); using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); args.Add("type: typeof(TMajor)"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"IEnumerable<TMajor> records"); args.Add($"bool throwIfUnknown = true"); args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.Add("keys: records.Select(m => m.FormKey).ToHashSet()"); args.Add("type: typeof(TMajor)"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"{nameof(FormKey)} key"); args.Add($"bool throwIfUnknown = true"); args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}"); } using (new BraceWrapper(fg)) { fg.AppendLine($"var keys = new HashSet<{nameof(FormKey)}>();"); fg.AppendLine("keys.Add(key);"); using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); args.Add("type: typeof(TMajor)"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"IEnumerable<{nameof(FormKey)}> keys"); args.Add($"bool throwIfUnknown = true"); args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.Add("keys: keys.ToHashSet()"); args.Add("type: typeof(TMajor)"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static void Remove{obj.GetGenericTypes(MaskType.Normal, "TMajor")}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics)); args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj"); args.Add($"HashSet<{nameof(FormKey)}> keys"); args.Add($"bool throwIfUnknown = true"); args.Wheres.Add($"where TMajor : {nameof(IMajorRecordGetter)}"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"{obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.Remove")) { args.AddPassArg("obj"); args.AddPassArg("keys"); args.Add("type: typeof(TMajor)"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); }
public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes) { bool getter = maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class); if (!getter) { return; } var accessor = new Accessor("obj"); if (obj.Abstract) { return; } if (obj.GetObjectType() == ObjectType.Group) { return; } if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No) { return; } var overrideStr = await obj.FunctionOverride(async c => await MajorRecordModule.HasMajorRecords(c, includeBaseClass : false, includeSelf : true) != Case.No); using (var args = new FunctionWrapper(fg, $"public{overrideStr}IEnumerable<IModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>> EnumerateMajorRecordContexts")) { args.Add($"{obj.Interface(getter: getter, internalInterface: true)} obj"); args.Add($"{nameof(ILinkCache)} linkCache"); args.Add($"Type type"); if (obj.GetObjectType() != ObjectType.Mod) { args.Add($"{nameof(ModKey)} modKey"); args.Add($"IModContext? parent"); } args.Add($"bool throwIfUnknown"); if (obj.GetObjectType() == ObjectType.Record) { args.Add($"Func<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, {obj.Interface(getter: true)}, {obj.Interface(getter: false)}> getter"); } } using (new BraceWrapper(fg)) { if (obj.GetObjectType() == ObjectType.Record) { using (var args = new ArgsWrapper(fg, $"var curContext = new ModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}>")) { args.Add($"{(obj.GetObjectType() == ObjectType.Mod ? "obj.ModKey" : "modKey")}"); args.Add("record: obj"); args.AddPassArg("getter"); args.AddPassArg("parent"); } } var fgCount = fg.Count; fg.AppendLine("switch (type.Name)"); using (new BraceWrapper(fg)) { var gameCategory = obj.GetObjectData().GameCategory; Dictionary <object, FileGeneration> generationDict = new Dictionary <object, FileGeneration>(); foreach (var field in obj.IterateFields()) { FileGeneration fieldGen; if (field is LoquiType loqui) { if (loqui.TargetObjectGeneration.IsListGroup()) { continue; } var isMajorRecord = loqui.TargetObjectGeneration != null && await loqui.TargetObjectGeneration.IsMajorRecord(); if (!isMajorRecord && await MajorRecordModule.HasMajorRecords(loqui, includeBaseClass: true) == Case.No) { continue; } if (loqui.TargetObjectGeneration.GetObjectType() == ObjectType.Group) { fieldGen = generationDict.GetOrAdd(loqui.GetGroupTarget()); } else { fieldGen = generationDict.GetOrAdd(((object)loqui?.TargetObjectGeneration) ?? loqui); } } else if (field is ContainerType cont) { if (!(cont.SubTypeGeneration is LoquiType contLoqui)) { continue; } if (contLoqui.RefType == LoquiType.LoquiRefType.Generic) { fieldGen = generationDict.GetOrAdd("default:"); } else { fieldGen = generationDict.GetOrAdd(((object)contLoqui?.TargetObjectGeneration) ?? contLoqui); } } else if (field is DictType dict) { if (dict.Mode != DictMode.KeyedValue) { continue; } if (!(dict.ValueTypeGen is LoquiType dictLoqui)) { continue; } if (dictLoqui.RefType == LoquiType.LoquiRefType.Generic) { fieldGen = generationDict.GetOrAdd("default:"); } else { fieldGen = generationDict.GetOrAdd(((object)dictLoqui?.TargetObjectGeneration) ?? dictLoqui); } } else { continue; } await ApplyIterationLines(obj, field, fieldGen, accessor, getter); } bool doAdditionlDeepLogic = obj.Name != "ListGroup"; if (doAdditionlDeepLogic) { var deepRecordMapping = await MajorRecordModule.FindDeepRecords(obj); foreach (var deepRec in deepRecordMapping) { FileGeneration deepFg = generationDict.GetOrAdd(deepRec.Key); foreach (var field in deepRec.Value) { await ApplyIterationLines(obj, field, deepFg, accessor, getter, hasTarget : true, includeSelf : false); } } HashSet <string> blackList = new HashSet <string>(); foreach (var kv in generationDict) { switch (kv.Key) { case LoquiType loqui: if (loqui.RefType == LoquiType.LoquiRefType.Generic) { // Handled in default case continue; } else { fg.AppendLine($"case \"{loqui.Interface(getter: true)}\":"); fg.AppendLine($"case \"{loqui.Interface(getter: false)}\":"); if (loqui.HasInternalGetInterface) { fg.AppendLine($"case \"{loqui.Interface(getter: true, internalInterface: true)}\":"); } if (loqui.HasInternalSetInterface) { fg.AppendLine($"case \"{loqui.Interface(getter: false, internalInterface: true)}\":"); } if (loqui.RefType == LoquiType.LoquiRefType.Interface) { blackList.Add(loqui.SetterInterface); } } break; case ObjectGeneration targetObj: fg.AppendLine($"case \"{targetObj.ObjectName}\":"); fg.AppendLine($"case \"{targetObj.Interface(getter: true)}\":"); fg.AppendLine($"case \"{targetObj.Interface(getter: false)}\":"); if (targetObj.HasInternalGetInterface) { fg.AppendLine($"case \"{targetObj.Interface(getter: true, internalInterface: true)}\":"); } if (targetObj.HasInternalSetInterface) { fg.AppendLine($"case \"{targetObj.Interface(getter: false, internalInterface: true)}\":"); } break; case string str: if (str != "default:") { throw new NotImplementedException(); } continue; default: throw new NotImplementedException(); } using (new DepthWrapper(fg)) { fg.AppendLines(kv.Value); fg.AppendLine("yield break;"); } } // Generate for major record marker interfaces if (LinkInterfaceModule.ObjectMappings.TryGetValue(obj.ProtoGen.Protocol, out var interfs)) { foreach (var interf in interfs) { if (blackList.Contains(interf.Key)) { continue; } FileGeneration subFg = new FileGeneration(); HashSet <ObjectGeneration> passedObjects = new HashSet <ObjectGeneration>(); HashSet <TypeGeneration> deepObjects = new HashSet <TypeGeneration>(); foreach (var subObj in interf.Value) { var grup = obj.Fields .WhereCastable <TypeGeneration, GroupType>() .Where(g => g.GetGroupTarget() == subObj) .FirstOrDefault(); if (grup != null) { subFg.AppendLine($"foreach (var item in EnumerateMajorRecordContexts({accessor}, linkCache, typeof({grup.GetGroupTarget().Interface(getter: true)}), throwIfUnknown: throwIfUnknown))"); using (new BraceWrapper(subFg)) { subFg.AppendLine("yield return item;"); } passedObjects.Add(grup.GetGroupTarget()); } else if (deepRecordMapping.TryGetValue(subObj, out var deepRec)) { foreach (var field in deepRec) { deepObjects.Add(field); } } } foreach (var deepObj in deepObjects) { await ApplyIterationLines(obj, deepObj, subFg, accessor, getter, blackList : passedObjects, hasTarget : true, includeSelf : false); } if (!subFg.Empty) { fg.AppendLine($"case \"{interf.Key}\":"); fg.AppendLine($"case \"{interf.Key}Getter\":"); using (new BraceWrapper(fg)) { fg.AppendLines(subFg); fg.AppendLine("yield break;"); } } } } } fg.AppendLine("default:"); using (new DepthWrapper(fg)) { if (generationDict.TryGetValue("default:", out var gen)) { fg.AppendLines(gen); fg.AppendLine("yield break;"); } else { fg.AppendLine("if (throwIfUnknown)"); using (new BraceWrapper(fg)) { fg.AppendLine("throw new ArgumentException($\"Unknown major record type: {type}\");"); } fg.AppendLine($"else"); using (new BraceWrapper(fg)) { fg.AppendLine("yield break;"); } } } } } fg.AppendLine(); }
public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg) { if (obj.GetObjectType() != ObjectType.Mod) { return; } var needsCatch = obj.GetObjectType() == ObjectType.Mod; string catchLine = needsCatch ? ".Catch(e => throw RecordException.Factory(e, obj.ModKey))" : string.Empty; string enderSemi = needsCatch ? string.Empty : ";"; fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<IModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, TSetter, TGetter>> EnumerateMajorRecordContexts{obj.GetGenericTypes(MaskType.Normal, new string[] { "TSetter", "TGetter" })}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics)); args.Wheres.Add($"where TSetter : class, IMajorRecordCommon, TGetter"); args.Wheres.Add($"where TGetter : class, IMajorRecordCommonGetter"); args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj"); args.Add($"{nameof(ILinkCache)} linkCache"); args.Add($"bool throwIfUnknown = true"); } using (new BraceWrapper(fg)) { using (var args = new FunctionWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecordContexts")) { args.AddPassArg("obj"); args.AddPassArg("linkCache"); args.Add("type: typeof(TGetter)"); args.AddPassArg("throwIfUnknown"); } using (new DepthWrapper(fg)) { fg.AppendLine($".Select(m => m.AsType<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, {nameof(IMajorRecordCommon)}, {nameof(IMajorRecordCommonGetter)}, TSetter, TGetter>()){enderSemi}"); if (needsCatch) { fg.AppendLine($"{catchLine};"); } } } fg.AppendLine(); fg.AppendLine("[DebuggerStepThrough]"); using (var args = new FunctionWrapper(fg, $"public static IEnumerable<IModContext<{obj.GetObjectData().GameCategory.Value.ModInterface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>> EnumerateMajorRecordContexts{obj.GetGenericTypes(MaskType.Normal)}")) { args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj"); args.Add($"{nameof(ILinkCache)} linkCache"); args.Add($"Type type"); args.Add($"bool throwIfUnknown = true"); args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics)); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecordContexts")) { args.AddPassArg("obj"); args.AddPassArg("linkCache"); args.AddPassArg("type"); args.AddPassArg("throwIfUnknown"); } } fg.AppendLine(); }
public override async Task GenerateInClass(ObjectGeneration obj, FileGeneration fg) { await base.GenerateInClass(obj, fg); if (!await obj.IsMajorRecord()) { return; } using (var args = new FunctionWrapper(fg, $"public {obj.Name}")) { args.Add($"{nameof(FormKey)} formKey"); if (obj.GetObjectData().HasMultipleReleases) { args.Add($"{obj.GetObjectData().GameCategory}Release gameRelease"); } } using (new BraceWrapper(fg)) { fg.AppendLine("this.FormKey = formKey;"); if (obj.GetObjectData().HasMultipleReleases) { fg.AppendLine("this.FormVersion = gameRelease.ToGameRelease().GetDefaultFormVersion()!.Value;"); } fg.AppendLine("CustomCtor();"); } fg.AppendLine(); // Used for reflection based construction using (var args = new FunctionWrapper(fg, $"private {obj.Name}")) { args.Add($"{nameof(FormKey)} formKey"); args.Add($"{nameof(GameRelease)} gameRelease"); } using (new BraceWrapper(fg)) { fg.AppendLine("this.FormKey = formKey;"); if (obj.GetObjectData().GameCategory?.HasFormVersion() ?? false) { fg.AppendLine("this.FormVersion = gameRelease.GetDefaultFormVersion()!.Value;"); } fg.AppendLine("CustomCtor();"); } fg.AppendLine(); if (obj.GetObjectData().GameCategory?.HasFormVersion() ?? false) { using (var args = new FunctionWrapper(fg, $"internal {obj.Name}")) { args.Add($"{nameof(FormKey)} formKey"); args.Add($"ushort formVersion"); } using (new BraceWrapper(fg)) { fg.AppendLine("this.FormKey = formKey;"); fg.AppendLine("this.FormVersion = formVersion;"); fg.AppendLine("CustomCtor();"); } fg.AppendLine(); } fg.AppendLine($"public {obj.Name}(I{obj.GetObjectData().GameCategory}Mod mod)"); using (new DepthWrapper(fg)) { using (var args = new FunctionWrapper(fg, ": this")) { args.Add($"mod.{nameof(IMod.GetNextFormKey)}()"); if (obj.GetObjectData().HasMultipleReleases) { args.Add($"mod.{obj.GetObjectData().GameCategory}Release"); } } } using (new BraceWrapper(fg)) { } fg.AppendLine(); fg.AppendLine($"public {obj.Name}(I{obj.GetObjectData().GameCategory}Mod mod, string editorID)"); using (new DepthWrapper(fg)) { using (var args = new FunctionWrapper(fg, ": this")) { args.Add($"mod.{nameof(IMod.GetNextFormKey)}(editorID)"); if (obj.GetObjectData().HasMultipleReleases) { args.Add($"mod.{obj.GetObjectData().GameCategory}Release"); } } } using (new BraceWrapper(fg)) { fg.AppendLine("this.EditorID = editorID;"); } fg.AppendLine(); }
private void GenerateWriteParallel(ObjectGeneration obj, FileGeneration fg) { LoquiType groupInstance = null; LoquiType listGroupInstance = null; var objData = obj.GetObjectData(); fg.AppendLine("const int CutCount = 100;"); using (var args = new FunctionWrapper(fg, "public static void WriteParallel")) { args.Add($"{obj.Interface(getter: true, internalInterface: false)} item"); args.Add($"Stream stream"); args.Add($"{nameof(BinaryWriteParameters)} param"); args.Add($"ModKey modKey"); } using (new BraceWrapper(fg)) { string gameConstantsStr; if (objData.GameReleaseOptions == null) { gameConstantsStr = $"{nameof(GameConstants)}.{obj.GetObjectData().GameCategory}"; } else { fg.AppendLine($"var gameConstants = {nameof(GameConstants)}.Get(item.{ReleaseEnumName(obj)}.ToGameRelease());"); gameConstantsStr = $"gameConstants"; } fg.AppendLine($"var bundle = new {nameof(WritingBundle)}({gameConstantsStr});"); fg.AppendLine($"var writer = new MutagenWriter(stream, bundle);"); using (var args = new ArgsWrapper(fg, $"{nameof(ModHeaderWriteLogic)}.{nameof(ModHeaderWriteLogic.WriteHeader)}")) { args.AddPassArg("param"); args.AddPassArg("writer"); args.Add("mod: item"); args.Add("modHeader: item.ModHeader.DeepCopy()"); args.AddPassArg("modKey"); } int groupCount = obj.IterateFields() .Select(f => f as LoquiType) .Where(l => l != null) .Where(l => l.TargetObjectGeneration?.GetObjectData().ObjectType == ObjectType.Group) .Count(); fg.AppendLine($"Stream[] outputStreams = new Stream[{groupCount}];"); fg.AppendLine($"List<Action> toDo = new List<Action>();"); int i = 0; foreach (var field in obj.IterateFields()) { if (!(field is LoquiType loqui)) { continue; } if (loqui.TargetObjectGeneration?.GetObjectData().ObjectType != ObjectType.Group) { continue; } if (loqui.TargetObjectGeneration.Name == "ListGroup") { listGroupInstance = loqui; } else { groupInstance = loqui; } if (loqui.GetGroupTarget().GetObjectData().CustomBinaryEnd == CustomEnd.Off && loqui.TargetObjectGeneration.Name != "ListGroup") { fg.AppendLine($"toDo.Add(() => WriteGroupParallel(item.{field.Name}, writer.MetaData.MasterReferences!, {i}{(objData.GameReleaseOptions == null ? null : ", gameConstants")}, outputStreams{(objData.UsesStringFiles ? ", param.StringsWriter" : null)}));"); } else { fg.AppendLine($"toDo.Add(() => Write{field.Name}Parallel(item.{field.Name}, writer.MetaData.MasterReferences!, {i}{(objData.GameReleaseOptions == null ? null : ", gameConstants")}, outputStreams));"); } i++; } fg.AppendLine("Parallel.Invoke(toDo.ToArray());"); using (var args = new ArgsWrapper(fg, $"{nameof(UtilityTranslation)}.{nameof(UtilityTranslation.CompileStreamsInto)}")) { args.Add("outputStreams.NotNull()"); args.Add("stream"); } } fg.AppendLine(); if (groupInstance != null) { using (var args = new FunctionWrapper(fg, $"public static void WriteGroupParallel<T>")) { args.Add("IGroupGetter<T> group"); args.Add($"{nameof(MasterReferenceReader)} masters"); args.Add("int targetIndex"); if (objData.GameReleaseOptions != null) { args.Add($"{nameof(GameConstants)} gameConstants"); } args.Add("Stream[] streamDepositArray"); if (objData.UsesStringFiles) { args.Add($"{nameof(StringsWriter)}? stringsWriter"); } args.Wheres.AddRange(groupInstance.TargetObjectGeneration.GenerateWhereClauses(LoquiInterfaceType.IGetter, groupInstance.TargetObjectGeneration.Generics)); } using (new BraceWrapper(fg)) { string gameConstantsStr; if (objData.GameReleaseOptions == null) { gameConstantsStr = $"{nameof(GameConstants)}.{obj.GetObjectData().GameCategory}"; } else { gameConstantsStr = "gameConstants"; } fg.AppendLine("if (group.RecordCache.Count == 0) return;"); fg.AppendLine($"var cuts = group.Cut(CutCount).ToArray();"); fg.AppendLine($"Stream[] subStreams = new Stream[cuts.Length + 1];"); fg.AppendLine($"byte[] groupBytes = new byte[{gameConstantsStr}.GroupConstants.HeaderLength];"); fg.AppendLine($"BinaryPrimitives.WriteInt32LittleEndian(groupBytes.AsSpan(), RecordTypes.GRUP.TypeInt);"); fg.AppendLine($"var groupByteStream = new MemoryStream(groupBytes);"); fg.AppendLine($"using (var stream = new MutagenWriter(groupByteStream, {gameConstantsStr}, dispose: false))"); using (new BraceWrapper(fg)) { fg.AppendLine($"stream.Position += 8;"); fg.AppendLine($"GroupBinaryWriteTranslation.WriteEmbedded<T>(group, stream);"); } fg.AppendLine($"subStreams[0] = groupByteStream;"); fg.AppendLine($"Parallel.ForEach(cuts, (cutItems, state, counter) =>"); using (new BraceWrapper(fg) { AppendSemicolon = true, AppendParenthesis = true }) { fg.AppendLine($"{nameof(MemoryTributary)} trib = new {nameof(MemoryTributary)}();"); fg.AppendLine($"var bundle = new {nameof(WritingBundle)}({gameConstantsStr})"); using (var prop = new PropertyCtorWrapper(fg)) { prop.Add($"{nameof(WritingBundle.MasterReferences)} = masters"); if (objData.UsesStringFiles) { prop.Add($"{nameof(WritingBundle.StringsWriter)} = stringsWriter"); } } fg.AppendLine($"using (var stream = new MutagenWriter(trib, bundle, dispose: false))"); using (new BraceWrapper(fg)) { fg.AppendLine($"foreach (var item in cutItems)"); using (new BraceWrapper(fg)) { fg.AppendLine($"item.WriteToBinary(stream);"); } } fg.AppendLine($"subStreams[(int)counter + 1] = trib;"); } fg.AppendLine($"UtilityTranslation.CompileSetGroupLength(subStreams, groupBytes);"); fg.AppendLine($"streamDepositArray[targetIndex] = new CompositeReadStream(subStreams, resetPositions: true);"); } fg.AppendLine(); } }
public override void GenerateWriteToNode(ObjectGeneration obj, FileGeneration fg) { using (var args = new FunctionWrapper(fg, $"public static void WriteToNode{ModuleNickname}{obj.GetGenericTypes(MaskType.Normal)}")) { args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, defs: obj.Generics)); args.Add($"{obj.Interface(internalInterface: true, getter: true)} item"); args.Add($"XElement {XmlTranslationModule.XElementLine.GetParameterName(obj)}"); args.Add($"ErrorMaskBuilder? errorMask"); args.Add($"{nameof(TranslationCrystal)}? translationMask"); } using (new BraceWrapper(fg)) { if (obj.HasLoquiBaseObject) { using (var args = new ArgsWrapper(fg, $"{this.TranslationWriteClass(obj.BaseClass)}.WriteToNode{ModuleNickname}")) { args.Add($"item: item"); args.Add($"{XmlTranslationModule.XElementLine.GetParameterName(obj)}: {XmlTranslationModule.XElementLine.GetParameterName(obj)}"); args.Add($"errorMask: errorMask"); args.Add($"translationMask: translationMask"); } } void generateNormal(XmlTranslationGeneration generator, TypeGeneration field) { if (!generator.ShouldGenerateWrite(field)) { return; } List <string> conditions = new List <string>(); if (field.HasBeenSet) { conditions.Add($"{field.HasBeenSetAccessor(getter: true, accessor: Accessor.FromType(field, "item"))}"); } if (this.TranslationMaskParameter) { conditions.Add(field.GetTranslationIfAccessor("translationMask")); } if (conditions.Count > 0) { using (var args = new IfWrapper(fg, ANDs: true)) { foreach (var item in conditions) { args.Add(item); } } } using (new BraceWrapper(fg, doIt: conditions.Count > 0)) { var maskType = this.Gen.MaskModule.GetMaskModule(field.GetType()).GetErrorMaskTypeStr(field); generator.GenerateWrite( fg: fg, objGen: obj, typeGen: field, writerAccessor: $"{XmlTranslationModule.XElementLine.GetParameterName(obj)}", itemAccessor: Accessor.FromType(field, "item"), errorMaskAccessor: $"errorMask", translationMaskAccessor: "translationMask", nameAccessor: $"nameof(item.{field.Name})"); } } foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.FalseAndInclude, nonIntegrated: true)) { if (!this.TryGetTypeGeneration(field.GetType(), out var generator)) { if (!field.IntegrateField) { continue; } throw new ArgumentException("Unsupported type generator: " + field); } if (field is DataType dataType) { if (dataType.HasBeenSet) { fg.AppendLine($"if (item.{dataType.StateName}.HasFlag({obj.Name}.{dataType.EnumName}.Has))"); } using (new BraceWrapper(fg, doIt: dataType.HasBeenSet)) { bool isInRange = false; int encounteredBreakIndex = 0; foreach (var subField in dataType.IterateFieldsWithMeta()) { if (!this.TryGetTypeGeneration(subField.Field.GetType(), out var subGenerator)) { throw new ArgumentException("Unsupported type generator: " + subField.Field); } var subData = subField.Field.GetFieldData(); if (!subGenerator.ShouldGenerateCopyIn(subField.Field)) { continue; } if (subField.BreakIndex != -1) { fg.AppendLine($"if (!item.{dataType.StateName}.HasFlag({obj.Name}.{dataType.EnumName}.Break{subField.BreakIndex}))"); fg.AppendLine("{"); fg.Depth++; encounteredBreakIndex++; } if (subField.Range != null && !isInRange) { isInRange = true; fg.AppendLine($"if (item.{dataType.StateName}.HasFlag({obj.Name}.{dataType.EnumName}.Range{subField.RangeIndex}))"); fg.AppendLine("{"); fg.Depth++; } if (subField.Range == null && isInRange) { isInRange = false; fg.Depth--; fg.AppendLine("}"); } generateNormal(subGenerator, subField.Field); } for (int i = 0; i < encounteredBreakIndex; i++) { fg.Depth--; fg.AppendLine("}"); if (i == encounteredBreakIndex - 1) { fg.AppendLine("else"); using (new BraceWrapper(fg)) { fg.AppendLine($"node.Add(new XElement(\"Has{dataType.EnumName}\"));"); } } } } } else { generateNormal(generator, field); } } } fg.AppendLine(); }
public override async Task FinalizeGeneration(ProtocolGeneration proto) { if (proto.Protocol.Namespace.Equals("Bethesda")) { return; } bool generate = false; FileGeneration fg = new FileGeneration(); var modObj = proto.ObjectGenerationsByID.Values.FirstOrDefault(o => o.GetObjectType() == ObjectType.Mod); fg.AppendLine("using System.Collections.Generic;"); fg.AppendLine("using Mutagen.Bethesda.Plugins.Cache;"); fg.AppendLine("using Mutagen.Bethesda.Plugins.Order;"); fg.AppendLine("using Mutagen.Bethesda.Plugins.Order.Internals;"); fg.AppendLine(); using (var n = new NamespaceWrapper(fg, proto.DefaultNamespace)) { using (var c = new ClassWrapper(fg, "TypeOptionSolidifierMixIns")) { c.Static = true; } using (new BraceWrapper(fg)) { using (new RegionWrapper(fg, "Normal")) { foreach (var obj in proto.ObjectGenerationsByName .OrderBy(x => x.Key) .Select(x => x.Value)) { if (!await obj.IsMajorRecord()) { continue; } var topLevel = modObj.Fields.Any(x => { if (x is not GroupType grup) { return(false); } var grupTarget = grup.GetGroupTarget(); if (grupTarget == obj) { return(true); } return(obj.BaseClassTrail().Any(b => b == grupTarget)); }); var topLevelStr = topLevel ? "TopLevel" : string.Empty; using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Scope a load order query to {obj.Name}"); comment.Parameters.GetOrAdd("listings").AppendLine("ModListings to query"); comment.Return.AppendLine($"A typed object to do further queries on {obj.Name}"); } using (var args = new FunctionWrapper(fg, $"public static {topLevelStr}TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}> {obj.Name}")) { args.Add($"this IEnumerable<IModListingGetter<I{proto.Protocol.Namespace}ModGetter>> listings"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return new {topLevelStr}TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}>")) { args.Add($"(bool includeDeletedRecords) => listings.WinningOverrides<{obj.Interface(getter: true)}>(includeDeletedRecords: includeDeletedRecords)"); args.Add($"({nameof(ILinkCache)} linkCache, bool includeDeletedRecords) => listings.WinningOverrideContexts<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}>(linkCache, includeDeletedRecords: includeDeletedRecords)"); } } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Scope a load order query to {obj.Name}"); comment.Parameters.GetOrAdd("mods").AppendLine("Mods to query"); comment.Return.AppendLine($"A typed object to do further queries on {obj.Name}"); } using (var args = new FunctionWrapper(fg, $"public static {topLevelStr}TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}> {obj.Name}")) { args.Add($"this IEnumerable<I{proto.Protocol.Namespace}ModGetter> mods"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return new {topLevelStr}TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}>")) { args.Add($"(bool includeDeletedRecords) => mods.WinningOverrides<{obj.Interface(getter: true)}>(includeDeletedRecords: includeDeletedRecords)"); args.Add($"({nameof(ILinkCache)} linkCache, bool includeDeletedRecords) => mods.WinningOverrideContexts<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {obj.Interface(getter: false)}, {obj.Interface(getter: true)}>(linkCache, includeDeletedRecords: includeDeletedRecords)"); } } fg.AppendLine(); generate = true; } } using (new RegionWrapper(fg, "Link Interfaces")) { if (LinkInterfaceModule.ObjectMappings.TryGetValue(proto.Protocol, out var interfs)) { foreach (var interf in interfs) { var getter = $"{interf.Key}Getter"; using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Scope a load order query to {interf.Key}"); comment.Parameters.GetOrAdd("listings").AppendLine("ModListings to query"); comment.Return.AppendLine($"A typed object to do further queries on {interf.Key}"); } using (var args = new FunctionWrapper(fg, $"public static TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {interf.Key}, {getter}> {interf.Key}")) { args.Add($"this IEnumerable<IModListingGetter<I{proto.Protocol.Namespace}ModGetter>> listings"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return new TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {interf.Key}, {getter}>")) { args.Add($"(bool includeDeletedRecords) => listings.WinningOverrides<{getter}>(includeDeletedRecords: includeDeletedRecords)"); args.Add($"({nameof(ILinkCache)} linkCache, bool includeDeletedRecords) => listings.WinningOverrideContexts<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {interf.Key}, {getter}>(linkCache, includeDeletedRecords: includeDeletedRecords)"); } } fg.AppendLine(); using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine($"Scope a load order query to {interf.Key}"); comment.Parameters.GetOrAdd("mods").AppendLine("Mods to query"); comment.Return.AppendLine($"A typed object to do further queries on {interf.Key}"); } using (var args = new FunctionWrapper(fg, $"public static TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {interf.Key}, {getter}> {interf.Key}")) { args.Add($"this IEnumerable<I{proto.Protocol.Namespace}ModGetter> mods"); } using (new BraceWrapper(fg)) { using (var args = new ArgsWrapper(fg, $"return new TypedLoadOrderAccess<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {interf.Key}, {getter}>")) { args.Add($"(bool includeDeletedRecords) => mods.WinningOverrides<{getter}>(includeDeletedRecords: includeDeletedRecords)"); args.Add($"({nameof(ILinkCache)} linkCache, bool includeDeletedRecords) => mods.WinningOverrideContexts<I{proto.Protocol.Namespace}Mod, I{proto.Protocol.Namespace}ModGetter, {interf.Key}, {getter}>(linkCache, includeDeletedRecords: includeDeletedRecords)"); } } fg.AppendLine(); } } } } } if (!generate) { return; } var path = Path.Combine(proto.DefFileLocation.FullName, $"TypeSolidifier{Loqui.Generation.Constants.AutogeneratedMarkerString}.cs"); fg.Generate(path); proto.GeneratedFiles.Add(path, ProjItemType.Compile); }
public void Execute(GeneratorExecutionContext context) { if (context.CancellationToken.IsCancellationRequested) { return; } if (context.SyntaxReceiver is not CustomAspectInterfaceReceiver customAspectReceiver) { return; } try { if (context.CancellationToken.IsCancellationRequested) { return; } var interfaceSymbols = GetInterfaceTypeDictionary(context, customAspectReceiver); // Group things by namespace if (context.CancellationToken.IsCancellationRequested) { return; } var targets = new Dictionary <string, GenerationTarget>(); foreach (var namespaceGroup in interfaceSymbols.Values .GroupBy(x => x.Symbol.ContainingNamespace)) { targets[namespaceGroup.Key.Name] = new GenerationTarget( namespaceGroup.Key.Name, namespaceGroup, new()); } HashSet <string> requiredUsings = new(targets.SelectMany(x => x.Value.UsedInterfaces) .SelectMany(x => x.Types) .Select(i => i.Symbol) .NotNull() .Select(x => x.ContainingNamespace.ToString())); // Generate foreach (var namespaceGroup in targets) { if (context.CancellationToken.IsCancellationRequested) { return; } var fg = new FileGeneration(); foreach (var use in requiredUsings) { fg.AppendLine($"using {use};"); } fg.AppendLine(); using (new NamespaceWrapper(fg, namespaceGroup.Key)) { using (new RegionWrapper(fg, "Wrappers")) { foreach (var decl in namespaceGroup.Value.UsedInterfaces) { if (context.CancellationToken.IsCancellationRequested) { return; } foreach (var t in decl.Types) { var className = $"{t.Syntax.Type}Wrapper"; using (var c = new ClassWrapper(fg, className)) { c.Interfaces.Add(decl.Symbol.Name); } using (new BraceWrapper(fg)) { fg.AppendLine($"private readonly {t.Syntax.Type} _wrapped;"); foreach (var member in decl.Symbol.GetMembers()) { switch (member) { case IPropertySymbol prop: fg.AppendLine($"public {prop.Type} {prop.Name}"); using (new BraceWrapper(fg)) { if (!prop.IsWriteOnly) { fg.AppendLine($"get => _wrapped.{member.Name};"); } if (!prop.IsReadOnly) { fg.AppendLine($"set => _wrapped.{member.Name} = value;"); } } break; default: continue; } fg.AppendLine(); } using (var args = new FunctionWrapper(fg, $"public {className}")) { args.Add($"{t.Syntax.Type} rhs"); } using (new BraceWrapper(fg)) { fg.AppendLine("_wrapped = rhs;"); } } fg.AppendLine(); } } fg.AppendLine(); } if (context.CancellationToken.IsCancellationRequested) { return; } using (new RegionWrapper(fg, "Mix Ins")) { using (var c = new ClassWrapper(fg, "WrapperMixIns")) { c.Static = true; } using (new BraceWrapper(fg)) { foreach (var decl in namespaceGroup.Value.UsedInterfaces) { if (context.CancellationToken.IsCancellationRequested) { return; } foreach (var t in decl.Types) { using (var args = new FunctionWrapper(fg, $"public static {t.Syntax.Type}Wrapper As{decl.Symbol.Name}")) { args.Add($"this {t.Syntax.Type} rhs"); } using (new BraceWrapper(fg)) { fg.AppendLine($"return new {t.Syntax.Type}Wrapper(rhs);"); } fg.AppendLine(); } } } } } context.AddSource($"CustomAspectInterfaces.g.cs", fg.ToString()); } } catch (Exception ex) { customAspectReceiver.Exceptions.Add(ex); } if (customAspectReceiver.Exceptions.Count > 0) { context.AddSource($"Errors.g.cs", $"Number of exceptions: {customAspectReceiver.Exceptions.Count}\n" + $"{customAspectReceiver.Exceptions.FirstOrDefault()}"); } }