private static void WriteFieldSwitch(IndentedWriter output, Block block, string variable) { output. Line("switch (assignment.Name.ToLower())"). OpenParen(); foreach (var field in block.Fields) { output. Line($"case \"{field.FormatName.ToLowerInvariant()}\":"). IncreaseIndent(). Line($"{variable}.{field.PropertyName} = Read{field.PropertyType.ToPascalCase()}Value(assignment, \"{block.CodeName}.{field.PropertyName}\");"). Line("break;"). DecreaseIndent(); } output. Line("default:"). IncreaseIndent(). Line($"{variable}.UnknownProperties.Add(new UnknownProperty(assignment.Name, assignment.ValueAsString()));"). Line("break;"). DecreaseIndent(). CloseParen(); }
private static void WriteProperties(Block block, IndentedWriter sb) { foreach (var property in block.Fields.Where(_ => _.IsRequired)) { sb.Line($"private bool {property.FieldName}HasBeenSet = false;"). Line($"private {property.PropertyType} {property.FieldName};"). Line($"public {property.PropertyType} {property.PropertyName}"). OpenParen(). Line($"get {{ return {property.FieldName}; }}"). Line($"set"). OpenParen(). Line($"{property.FieldName}HasBeenSet = true;"). Line($"{property.FieldName} = value;"). CloseParen(). CloseParen(); } foreach (var field in block.Fields.Where(_ => !_.IsRequired)) { sb.Line($"public {field.PropertyType} {field.PropertyName} {{ get; set; }} = {field.DefaultValue};"); } foreach (var subBlock in block.SubBlocks) { sb.Line( $"public {subBlock.PropertyType} {subBlock.PropertyName} {{ get; }} = new {subBlock.PropertyType}();"); } }
public static void WriteTo(StreamWriter stream) { using (var output = new IndentedWriter(stream)) { output.Line( $@"// Copyright (c) {DateTime.Today.Year}, David Aramant // Distributed under the 3-clause BSD license. For full terms see the file LICENSE. using System.CodeDom.Compiler; using UdmfParsing.Udmf.Parsing.SuperpowerVersion.AbstractSyntaxTree; namespace UdmfParsing.Udmf.Parsing.SuperpowerVersion").OpenParen() .Line($"[GeneratedCode(\"{CurrentLibraryInfo.Name}\", \"{CurrentLibraryInfo.Version}\")]") .Line("public static partial class UdmfSemanticAnalyzer").OpenParen(); WriteGlobalFieldParsing(output); output.Line(); WriteBlockParsing(output); output.Line(); foreach (var block in UdmfDefinitions.Blocks.Where(b => b.IsSubBlock)) { WriteBlockParser(block, output); } output.CloseParen(); output.CloseParen(); } }
private static void WriteBlockParsing(IndentedWriter output) { output. Line("static partial void ProcessBlock(MapData map, Block block)"). OpenParen(). Line("switch (block.Name.ToLower())"). OpenParen(); foreach (var block in UdmfDefinitions.Blocks.Single(b => b.CodeName.ToPascalCase() == "MapData").SubBlocks .Where(b => b.IsRequired)) { output. Line($"case \"{block.FormatName.ToLowerInvariant()}\":"). IncreaseIndent(). Line($"map.{block.PropertyName}.Add(Process{block.FormatName.ToPascalCase()}(block));"). Line("break;"). DecreaseIndent(); } output. Line("default:"). IncreaseIndent(). Line($"map.UnknownBlocks.Add(ProcessUnknownBlock(block));"). Line("break;"). DecreaseIndent(). CloseParen(). CloseParen(); }
public static void WriteToPath(string basePath) { if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); } using var stream = File.CreateText(Path.Combine(basePath, "MapDeclarationParser.Generated.cs")); using var output = new IndentedWriter(stream); var includes = new[] { "System.CodeDom.Compiler", "System.Linq", "Tiledriver.Core.FormatModels.Common", "Tiledriver.Core.FormatModels.MapInfo.Reading.AbstractSyntaxTree", }; output .Line("#nullable enable") .WriteHeader("Tiledriver.Core.FormatModels.MapInfo.Reading", includes) .Line($"[GeneratedCode(\"{CurrentLibraryInfo.Name}\", \"{CurrentLibraryInfo.Version}\")]") .Line($"public static partial class MapDeclarationParser") .OpenParen(); WriteParser(output, MapInfoDefinitions.Blocks.Single(b => b.ClassName == "DefaultMap")); output.Line(); WriteParser(output, MapInfoDefinitions.Blocks.Single(b => b.ClassName == "AddDefaultMap")); output.Line(); WriteMapParser(output, MapInfoDefinitions.Blocks.Single(b => b.ClassName == "Map")); output.Line(); WriteDefaultMapUpdater(output, MapInfoDefinitions.Blocks.Single(b => b.ClassName == "DefaultMap")); output.CloseParen(); }
static void WriteRecord(string basePath, Block block) { using var blockStream = File.CreateText(Path.Combine(basePath, block.ClassName + ".Generated.cs")); using var output = new IndentedWriter(blockStream); var containsCollection = block.Properties.Any(p => p is CollectionProperty); bool includeConverter = block.ClassName == "TileTemplate"; var includes = new List <string> { "System.CodeDom.Compiler" }; if (containsCollection) { includes.Add("System.Collections.Immutable"); } if (includeConverter) { includes.Add("Tiledriver.Core.FormatModels.Uwmf"); } output .WriteHeader("Tiledriver.Core.FormatModels.Xlat", includes) .Line($"[GeneratedCode(\"{CurrentLibraryInfo.Name}\", \"{CurrentLibraryInfo.Version}\")]") .Line($"public sealed partial record {block.ClassName}(") .IncreaseIndent() .JoinLines(",", block.OrderedProperties.Select(GetPropertyDefinition)) .DecreaseIndent(); if (includeConverter) { output .Line(")") .OpenParen() .Line("public Tile ToTile() =>") .IncreaseIndent() .Line("new Tile(") .IncreaseIndent() .JoinLines(",", block .OrderedProperties .Where(p => p.PropertyName != "OldNum") .Select(p => $"{p.PropertyName}: {p.PropertyName}")) .DecreaseIndent() .Line(");") .DecreaseIndent() .CloseParen(); } else { output.Line(");"); } }
static void WriteRecord(string basePath, IBlock block) { using var blockStream = File.CreateText(Path.Combine(basePath, block.ClassName + ".Generated.cs")); using var output = new IndentedWriter(blockStream); var containsCollection = block.OrderedProperties.Any(p => p is CollectionProperty); var containsIdentifier = block.OrderedProperties.Any(p => p is IdentifierProperty); List <string> includes = new() { "System.CodeDom.Compiler" }; if (containsCollection) { includes.Add("System.Collections.Immutable"); } if (containsIdentifier) { includes.Add("Tiledriver.Core.FormatModels.Common"); } var qualifier = block is AbstractBlock ? "abstract" : "sealed"; var includesNullables = block.OrderedProperties.OfType <ScalarProperty>().Any(sp => sp.IsNullable); if (includesNullables) { output.Line("#nullable enable"); } output .WriteHeader("Tiledriver.Core.FormatModels.MapInfo", includes) .Line($"[GeneratedCode(\"{CurrentLibraryInfo.Name}\", \"{CurrentLibraryInfo.Version}\")]") .Line($"public {qualifier} partial record {block.ClassName}(") .IncreaseIndent() .JoinLines(",", block.OrderedProperties.Select(GetPropertyDefinition)) .DecreaseIndent(); if (block is InheritedBlock ib) { output .Line($") : {ib.BaseClass.ClassName}(") .IncreaseIndent() .JoinLines(",", ib.BaseClass.OrderedProperties.Select(p => p.PropertyName)) .DecreaseIndent(); } output .Line(");"); }
private static void WriteSemanticValidityMethods(IndentedWriter output, Block block) { output.Line(@"public void CheckSemanticValidity()"). OpenParen(); // CHECK THAT ALL REQUIRED PROPERTIES HAVE BEEN SET foreach (var field in block.Fields.Where(_ => _.IsRequired)) { output.Line( $"if (!{field.FieldName}HasBeenSet) throw new InvalidUdmfException(\"Did not set {field.PropertyName} on {block.CodeName.ToPascalCase()}\");"); } output.Line(@"AdditionalSemanticChecks();"). CloseParen(). Line(). Line("partial void AdditionalSemanticChecks();"); }
private static void WriteWriteToMethod(Block block, IndentedWriter sb) { sb.Line(@"public Stream WriteTo(Stream stream)"). OpenParen(). Line("CheckSemanticValidity();"); var indent = block.IsSubBlock ? "true" : "false"; if (block.IsSubBlock) { sb.Line($"stream.WriteLine(\"{block.FormatName}\");"); sb.Line("stream.WriteLine(\"{\");"); } // WRITE ALL REQUIRED PROPERTIES foreach (var field in block.Fields.Where(_ => _.IsRequired)) { sb.Line( $"stream.WriteProperty(\"{field.FormatName}\", {field.FieldName}, indent: {indent});"); } // WRITE OPTIONAL PROPERTIES foreach (var field in block.Fields.Where(_ => !_.IsRequired)) { sb.Line( $"if ({field.PropertyName} != {field.DefaultValue}) stream.WriteProperty(\"{field.FormatName}\", {field.PropertyName}, indent: {indent});"); } // WRITE UNKNOWN PROPERTIES sb.Line($"foreach (var property in UnknownProperties)"). OpenParen(). Line($"stream.WritePropertyVerbatim((string)property.Name, property.Value, indent: {indent});"). CloseParen(); // WRITE SUB-BLOCKS foreach (var subBlock in block.SubBlocks.Where(b => !(b is UnknownPropertiesList))) { var variable = subBlock.FormatName; sb.Line($"foreach(var {variable} in {subBlock.PropertyName})"). OpenParen(). Line($"{variable}.WriteTo(stream);"). CloseParen(); } if (block.IsSubBlock) { sb.Line("stream.WriteLine(\"}\");"); } sb.Line("return stream;"). CloseParen(); }
static void WriteActorFile(string basePath, IReadOnlyList <Actor> actors) { using var blockStream = File.CreateText(Path.Combine(basePath, "Actor.Generated.cs")); using var output = new IndentedWriter(blockStream); output .WriteHeader("Tiledriver.Core.GameInfo.Doom", new[] { "System.Collections.Generic", "System.CodeDom.Compiler" }) .Line($"[GeneratedCode(\"{CurrentLibraryInfo.Name}\", \"{CurrentLibraryInfo.Version}\")]") .Line($"public sealed partial record Actor") .OpenParen(); foreach (var actor in actors) { output .Line($"/// <summary>{actor.Description}</summary>") .Line($"public static readonly Actor {actor.SafeName} = new(") .IncreaseIndent() .JoinLines(",", new[] { $"Id: {actor.Id}", $"Description: \"{actor.Description}\"", $"Width: {actor.Width}", $"Height: {actor.Height}" }) .DecreaseIndent() .Line(");") .Line(); } foreach (var category in actors.GroupBy(c => c.CategoryName)) { output .Line($"public static class {category.Key}") .OpenParen() .Lines(category.Select(actor => $"public static Actor {actor.SafeName} => Actor.{actor.SafeName};")) .Line("public static IEnumerable<Actor> GetAll()") .OpenParen() .Lines(category.Select(actor => $"yield return {actor.SafeName};")) .CloseParen() .CloseParen(); } output .CloseParen(); }
private static void WriteParser(IndentedWriter output, IBlock block) { output .Line($"private static partial {block.ClassName} Parse{block.ClassName}(ILookup<Identifier, VariableAssignment> assignmentLookup)") .IncreaseIndent() .Line($"=> new {block.ClassName}(") .IncreaseIndent() .JoinLines(",", block.OrderedProperties.Select(GetPropertyReader)) .DecreaseIndent() .Line(");") .DecreaseIndent(); }
private static void CreateBlockWriter(IndentedWriter output, Block block) { output .Line($"private static void Write(StreamWriter writer, {block.ClassName} {block.Name})") .OpenParen(); if (block.Serialization == SerializationType.Normal) { output .Line($"writer.WriteLine(\"{block.Name}\");") .Line("writer.WriteLine(\"{\");"); } foreach (var p in block.Properties) { if (p is ScalarProperty sp) { var defaultValue = sp.DefaultString; if (sp is TextureProperty { IsOptional: true })
private static void WriteGlobalFieldParsing(IndentedWriter output) { output. Line("static partial void ProcessGlobalAssignment(MapData map, Assignment assignment)"). OpenParen(); var block = UdmfDefinitions.Blocks.Single(b => b.CodeName.ToPascalCase() == "MapData"); WriteFieldSwitch(output, block, "map"); output. CloseParen(); }
private static void CreateBlockWriter(IndentedWriter output, Block block) { output .Line($"private static void Write(StreamWriter writer, {block.ClassName} {block.Name})") .OpenParen(); if (block.Serialization == SerializationType.Normal) { output .Line($"writer.WriteLine(\"{block.Name}\");") .Line("writer.WriteLine(\"{\");"); } foreach (var p in block.Properties) { if (p is ScalarProperty sp) { var defaultValue = sp.DefaultString; string optionalDefault = defaultValue != null ? ", " + defaultValue : string.Empty; string indent = block.Serialization == SerializationType.Normal ? string.Empty : ", indent:false"; output.Line($"WriteProperty(writer, \"{sp.FormatName}\", {block.Name}.{sp.PropertyName}{optionalDefault}{indent});"); } else if (p is CollectionProperty cp) { output.Line($"foreach(var block in {block.Name}.{cp.PropertyName})") .OpenParen() .Line($"Write(writer, block);") .CloseParen(); } } if (block.Serialization == SerializationType.Normal) { output.Line("writer.WriteLine(\"}\");"); } output.CloseParen(); }
private static void WriteCloneMethod(IndentedWriter output, Block block) { output. Line(). Line($"public {block.CodeName} Clone()"). OpenParen(). Line($"return new {block.CodeName}(").IncreaseIndent(); foreach (var indexed in block.OrderedProperties().Select((param, index) => new { param, index })) { var postfix = indexed.index == block.Properties.Count() - 1 ? ");" : ","; if (indexed.param is BlockList) { postfix = ".Select(item => item.Clone())" + postfix; } output.Line(indexed.param.ConstructorArgumentName + ": " + indexed.param.PropertyName + postfix); } output. DecreaseIndent(). CloseParen(); }
private static void WriteMapParser(IndentedWriter output, IBlock block) { output.Line("private static partial Map ParseMap(") .IncreaseIndent() .Line("ILookup<Identifier, VariableAssignment> assignmentLookup,") .Line("string mapLump,") .Line("string? mapName,") .Line("bool isMapNameLookup,") .Line("DefaultMap defaultMap) =>") .Line("new Map(") .IncreaseIndent() .JoinLines(",", block.OrderedProperties.Select(GetMapPropertyReader)) .DecreaseIndent() .Line(");") .DecreaseIndent(); }
public static void WriteToPath(string basePath) { foreach (var block in UdmfDefinitions.Blocks) { using (var blockStream = File.CreateText(Path.Combine(basePath, block.CodeName.ToPascalCase() + ".Generated.cs"))) using (var output = new IndentedWriter(blockStream)) { output.Line( $@"// Copyright (c) {DateTime.Today.Year}, David Aramant // Distributed under the 3-clause BSD license. For full terms see the file LICENSE. using System.CodeDom.Compiler; using System.Collections.Generic; using System.IO; using System.Linq; using UdmfParsing.Udmf.WritingExtensions; namespace UdmfParsing.Udmf"); output.OpenParen(); output.Line( $"[GeneratedCode(\"{CurrentLibraryInfo.Name}\", \"{CurrentLibraryInfo.Version}\")]"); output.Line( $"public sealed partial class {block.CodeName}"); output.OpenParen(); WriteProperties(block, output); output.Line(); WriteConstructors(output, block); output.Line(); WriteWriteToMethod(block, output); output.Line(); WriteSemanticValidityMethods(output, block); WriteCloneMethod(output, block); output.CloseParen(); output.Line(); output.CloseParen(); // End namespace } } }
private static void WriteBlockParser(Block block, IndentedWriter output) { var variable = block.CodeName.ToCamelCase(); output. Line($"static {block.CodeName} Process{block.CodeName}(Block block)"). OpenParen(). Line($"var {variable} = new {block.CodeName}();"). Line("foreach (var assignment in block.Fields)"). OpenParen(); WriteFieldSwitch(output, block, variable); output. CloseParen(). Line($"return {variable};"). CloseParen(). Line(); }
private static void WriteConstructors(IndentedWriter sb, Block block) { sb.Line($"public {block.CodeName}() {{ }}"); sb.Line($"public {block.CodeName}("); sb.IncreaseIndent(); foreach (var indexed in block.OrderedProperties().Select((param, index) => new { param, index })) { var property = indexed.param; var argument = $"{property.ConstructorArgumentType} {property.ConstructorArgumentName}" + (property.IsRequired ? string.Empty : $" = {property.DefaultValue}"); sb.Line(argument + (indexed.index == block.Properties.Count() - 1 ? ")" : ",")); } sb.DecreaseIndent(); sb.OpenParen(); foreach (var property in block.OrderedProperties()) { switch (property) { case Field field: sb.Line($"{field.PropertyName} = {field.ConstructorArgumentName};"); break; case BlockList requiredBlockList when requiredBlockList.IsRequired: sb.Line($"{requiredBlockList.PropertyName}.AddRange({requiredBlockList.ConstructorArgumentName});"); break; case BlockList blockList: sb.Line($"{blockList.PropertyName}.AddRange({blockList.ConstructorArgumentName} ?? Enumerable.Empty<{blockList.SingularName}>());"); break; } } sb.Line(@"AdditionalSemanticChecks();"); sb.CloseParen(); }