diff --git a/Schema/Schema.csproj b/Schema/Schema.csproj index e99b772..d26b5ab 100644 --- a/Schema/Schema.csproj +++ b/Schema/Schema.csproj @@ -20,12 +20,9 @@ - - - @@ -35,4 +32,22 @@ + + + + + + + + $(GetTargetPathDependsOn);GetDependencyTargetPaths + + + + + + + + + + \ No newline at end of file diff --git a/Schema/src/binary/text/BinarySchemaReaderGenerator.cs b/Schema/src/binary/text/BinarySchemaReaderGenerator.cs index 423d024..fb551af 100644 --- a/Schema/src/binary/text/BinarySchemaReaderGenerator.cs +++ b/Schema/src/binary/text/BinarySchemaReaderGenerator.cs @@ -10,7 +10,6 @@ using schema.util.asserts; using schema.util.symbols; using schema.util.text; -using schema.util.types; namespace schema.binary.text { public class BinarySchemaReaderGenerator { @@ -19,12 +18,8 @@ public class BinarySchemaReaderGenerator { public string Generate(IBinarySchemaContainer container) { var typeSymbol = container.TypeSymbol; - var typeNamespace = typeSymbol.GetFullyQualifiedNamespace(); - - var declaringTypes = typeSymbol.GetDeclaringTypesDownward(); - var sb = new StringBuilder(); - using var cbsb = new CurlyBracketTextWriter(new StringWriter(sb)); + using var sw = new SourceWriter(new StringWriter(sb)); { var dependencies = new List { "System", "schema.binary" }; @@ -42,85 +37,71 @@ public string Generate(IBinarySchemaContainer container) { dependencies.Sort(StringComparer.Ordinal); foreach (var dependency in dependencies) { - cbsb.WriteLine($"using {dependency};"); + sw.WriteLine($"using {dependency};"); } - cbsb.WriteLine(""); - } - - // TODO: Handle fancier cases here - if (typeNamespace != null) { - cbsb.EnterBlock($"namespace {typeNamespace}"); - } - - foreach (var declaringType in declaringTypes) { - cbsb.EnterBlock(declaringType.GetQualifiersAndNameAndGenericParametersFor()); + sw.WriteLine(""); } - cbsb.EnterBlock(typeSymbol.GetQualifiersAndNameAndGenericParametersFor()); - - cbsb.EnterBlock($"public void Read(IBinaryReader {READER})"); - { - var hasLocalPositions = container.LocalPositions; - if (hasLocalPositions) { - cbsb.WriteLine($"{READER}.PushLocalSpace();"); - } - - var hasEndianness = container.Endianness != null; - if (hasEndianness) { - cbsb.WriteLine( - $"{READER}.PushContainerEndianness({SchemaGeneratorUtil.GetEndiannessName(container.Endianness.Value)});"); - } - - foreach (var member in container.Members) { - if (member is ISchemaValueMember valueMember) { - BinarySchemaReaderGenerator.ReadValueMember_( - cbsb, - typeSymbol, - valueMember); - } else if (member is ISchemaMethodMember) { - cbsb.WriteLine($"this.{member.Name}({READER});"); - } - } + sw.WriteNamespaceAndParentTypeBlocks( + typeSymbol, + () => { + sw.EnterBlock( + typeSymbol.GetQualifiersAndNameAndGenericParametersFor()); + + sw.EnterBlock($"public void Read(IBinaryReader {READER})"); + { + var hasLocalPositions = container.LocalPositions; + if (hasLocalPositions) { + sw.WriteLine($"{READER}.PushLocalSpace();"); + } - if (hasEndianness) { - cbsb.WriteLine($"{READER}.PopEndianness();"); - } + var hasEndianness = container.Endianness != null; + if (hasEndianness) { + sw.WriteLine( + $"{READER}.PushContainerEndianness({SchemaGeneratorUtil.GetEndiannessName(container.Endianness.Value)});"); + } - if (hasLocalPositions) { - cbsb.WriteLine($"{READER}.PopLocalSpace();"); - } - } - cbsb.ExitBlock(); + foreach (var member in container.Members) { + if (member is ISchemaValueMember valueMember) { + BinarySchemaReaderGenerator.ReadValueMember_( + sw, + typeSymbol, + valueMember); + } else if (member is ISchemaMethodMember) { + sw.WriteLine($"this.{member.Name}({READER});"); + } + } - // TODO: Handle fancier cases here + if (hasEndianness) { + sw.WriteLine($"{READER}.PopEndianness();"); + } - // type - cbsb.ExitBlock(); + if (hasLocalPositions) { + sw.WriteLine($"{READER}.PopLocalSpace();"); + } + } + sw.ExitBlock(); - // parent types - foreach (var declaringType in declaringTypes) { - cbsb.ExitBlock(); - } + // TODO: Handle fancier cases here - // namespace - if (typeNamespace != null) { - cbsb.ExitBlock(); - } + // type + sw.ExitBlock(); + }); var generatedCode = sb.ToString(); return generatedCode; } private static void ReadValueMember_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ITypeSymbol sourceSymbol, ISchemaValueMember member) { if (member.IsPosition) { if (member.MemberType.IsReadOnly) { - cbsb.WriteLine($"{READER}.AssertPosition(this.{member.Name});"); + sw.WriteLine($"{READER}.AssertPosition(this.{member.Name});"); } else { - cbsb.WriteLine($"this.{member.Name} = {READER}.Position;"); + sw.WriteLine($"this.{member.Name} = {READER}.Position;"); } return; @@ -137,14 +118,14 @@ private static void ReadValueMember_( var nullValue = offset.NullValue; var readBlockPrefix = ""; if (nullValue != null) { - cbsb.EnterBlock($"if (this.{offset.OffsetName.Name} == {nullValue})") + sw.EnterBlock($"if (this.{offset.OffsetName.Name} == {nullValue})") .WriteLine($"this.{member.Name} = null;") .ExitBlock(); readBlockPrefix = "else"; } - cbsb.EnterBlock(readBlockPrefix) + sw.EnterBlock(readBlockPrefix) .WriteLine($"var tempLocation = {READER}.Position;") .WriteLine( $"{READER}.Position = this.{offset.OffsetName.Name};"); @@ -154,7 +135,7 @@ private static void ReadValueMember_( var immediateIfBoolean = ifBoolean?.SourceType == IfBooleanSourceType.IMMEDIATE_VALUE; if (immediateIfBoolean) { - cbsb.EnterBlock(); + sw.EnterBlock(); } if (ifBoolean != null) { @@ -163,20 +144,20 @@ private static void ReadValueMember_( var booleanPrimitiveType = booleanNumberType.AsPrimitiveType(); var booleanPrimitiveLabel = SchemaGeneratorUtil.GetPrimitiveLabel(booleanPrimitiveType); - cbsb.WriteLine( + sw.WriteLine( $"var b = {READER}.Read{booleanPrimitiveLabel}() != 0;") .EnterBlock("if (b)"); } else { - cbsb.EnterBlock($"if (this.{ifBoolean.OtherMember.Name})"); + sw.EnterBlock($"if (this.{ifBoolean.OtherMember.Name})"); } if (member.MemberType is not IPrimitiveMemberType && member.MemberType is not IContainerMemberType && member.MemberType is not ISequenceMemberType { - SequenceTypeInfo.SequenceType: SequenceType + SequenceTypeInfo.SequenceType: SequenceType .MUTABLE_ARRAY }) { - cbsb.WriteLine( + sw.WriteLine( $"this.{member.Name} = new {sourceSymbol.GetQualifiedNameFromCurrentSymbol(member.MemberType.TypeSymbol)}();"); } } @@ -188,51 +169,51 @@ member.MemberType is not ISequenceMemberType { switch (memberType) { case IPrimitiveMemberType: { - BinarySchemaReaderGenerator.ReadPrimitive_( - cbsb, - sourceSymbol, - member); - break; - } - case IStringType: { - BinarySchemaReaderGenerator.ReadString_(cbsb, member); - break; - } - case IContainerMemberType containerMemberType: { - BinarySchemaReaderGenerator.ReadContainer_(cbsb, + BinarySchemaReaderGenerator.ReadPrimitive_( + sw, sourceSymbol, - containerMemberType, member); - break; - } + break; + } + case IStringType: { + BinarySchemaReaderGenerator.ReadString_(sw, member); + break; + } + case IContainerMemberType containerMemberType: { + BinarySchemaReaderGenerator.ReadContainer_(sw, + sourceSymbol, + containerMemberType, + member); + break; + } case ISequenceMemberType: { - BinarySchemaReaderGenerator.ReadArray_(cbsb, sourceSymbol, member); - break; - } + BinarySchemaReaderGenerator.ReadArray_(sw, sourceSymbol, member); + break; + } default: { - // Anything that makes it down here probably isn't meant to be read. - throw new NotImplementedException(); - } + // Anything that makes it down here probably isn't meant to be read. + throw new NotImplementedException(); + } } if (ifBoolean != null) { - cbsb.ExitBlock() + sw.ExitBlock() .EnterBlock("else") .WriteLine($"this.{member.Name} = null;") .ExitBlock(); if (immediateIfBoolean) { - cbsb.ExitBlock(); + sw.ExitBlock(); } } if (offset != null) { - cbsb.WriteLine($"{READER}.Position = tempLocation;") + sw.WriteLine($"{READER}.Position = tempLocation;") .ExitBlock(); } } private static void Align_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member) { var align = member.Align; if (align == null) { @@ -240,47 +221,47 @@ private static void Align_( } var valueName = align.Method switch { - AlignSourceType.CONST => $"{align.ConstAlign}", - AlignSourceType.OTHER_MEMBER => $"{align.OtherMember.Name}" + AlignSourceType.CONST => $"{align.ConstAlign}", + AlignSourceType.OTHER_MEMBER => $"{align.OtherMember.Name}" }; - cbsb.WriteLine($"{READER}.Align({valueName});"); + sw.WriteLine($"{READER}.Align({valueName});"); } private static void HandleMemberEndianness_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member, Action handler) { var hasEndianness = member.Endianness != null; if (hasEndianness) { - cbsb.WriteLine( + sw.WriteLine( $"{READER}.PushMemberEndianness({SchemaGeneratorUtil.GetEndiannessName(member.Endianness.Value)});"); } - BinarySchemaReaderGenerator.Align_(cbsb, member); + BinarySchemaReaderGenerator.Align_(sw, member); handler(); if (hasEndianness) { - cbsb.WriteLine($"{READER}.PopEndianness();"); + sw.WriteLine($"{READER}.PopEndianness();"); } } private static void ReadPrimitive_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ITypeSymbol sourceSymbol, ISchemaValueMember member) { var primitiveType = Asserts.CastNonnull(member.MemberType as IPrimitiveMemberType); HandleMemberEndianness_( - cbsb, + sw, member, () => { if (!primitiveType.IsReadOnly) { - cbsb.WriteLine( + sw.WriteLine( $"this.{member.Name} = {GetReadPrimitiveText_(sourceSymbol, primitiveType)};"); } else { - cbsb.WriteLine($"{GetAssertPrimitiveText_( + sw.WriteLine($"{GetAssertPrimitiveText_( primitiveType, $"this.{member.Name}")};"); } @@ -288,10 +269,10 @@ private static void ReadPrimitive_( } private static void ReadString_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member) { HandleMemberEndianness_( - cbsb, + sw, member, () => { var stringType = @@ -301,10 +282,10 @@ private static void ReadString_( var encodingType = ""; if (stringType.EncodingType != StringEncodingType.ASCII) { encodingType = stringType.EncodingType switch { - StringEncodingType.UTF8 => "StringEncodingType.UTF8", - StringEncodingType.UTF16 => "StringEncodingType.UTF16", - StringEncodingType.UTF32 => "StringEncodingType.UTF32", - _ => throw new ArgumentOutOfRangeException() + StringEncodingType.UTF8 => "StringEncodingType.UTF8", + StringEncodingType.UTF16 => "StringEncodingType.UTF16", + StringEncodingType.UTF32 => "StringEncodingType.UTF32", + _ => throw new ArgumentOutOfRangeException() }; } @@ -314,10 +295,10 @@ private static void ReadString_( if (stringType.IsReadOnly) { if (stringType.LengthSourceType == StringLengthSourceType.NULL_TERMINATED) { - cbsb.WriteLine( + sw.WriteLine( $"{READER}.AssertStringNT({encodingTypeWithComma}this.{member.Name});"); } else { - cbsb.WriteLine( + sw.WriteLine( $"{READER}.AssertString({encodingTypeWithComma}this.{member.Name});"); } @@ -326,7 +307,7 @@ private static void ReadString_( if (stringType.LengthSourceType == StringLengthSourceType.NULL_TERMINATED) { - cbsb.WriteLine( + sw.WriteLine( $"this.{member.Name} = {READER}.ReadStringNT({encodingType});"); return; } @@ -336,7 +317,7 @@ private static void ReadString_( : "ReadString"; if (stringType.LengthSourceType == StringLengthSourceType.CONST) { - cbsb.WriteLine( + sw.WriteLine( $"this.{member.Name} = {READER}.{readMethod}({encodingTypeWithComma}{stringType.ConstLength});"); return; } @@ -346,7 +327,7 @@ private static void ReadString_( var readType = SchemaGeneratorUtil.GetIntLabel( stringType.ImmediateLengthType); - cbsb.EnterBlock() + sw.EnterBlock() .WriteLine($"var l = {READER}.Read{readType}();") .WriteLine( $"this.{member.Name} = {READER}.{readMethod}({encodingTypeWithComma}l);") @@ -356,7 +337,7 @@ private static void ReadString_( if (stringType.LengthSourceType == StringLengthSourceType.OTHER_MEMBER) { - cbsb.WriteLine( + sw.WriteLine( $"this.{member.Name} = {READER}.{readMethod}({encodingTypeWithComma}{stringType.LengthMember.Name});"); return; } @@ -367,18 +348,18 @@ private static void ReadString_( } private static void ReadContainer_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ITypeSymbol sourceSymbol, IContainerMemberType containerMemberType, ISchemaValueMember member) { // TODO: Do value types need to be handled differently? var memberName = member.Name; if (containerMemberType.IsChild) { - cbsb.WriteLine($"this.{memberName}.Parent = this;"); + sw.WriteLine($"this.{memberName}.Parent = this;"); } HandleMemberEndianness_( - cbsb, + sw, member, () => { var isNullable = containerMemberType.TypeInfo.IsNullable; @@ -390,13 +371,13 @@ private static void ReadContainer_( containerMemberType.TypeSymbol); if (isNullable) { - cbsb.WriteLine( + sw.WriteLine( $"this.{memberName} = {READER}.ReadNew<{qualifiedTypeName}>();"); } else { if (!isStruct) { - cbsb.WriteLine($"this.{memberName}.Read({READER});"); + sw.WriteLine($"this.{memberName}.Read({READER});"); } else { - cbsb.EnterBlock() + sw.EnterBlock() .WriteLine($"var value = this.{memberName};") .WriteLine($"value.Read({READER});") .WriteLine($"this.{memberName} = value;") @@ -407,7 +388,7 @@ private static void ReadContainer_( } private static void ReadArray_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ITypeSymbol sourceSymbol, ISchemaValueMember member) { var arrayType = @@ -441,10 +422,10 @@ arrayType.ElementType is IPrimitiveMemberType var label = SchemaGeneratorUtil.GetPrimitiveLabel( primitiveElementType.PrimitiveType); - cbsb.WriteLine( + sw.WriteLine( $"{memberAccessor} = {READER}.Read{label}s({readCountAccessor});"); } else { - cbsb.WriteLine( + sw.WriteLine( $"{memberAccessor} = new {qualifiedElementName}[{readCountAccessor}];") .EnterBlock( $"for (var i = 0; i < {memberAccessor}.Length; ++i)") @@ -457,20 +438,20 @@ arrayType.ElementType is IPrimitiveMemberType } } - cbsb.EnterBlock(); + sw.EnterBlock(); if (!isArray) { - cbsb.WriteLine($"{memberAccessor}.Clear();"); + sw.WriteLine($"{memberAccessor}.Clear();"); } var target = isArray ? "temp" : $"this.{member.Name}"; if (isArray) { - cbsb.WriteLine( + sw.WriteLine( $"var {target} = new List<{qualifiedElementName}>();"); } { - cbsb.EnterBlock($"while (!{READER}.Eof)"); + sw.EnterBlock($"while (!{READER}.Eof)"); { var elementType = arrayType.ElementType; if (elementType is IGenericMemberType genericElementType) { @@ -478,28 +459,28 @@ arrayType.ElementType is IPrimitiveMemberType } if (elementType is IPrimitiveMemberType primitiveElementType) { - cbsb.WriteLine( + sw.WriteLine( $"{target}.Add({GetReadPrimitiveText_(sourceSymbol, primitiveElementType)});"); } else if (elementType is IContainerMemberType containerElementType) { - cbsb.WriteLine($"var e = new {qualifiedElementName}();"); + sw.WriteLine($"var e = new {qualifiedElementName}();"); if (containerElementType.IsChild) { - cbsb.WriteLine("e.Parent = this;"); + sw.WriteLine("e.Parent = this;"); } - cbsb.WriteLine($"e.Read({READER});"); - cbsb.WriteLine($"{target}.Add(e);"); + sw.WriteLine($"e.Read({READER});"); + sw.WriteLine($"{target}.Add(e);"); } } - cbsb.ExitBlock(); + sw.ExitBlock(); } if (isArray) { - cbsb.WriteLine($"this.{member.Name} = {target}.ToArray();"); + sw.WriteLine($"this.{member.Name} = {target}.ToArray();"); } - cbsb.ExitBlock(); + sw.ExitBlock(); return; } else if (arrayType.LengthSourceType != @@ -509,11 +490,11 @@ arrayType.ElementType is IPrimitiveMemberType SequenceLengthSourceType.IMMEDIATE_VALUE; var lengthName = arrayType.LengthSourceType switch { - SequenceLengthSourceType.IMMEDIATE_VALUE => "c", - SequenceLengthSourceType.OTHER_MEMBER => - $"this.{arrayType.LengthMember!.Name}", - SequenceLengthSourceType.CONST_LENGTH => - $"{arrayType.ConstLength}", + SequenceLengthSourceType.IMMEDIATE_VALUE => "c", + SequenceLengthSourceType.OTHER_MEMBER => + $"this.{arrayType.LengthMember!.Name}", + SequenceLengthSourceType.CONST_LENGTH => + $"{arrayType.ConstLength}", }; var castText = ""; @@ -530,39 +511,39 @@ arrayType.ElementType is IPrimitiveMemberType if (isImmediate) { var readType = SchemaGeneratorUtil.GetIntLabel( arrayType.ImmediateLengthType); - cbsb.EnterBlock() + sw.EnterBlock() .WriteLine($"var {lengthName} = {READER}.Read{readType}();"); } var inPlace = arrayType.SequenceTypeInfo.SequenceType == - SequenceType.MUTABLE_LIST - || arrayType.SequenceTypeInfo is { - SequenceType: SequenceType.MUTABLE_SEQUENCE, - IsLengthConst: false + SequenceType.MUTABLE_LIST || + arrayType.SequenceTypeInfo is { + SequenceType: SequenceType.MUTABLE_SEQUENCE, + IsLengthConst: false }; if (inPlace) { - cbsb.WriteLine( + sw.WriteLine( $"SequencesUtil.ResizeSequenceInPlace(this.{member.Name}, {castText}{lengthName});"); } else { - cbsb.WriteLine( + sw.WriteLine( $"this.{member.Name} = SequencesUtil.CloneAndResizeSequence(this.{member.Name}, {castText}{lengthName});"); } if (isImmediate) { - cbsb.ExitBlock(); + sw.ExitBlock(); } } - BinarySchemaReaderGenerator.ReadIntoArray_(cbsb, sourceSymbol, member); + BinarySchemaReaderGenerator.ReadIntoArray_(sw, sourceSymbol, member); } private static void ReadIntoArray_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ITypeSymbol sourceSymbol, ISchemaValueMember member) { HandleMemberEndianness_( - cbsb, + sw, member, () => { var sequenceMemberType = @@ -571,7 +552,7 @@ private static void ReadIntoArray_( var sequenceType = sequenceTypeInfo.SequenceType; if (sequenceType.IsISequence()) { - cbsb.WriteLine($"this.{member.Name}.Read({READER});"); + sw.WriteLine($"this.{member.Name}.Read({READER});"); return; } @@ -589,10 +570,10 @@ private static void ReadIntoArray_( var label = SchemaGeneratorUtil.GetPrimitiveLabel( primitiveElementType.PrimitiveType); if (!primitiveElementType.IsReadOnly) { - cbsb.WriteLine( + sw.WriteLine( $"{READER}.Read{label}s(this.{member.Name});"); } else { - cbsb.WriteLine( + sw.WriteLine( $"{READER}.Assert{label}s(this.{member.Name});"); } @@ -603,13 +584,13 @@ private static void ReadIntoArray_( if (!primitiveElementType.IsReadOnly) { var arrayLengthName = sequenceTypeInfo.LengthName; - cbsb.EnterBlock( + sw.EnterBlock( $"for (var i = 0; i < this.{member.Name}.{arrayLengthName}; ++i)") .WriteLine( $"this.{member.Name}[i] = {GetReadPrimitiveText_(sourceSymbol, primitiveElementType)};") .ExitBlock(); } else { - cbsb.EnterBlock( + sw.EnterBlock( $"foreach (var e in this.{member.Name})") .WriteLine( $"{GetAssertPrimitiveText_( @@ -623,31 +604,31 @@ private static void ReadIntoArray_( if (elementType is IContainerMemberType containerElementType) { if (!containerElementType.TypeSymbol.IsStruct()) { - cbsb.EnterBlock( + sw.EnterBlock( $"foreach (var e in this.{member.Name})"); if (containerElementType.IsChild) { - cbsb.WriteLine("e.Parent = this;"); + sw.WriteLine("e.Parent = this;"); } - cbsb.WriteLine($"e.Read({READER});"); - cbsb.ExitBlock(); + sw.WriteLine($"e.Read({READER});"); + sw.ExitBlock(); } else { var arrayLengthName = sequenceTypeInfo.LengthName; - cbsb.EnterBlock( + sw.EnterBlock( $"for (var i = 0; i < this.{member.Name}.{arrayLengthName}; ++i)"); - cbsb.WriteLine( + sw.WriteLine( $"var e = this.{member.Name}[i];"); if (containerElementType.IsChild) { - cbsb.WriteLine("e.Parent = this;"); + sw.WriteLine("e.Parent = this;"); } - cbsb.WriteLine($"e.Read({READER});"); - cbsb.WriteLine( + sw.WriteLine($"e.Read({READER});"); + sw.WriteLine( $"this.{member.Name}[i] = e;"); - cbsb.ExitBlock(); + sw.ExitBlock(); } return; @@ -676,7 +657,8 @@ private static string GetReadPrimitiveText_( } var castText = ""; - if (primitiveMemberType.UseAltFormat && !isBoolean && + if (primitiveMemberType.UseAltFormat && + !isBoolean && primitiveType != altFormat.AsPrimitiveType().GetUnderlyingPrimitiveType()) { var castType = primitiveType == SchemaPrimitiveType.ENUM diff --git a/Schema/src/binary/text/BinarySchemaWriterGenerator.cs b/Schema/src/binary/text/BinarySchemaWriterGenerator.cs index c1bb3e0..86a2a16 100644 --- a/Schema/src/binary/text/BinarySchemaWriterGenerator.cs +++ b/Schema/src/binary/text/BinarySchemaWriterGenerator.cs @@ -20,13 +20,8 @@ public class BinarySchemaWriterGenerator { public string Generate(IBinarySchemaContainer container) { var typeSymbol = container.TypeSymbol; - var typeNamespace = typeSymbol.GetFullyQualifiedNamespace(); - - var declaringTypes = - SymbolTypeUtil.GetDeclaringTypesDownward(typeSymbol); - var sb = new StringBuilder(); - using var cbsb = new CurlyBracketTextWriter(new StringWriter(sb)); + using var sw = new SourceWriter(new StringWriter(sb)); { var dependencies = new List { "System", "schema.binary" }; @@ -45,75 +40,61 @@ public string Generate(IBinarySchemaContainer container) { dependencies.Sort(StringComparer.Ordinal); foreach (var dependency in dependencies) { - cbsb.WriteLine($"using {dependency};"); + sw.WriteLine($"using {dependency};"); } - cbsb.WriteLine(""); - } - - // TODO: Handle fancier cases here - if (typeNamespace != null) { - cbsb.EnterBlock($"namespace {typeNamespace}"); + sw.WriteLine(""); } - foreach (var declaringType in declaringTypes) { - cbsb.EnterBlock(declaringType - .GetQualifiersAndNameAndGenericParametersFor()); - } - - cbsb.EnterBlock(typeSymbol.GetQualifiersAndNameAndGenericParametersFor()); - - cbsb.EnterBlock($"public void Write(IBinaryWriter {WRITER})"); - { - var hasLocalPositions = container.LocalPositions; - if (hasLocalPositions) { - cbsb.WriteLine($"{WRITER}.PushLocalSpace();"); - } - - var hasEndianness = container.Endianness != null; - if (hasEndianness) { - cbsb.WriteLine( - $"{WRITER}.PushContainerEndianness({SchemaGeneratorUtil.GetEndiannessName(container.Endianness.Value)});"); - } - - foreach (var member in container.Members.OfType()) { - BinarySchemaWriterGenerator.WriteValueMember_( - cbsb, - typeSymbol, - member); - } + sw.WriteNamespaceAndParentTypeBlocks( + typeSymbol, + () => { + sw.EnterBlock( + typeSymbol.GetQualifiersAndNameAndGenericParametersFor()); + + sw.EnterBlock($"public void Write(IBinaryWriter {WRITER})"); + { + var hasLocalPositions = container.LocalPositions; + if (hasLocalPositions) { + sw.WriteLine($"{WRITER}.PushLocalSpace();"); + } - if (hasEndianness) { - cbsb.WriteLine($"{WRITER}.PopEndianness();"); - } + var hasEndianness = container.Endianness != null; + if (hasEndianness) { + sw.WriteLine( + $"{WRITER}.PushContainerEndianness({SchemaGeneratorUtil.GetEndiannessName(container.Endianness.Value)});"); + } - if (hasLocalPositions) { - cbsb.WriteLine($"{WRITER}.PopLocalSpace();"); - } - } - cbsb.ExitBlock(); + foreach (var member in container.Members + .OfType()) { + BinarySchemaWriterGenerator.WriteValueMember_( + sw, + typeSymbol, + member); + } - // TODO: Handle fancier cases here + if (hasEndianness) { + sw.WriteLine($"{WRITER}.PopEndianness();"); + } - // type - cbsb.ExitBlock(); + if (hasLocalPositions) { + sw.WriteLine($"{WRITER}.PopLocalSpace();"); + } + } + sw.ExitBlock(); - // parent types - foreach (var declaringType in declaringTypes) { - cbsb.ExitBlock(); - } + // TODO: Handle fancier cases here - // namespace - if (typeNamespace != null) { - cbsb.ExitBlock(); - } + // type + sw.ExitBlock(); + }); var generatedCode = sb.ToString(); return generatedCode; } private static void WriteValueMember_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ITypeSymbol sourceSymbol, ISchemaValueMember member) { if (member.IsSkipped) { @@ -128,12 +109,12 @@ private static void WriteValueMember_( member.MemberType is not IContainerMemberType; var ifBoolean = member.IfBoolean; if (ifBoolean?.SourceType == IfBooleanSourceType.IMMEDIATE_VALUE) { - cbsb.WriteLine( + sw.WriteLine( $"{GetWritePrimitiveText_(SchemaPrimitiveType.BOOLEAN, ifBoolean.ImmediateBooleanType.AsNumberType(), $"this.{member.Name} != null")};"); } if (shouldSkipWhenNull) { - cbsb.EnterBlock($"if (this.{member.Name} != null)"); + sw.EnterBlock($"if (this.{member.Name} != null)"); } var memberType = member.MemberType; @@ -143,22 +124,22 @@ private static void WriteValueMember_( switch (memberType) { case IPrimitiveMemberType: { - BinarySchemaWriterGenerator.WritePrimitive_(cbsb, member); + BinarySchemaWriterGenerator.WritePrimitive_(sw, member); break; } case IStringType: { - BinarySchemaWriterGenerator.WriteString_(cbsb, member); + BinarySchemaWriterGenerator.WriteString_(sw, member); break; } case IContainerMemberType containerMemberType: { BinarySchemaWriterGenerator.WriteContainer_( - cbsb, + sw, containerMemberType, member); break; } case ISequenceMemberType: { - BinarySchemaWriterGenerator.WriteArray_(cbsb, member); + BinarySchemaWriterGenerator.WriteArray_(sw, member); break; } default: @@ -167,12 +148,12 @@ private static void WriteValueMember_( } if (shouldSkipWhenNull) { - cbsb.ExitBlock(); + sw.ExitBlock(); } } private static void Align_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member) { var align = member.Align; if (align == null) { @@ -183,39 +164,39 @@ private static void Align_( AlignSourceType.CONST => $"{align.ConstAlign}", AlignSourceType.OTHER_MEMBER => $"{align.OtherMember.Name}" }; - cbsb.WriteLine($"{WRITER}.Align({valueName});"); + sw.WriteLine($"{WRITER}.Align({valueName});"); } private static void HandleMemberEndiannessAndTracking_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member, Action handler) { - BinarySchemaWriterGenerator.Align_(cbsb, member); + BinarySchemaWriterGenerator.Align_(sw, member); var hasEndianness = member.Endianness != null; if (hasEndianness) { - cbsb.WriteLine( + sw.WriteLine( $"{WRITER}.PushMemberEndianness({SchemaGeneratorUtil.GetEndiannessName(member.Endianness.Value)});"); } var shouldTrackStartAndEnd = member.TrackStartAndEnd; if (shouldTrackStartAndEnd) { - cbsb.WriteLine($"{WRITER}.MarkStartOfMember(\"{member.Name}\");"); + sw.WriteLine($"{WRITER}.MarkStartOfMember(\"{member.Name}\");"); } handler(); if (shouldTrackStartAndEnd) { - cbsb.WriteLine($"{WRITER}.MarkEndOfMember();"); + sw.WriteLine($"{WRITER}.MarkEndOfMember();"); } if (hasEndianness) { - cbsb.WriteLine($"{WRITER}.PopEndianness();"); + sw.WriteLine($"{WRITER}.PopEndianness();"); } } private static void WritePrimitive_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member) { var primitiveMemberType = member.MemberType as IPrimitiveMemberType; if (primitiveMemberType == null) { @@ -228,7 +209,7 @@ private static void WritePrimitive_( var primitiveType = primitiveMemberType.PrimitiveType; HandleMemberEndiannessAndTracking_( - cbsb, + sw, member, () => { var writeType = useAltFormat @@ -253,7 +234,7 @@ private static void WritePrimitive_( if (isLengthOfString) { accessText = $"{lengthOfStringMembers[0].Name}.Length"; if (lengthOfStringMembers.Length > 1) { - cbsb.WriteLine( + sw.WriteLine( $"Asserts.AllEqual({string.Join(", ", lengthOfStringMembers.Select(member => $"{member.Name}.Length"))});"); } } @@ -268,7 +249,7 @@ private static void WritePrimitive_( (first.MemberTypeInfo as ISequenceTypeInfo).LengthName; accessText = $"{first.Name}.{firstLengthName}"; if (lengthOfSequenceMembers.Length > 1) { - cbsb.WriteLine( + sw.WriteLine( $"Asserts.AllEqual({string.Join(", ", lengthOfSequenceMembers.Select( member => { var lengthName = @@ -280,13 +261,13 @@ private static void WritePrimitive_( if ((isLengthOfString || isLengthOfSequence) && !primitiveType.AsIntegerType().CanAcceptAnInt32()) { - cbsb.WriteLine( + sw.WriteLine( $"{GetWritePrimitiveText_( SchemaPrimitiveType.INT32, primitiveType.AsNumberType(), accessText)};"); } else { - cbsb.WriteLine( + sw.WriteLine( $"{GetWritePrimitiveText_(primitiveMemberType, accessText)};"); } } else { @@ -321,17 +302,17 @@ private static void WritePrimitive_( accessText = $"{WRITER}.GetAbsoluteLength()"; } - cbsb.WriteLine( + sw.WriteLine( $"{WRITER}.Write{writeTypeLabel}Delayed({accessText}{castText});"); } }); } private static void WriteString_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member) { HandleMemberEndiannessAndTracking_( - cbsb, + sw, member, () => { var stringType = @@ -352,11 +333,11 @@ private static void WriteString_( if (stringType.LengthSourceType == StringLengthSourceType.NULL_TERMINATED) { - cbsb.WriteLine( + sw.WriteLine( $"{WRITER}.WriteStringNT({encodingTypeWithComma}this.{member.Name});"); } else if (stringType.LengthSourceType == StringLengthSourceType.CONST) { - cbsb.WriteLine( + sw.WriteLine( $"{WRITER}.WriteStringWithExactLength({encodingTypeWithComma}this.{member.Name}, {stringType.ConstLength});"); } else if (stringType.LengthSourceType == StringLengthSourceType.IMMEDIATE_VALUE) { @@ -373,40 +354,40 @@ private static void WriteString_( var accessText = $"this.{member.Name}.Length"; var writeType = stringType.ImmediateLengthType.GetIntLabel(); - cbsb.WriteLine( - $"{WRITER}.Write{writeType}({castText}{accessText});") - .WriteLine( - $"{WRITER}.WriteString({encodingTypeWithComma}this.{member.Name});"); + sw.WriteLine( + $"{WRITER}.Write{writeType}({castText}{accessText});") + .WriteLine( + $"{WRITER}.WriteString({encodingTypeWithComma}this.{member.Name});"); } else { - cbsb.WriteLine( + sw.WriteLine( $"{WRITER}.WriteString({encodingTypeWithComma}this.{member.Name});"); } }); } private static void WriteContainer_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, IContainerMemberType containerMemberType, ISchemaValueMember member) { var memberName = member.Name; if (containerMemberType.IsChild) { - cbsb.WriteLine($"this.{memberName}.Parent = this;"); + sw.WriteLine($"this.{memberName}.Parent = this;"); } HandleMemberEndiannessAndTracking_( - cbsb, + sw, member, () => { if (containerMemberType.TypeInfo.IsNullable) { - cbsb.WriteLine($"this.{memberName}?.Write({WRITER});"); + sw.WriteLine($"this.{memberName}?.Write({WRITER});"); } else { - cbsb.WriteLine($"this.{memberName}.Write({WRITER});"); + sw.WriteLine($"this.{memberName}.Write({WRITER});"); } }); } private static void WriteArray_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, ISchemaValueMember member) { var sequenceMemberType = Asserts.CastNonnull(member.MemberType as ISequenceMemberType); @@ -420,18 +401,18 @@ private static void WriteArray_( var arrayLengthName = sequenceMemberType.SequenceTypeInfo.LengthName; var arrayLengthAccessor = $"this.{member.Name}.{arrayLengthName}"; - cbsb.WriteLine( + sw.WriteLine( $"{GetWritePrimitiveText_(SchemaPrimitiveType.INT32, sequenceMemberType.ImmediateLengthType.AsNumberType(), arrayLengthAccessor)};"); } } - BinarySchemaWriterGenerator.WriteIntoArray_(cbsb, member); + BinarySchemaWriterGenerator.WriteIntoArray_(sw, member); } - private static void WriteIntoArray_(ICurlyBracketTextWriter cbsb, + private static void WriteIntoArray_(ISourceWriter sw, ISchemaValueMember member) { HandleMemberEndiannessAndTracking_( - cbsb, + sw, member, () => { var sequenceMemberType = @@ -440,7 +421,7 @@ private static void WriteIntoArray_(ICurlyBracketTextWriter cbsb, var sequenceType = sequenceTypeInfo.SequenceType; if (sequenceType.IsISequence()) { - cbsb.WriteLine($"this.{member.Name}.Write({WRITER});"); + sw.WriteLine($"this.{member.Name}.Write({WRITER});"); return; } @@ -459,30 +440,30 @@ private static void WriteIntoArray_(ICurlyBracketTextWriter cbsb, var label = SchemaGeneratorUtil.GetPrimitiveLabel( primitiveElementType.PrimitiveType); - cbsb.WriteLine( + sw.WriteLine( $"{WRITER}.Write{label}s(this.{member.Name});"); return; } // Primitives that *do* need to be cast have to be written individually. var arrayLengthName = sequenceTypeInfo.LengthName; - cbsb.EnterBlock( - $"for (var i = 0; i < this.{member.Name}.{arrayLengthName}; ++i)") - .WriteLine( - $"{GetWritePrimitiveText_(primitiveElementType, $"this.{member.Name}[i]")};") - .ExitBlock(); + sw.EnterBlock( + $"for (var i = 0; i < this.{member.Name}.{arrayLengthName}; ++i)") + .WriteLine( + $"{GetWritePrimitiveText_(primitiveElementType, $"this.{member.Name}[i]")};") + .ExitBlock(); return; } if (elementType is IContainerMemberType containerElementType) { - cbsb.EnterBlock($"foreach (var e in this.{member.Name})"); + sw.EnterBlock($"foreach (var e in this.{member.Name})"); if (containerElementType.IsChild) { - cbsb.WriteLine("e.Parent = this;"); + sw.WriteLine("e.Parent = this;"); } - cbsb.WriteLine($"e.Write({WRITER});") - .ExitBlock(); + sw.WriteLine($"e.Write({WRITER});") + .ExitBlock(); return; } diff --git a/Schema/src/readOnly/ReadOnlyTypeGenerator.cs b/Schema/src/readOnly/ReadOnlyTypeGenerator.cs index bb39133..1f07a49 100644 --- a/Schema/src/readOnly/ReadOnlyTypeGenerator.cs +++ b/Schema/src/readOnly/ReadOnlyTypeGenerator.cs @@ -52,132 +52,118 @@ internal override bool FilterNamedTypesBeforeGenerating( public string GenerateSourceForNamedType(INamedTypeSymbol typeSymbol, SemanticModel semanticModel, TypeDeclarationSyntax syntax) { - var typeNamespace = typeSymbol.GetFullyQualifiedNamespace(); - - var declaringTypes = typeSymbol.GetDeclaringTypesDownward(); - var sb = new StringBuilder(); - using var cbsb = new CurlyBracketTextWriter(new StringWriter(sb)); + using var sw = new SourceWriter(new StringWriter(sb)); + + sw.WriteNamespaceAndParentTypeBlocks( + typeSymbol, + () => { + var interfaceName = typeSymbol.GetConstInterfaceName(); + + var constMembers + = parser_ + .ParseMembers(typeSymbol) + .Where(parsedMember => { + var (parseStatus, memberSymbol, _, _) = parsedMember; + if (parseStatus == + TypeInfoParser.ParseStatus + .NOT_A_FIELD_OR_PROPERTY_OR_METHOD) { + return false; + } + + if (memberSymbol.DeclaredAccessibility is not ( + Accessibility.Public + or Accessibility.Internal)) { + return false; + } + + if (memberSymbol is IFieldSymbol) { + return false; + } + + if (memberSymbol is IPropertySymbol) { + return false; + } + + if (memberSymbol is IMethodSymbol && + !memberSymbol.Name.StartsWith("get_") && + !memberSymbol.HasAttribute()) { + return false; + } + + return true; + }) + .Select(parsedMember => (IMethodSymbol) parsedMember.Item2) + .ToArray(); - // TODO: Handle fancier cases here - if (typeNamespace != null) { - cbsb.EnterBlock($"namespace {typeNamespace}"); - } + // Class + { + var blockPrefix = + typeSymbol.GetQualifiersAndNameAndGenericParametersFor() + + " : " + + typeSymbol.GetNameAndGenericParametersFor(interfaceName); - foreach (var declaringType in declaringTypes) { - cbsb.EnterBlock(declaringType - .GetQualifiersAndNameAndGenericParametersFor()); - } - - var interfaceName = typeSymbol.GetConstInterfaceName(); - - var constMembers - = parser_ - .ParseMembers(typeSymbol) - .Where(parsedMember => { - var (parseStatus, memberSymbol, _, _) = parsedMember; - if (parseStatus == - TypeInfoParser.ParseStatus - .NOT_A_FIELD_OR_PROPERTY_OR_METHOD) { - return false; - } - - if (memberSymbol.DeclaredAccessibility is not ( - Accessibility.Public or Accessibility.Internal)) { - return false; - } - - if (memberSymbol is IFieldSymbol) { - return false; - } - - if (memberSymbol is IPropertySymbol) { - return false; - } - - if (memberSymbol is IMethodSymbol && - !memberSymbol.Name.StartsWith("get_") && - !memberSymbol.HasAttribute()) { - return false; - } - - return true; - }) - .Select(parsedMember => (IMethodSymbol) parsedMember.Item2) - .ToArray(); - - // Class - { - var blockPrefix = - typeSymbol.GetQualifiersAndNameAndGenericParametersFor() + - " : " + - typeSymbol.GetNameAndGenericParametersFor(interfaceName); - - if (constMembers.Length == 0) { - cbsb.Write(blockPrefix).WriteLine(";"); - } else { - cbsb.EnterBlock(blockPrefix); - WriteMembers_(cbsb, - typeSymbol, - constMembers, - semanticModel, - syntax, - interfaceName); - cbsb.ExitBlock(); - } - } - cbsb.WriteLine(""); - - // Interface - { - cbsb.Write( - SymbolTypeUtil.AccessibilityToModifier( - typeSymbol.DeclaredAccessibility)); - cbsb.Write(" interface "); - - var blockPrefix = interfaceName; - blockPrefix - += typeSymbol.GetGenericParametersWithVarianceForReadOnlyVersion( - constMembers); - var parentConstNames = - GetDirectBaseTypeAndInterfaces_(typeSymbol) - .Where(i => i.HasAttribute() || - IsTypeAlreadyConst_(i)) - .Select(i => typeSymbol - .GetQualifiedNameAndGenericsOrReadOnlyFromCurrentSymbol( - i, - semanticModel, - syntax)) - .ToArray(); - if (parentConstNames.Length > 0) { - blockPrefix += " : " + string.Join(", ", parentConstNames); - } + if (constMembers.Length == 0) { + sw.Write(blockPrefix).WriteLine(";"); + } else { + sw.EnterBlock(blockPrefix); + WriteMembers_(sw, + typeSymbol, + constMembers, + semanticModel, + syntax, + interfaceName); + sw.ExitBlock(); + } + } + sw.WriteLine(""); + + // Interface + { + sw.Write( + SymbolTypeUtil.AccessibilityToModifier( + typeSymbol.DeclaredAccessibility)); + sw.Write(" interface "); + + var blockPrefix = interfaceName; + blockPrefix + += typeSymbol + .GetGenericParametersWithVarianceForReadOnlyVersion( + constMembers); + var parentConstNames = + GetDirectBaseTypeAndInterfaces_(typeSymbol) + .Where(i => i.HasAttribute() || + IsTypeAlreadyConst_(i)) + .Select(i => typeSymbol + .GetQualifiedNameAndGenericsOrReadOnlyFromCurrentSymbol( + i, + semanticModel, + syntax)) + .ToArray(); + if (parentConstNames.Length > 0) { + blockPrefix += " : " + string.Join(", ", parentConstNames); + } - blockPrefix += typeSymbol.GetTypeConstraintsOrReadonly( - typeSymbol.TypeParameters, - semanticModel, - syntax); - - if (constMembers.Length == 0) { - cbsb.Write(blockPrefix).WriteLine(";"); - } else { - cbsb.EnterBlock(blockPrefix); - WriteMembers_(cbsb, typeSymbol, constMembers, semanticModel, syntax); - cbsb.ExitBlock(); - } + blockPrefix += typeSymbol.GetTypeConstraintsOrReadonly( + typeSymbol.TypeParameters, + semanticModel, + syntax); - // parent types - foreach (var _ in declaringTypes) { - cbsb.ExitBlock(); - } - - // namespace - if (typeNamespace != null) { - cbsb.ExitBlock(); - } + if (constMembers.Length == 0) { + sw.Write(blockPrefix).WriteLine(";"); + } else { + sw.EnterBlock(blockPrefix); + WriteMembers_(sw, + typeSymbol, + constMembers, + semanticModel, + syntax); + sw.ExitBlock(); + } + } + }); - return sb.ToString(); - } + return sb.ToString(); } private static bool IsTypeAlreadyConst_(INamedTypeSymbol typeSymbol) { @@ -221,7 +207,7 @@ private static bool IsTypeAlreadyConst_(INamedTypeSymbol typeSymbol) { } private static void WriteMembers_( - ICurlyBracketTextWriter cbsb, + ISourceWriter sw, INamedTypeSymbol typeSymbol, IReadOnlyList constMembers, SemanticModel semanticModel, @@ -231,14 +217,14 @@ private static void WriteMembers_( var memberTypeSymbol = memberSymbol.ReturnType; if (interfaceName == null) { - cbsb.Write(SymbolTypeUtil.AccessibilityToModifier( + sw.Write(SymbolTypeUtil.AccessibilityToModifier( typeSymbol.DeclaredAccessibility)) .Write(" "); } IPropertySymbol? associatedPropertySymbol = memberSymbol.AssociatedSymbol as IPropertySymbol; - cbsb.Write( + sw.Write( typeSymbol .GetQualifiedNameAndGenericsOrReadOnlyFromCurrentSymbol( memberTypeSymbol, @@ -248,7 +234,7 @@ private static void WriteMembers_( .Write(" "); if (interfaceName != null) { - cbsb.Write(interfaceName) + sw.Write(interfaceName) .Write(typeSymbol.GetGenericParameters()) .Write("."); } @@ -260,17 +246,17 @@ var isIndexer if (!isIndexer) { propertyAccessName = propertyAccessName.EscapeKeyword(); - cbsb.Write(memberSymbol.Name.Substring(4).EscapeKeyword()); + sw.Write(memberSymbol.Name.Substring(4).EscapeKeyword()); } else { propertyAccessName = "this"; - cbsb.Write("this["); + sw.Write("this["); for (var i = 0; i < indexerParameterSymbols.Length; ++i) { if (i > 0) { - cbsb.Write(", "); + sw.Write(", "); } var parameterSymbol = indexerParameterSymbols[i]; - cbsb.Write( + sw.Write( typeSymbol.GetQualifiedNameAndGenericsFromCurrentSymbol( parameterSymbol.Type, semanticModel, @@ -280,13 +266,13 @@ var isIndexer .Write(parameterSymbol.Name.EscapeKeyword()); } - cbsb.Write("]"); + sw.Write("]"); } if (interfaceName == null) { - cbsb.WriteLine(" { get; }"); + sw.WriteLine(" { get; }"); } else { - cbsb.Write(" => ") + sw.Write(" => ") .Write(typeSymbol.GetCStyleCastToReadOnlyIfNeeded( associatedPropertySymbol, memberSymbol.ReturnType, @@ -295,101 +281,101 @@ var isIndexer .Write(propertyAccessName); if (isIndexer) { - cbsb.Write("["); + sw.Write("["); for (var i = 0; i < memberSymbol.Parameters.Length; ++i) { if (i > 0) { - cbsb.Write(", "); + sw.Write(", "); } var parameterSymbol = memberSymbol.Parameters[i]; - cbsb.Write(parameterSymbol.Name.EscapeKeyword()); + sw.Write(parameterSymbol.Name.EscapeKeyword()); } - cbsb.Write("]"); + sw.Write("]"); } - cbsb.WriteLine(";"); + sw.WriteLine(";"); } } // Method else { var accessName = memberSymbol.Name.EscapeKeyword(); - cbsb.Write(accessName); - cbsb.Write(memberSymbol.TypeParameters + sw.Write(accessName); + sw.Write(memberSymbol.TypeParameters .GetGenericParameters()); - cbsb.Write("("); + sw.Write("("); for (var i = 0; i < memberSymbol.Parameters.Length; ++i) { if (i > 0) { - cbsb.Write(", "); + sw.Write(", "); } var parameterSymbol = memberSymbol.Parameters[i]; if (parameterSymbol.IsParams) { - cbsb.Write("params "); + sw.Write("params "); } var refKindString = parameterSymbol.RefKind.GetRefKindString(); if (refKindString.Length > 0) { - cbsb.Write(refKindString).Write(" "); + sw.Write(refKindString).Write(" "); } - cbsb.Write(typeSymbol.GetQualifiedNameAndGenericsFromCurrentSymbol( - parameterSymbol.Type, - semanticModel, - syntax, - parameterSymbol)) + sw.Write( + typeSymbol.GetQualifiedNameAndGenericsFromCurrentSymbol( + parameterSymbol.Type, + semanticModel, + syntax, + parameterSymbol)) .Write(" ") .Write(parameterSymbol.Name.EscapeKeyword()); - if (interfaceName == null && parameterSymbol.HasExplicitDefaultValue) { var defaultValueType = parameterSymbol.Type.UnwrapNullable(); - - cbsb.Write(" = "); + + sw.Write(" = "); var explicitDefaultValue = parameterSymbol.ExplicitDefaultValue; if (defaultValueType.IsEnum(out _) && explicitDefaultValue != null) { - cbsb.Write( + sw.Write( $"({typeSymbol.GetQualifiedNameFromCurrentSymbol(defaultValueType)}) {explicitDefaultValue}"); } else { switch (explicitDefaultValue) { case null: - cbsb.Write("null"); + sw.Write("null"); break; case char: - cbsb.Write($"'{explicitDefaultValue}'"); + sw.Write($"'{explicitDefaultValue}'"); break; case string: - cbsb.Write($"\"{explicitDefaultValue}\""); + sw.Write($"\"{explicitDefaultValue}\""); break; case bool boolValue: - cbsb.Write(boolValue ? "true" : "false"); + sw.Write(boolValue ? "true" : "false"); break; default: - cbsb.Write(explicitDefaultValue.ToString()); + sw.Write(explicitDefaultValue.ToString()); break; } } } } - cbsb.Write(")"); + sw.Write(")"); if (interfaceName == null) { - cbsb.Write(typeSymbol.GetTypeConstraintsOrReadonly( + sw.Write(typeSymbol.GetTypeConstraintsOrReadonly( memberSymbol.TypeParameters, semanticModel, syntax)); } if (interfaceName == null) { - cbsb.WriteLine(";"); + sw.WriteLine(";"); } else { - cbsb.Write(" => ") + sw.Write(" => ") .Write(typeSymbol.GetCStyleCastToReadOnlyIfNeeded( memberSymbol, memberSymbol.ReturnType, @@ -400,20 +386,20 @@ var isIndexer .Write("("); for (var i = 0; i < memberSymbol.Parameters.Length; ++i) { if (i > 0) { - cbsb.Write(", "); + sw.Write(", "); } var parameterSymbol = memberSymbol.Parameters[i]; var refKindString = parameterSymbol.RefKind.GetRefKindString(); if (refKindString.Length > 0) { - cbsb.Write(refKindString).Write(" "); + sw.Write(refKindString).Write(" "); } - cbsb.Write(parameterSymbol.Name.EscapeKeyword()); + sw.Write(parameterSymbol.Name.EscapeKeyword()); } - cbsb.WriteLine(");"); + sw.WriteLine(");"); } } } @@ -446,12 +432,13 @@ var parentInterfaces internal static class ReadOnlyTypeGeneratorUtil { public const string PREFIX = "IReadOnly"; - public static string GetQualifiedNameAndGenericsOrReadOnlyFromCurrentSymbol( - this ITypeSymbol sourceSymbol, - ITypeSymbol referencedSymbol, - SemanticModel semanticModel, - TypeDeclarationSyntax sourceDeclarationSyntax, - ISymbol? memberSymbol = null) + public static string + GetQualifiedNameAndGenericsOrReadOnlyFromCurrentSymbol( + this ITypeSymbol sourceSymbol, + ITypeSymbol referencedSymbol, + SemanticModel semanticModel, + TypeDeclarationSyntax sourceDeclarationSyntax, + ISymbol? memberSymbol = null) => sourceSymbol.GetQualifiedNameFromCurrentSymbol( referencedSymbol, memberSymbol, @@ -520,14 +507,16 @@ private static IEnumerable GetTypeConstraintNames_( } if (typeParameter.HasReferenceTypeConstraint) { - yield return typeParameter.ReferenceTypeConstraintNullableAnnotation == + yield return typeParameter + .ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated ? "class?" : "class"; } - if (typeParameter is - { HasValueTypeConstraint: true, HasUnmanagedTypeConstraint: false }) { + if (typeParameter is { + HasValueTypeConstraint: true, HasUnmanagedTypeConstraint: false + }) { yield return "struct"; } @@ -537,7 +526,9 @@ private static IEnumerable GetTypeConstraintNames_( constraintType, typeParameter, ConvertName_, - r => GetNamespaceOfType(r, semanticModel, sourceDeclarationSyntax)); + r => GetNamespaceOfType(r, + semanticModel, + sourceDeclarationSyntax)); yield return typeParameter.ConstraintNullableAnnotations[i] == NullableAnnotation.Annotated diff --git a/Schema/src/util/text/CurlyBracketTextWriter.cs b/Schema/src/util/text/CurlyBracketTextWriter.cs deleted file mode 100644 index 2406ad0..0000000 --- a/Schema/src/util/text/CurlyBracketTextWriter.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.IO; - -namespace schema.util.text { - public interface ICurlyBracketTextWriter { - public ICurlyBracketTextWriter EnterBlock(string prefix = ""); - public ICurlyBracketTextWriter Write(string text); - public ICurlyBracketTextWriter WriteLine(string text); - public ICurlyBracketTextWriter ExitBlock(); - } - - public sealed class CurlyBracketTextWriter - : ICurlyBracketTextWriter, - IDisposable { - private readonly TextWriter impl_; - private int indentLevel_ = 0; - private bool hasIndentedOnCurrentLine_ = false; - - public CurlyBracketTextWriter(TextWriter impl) { - this.impl_ = impl; - } - - ~CurlyBracketTextWriter() => this.ReleaseUnmanagedResources_(); - - public void Dispose() { - this.ReleaseUnmanagedResources_(); - GC.SuppressFinalize(this); - } - - private void ReleaseUnmanagedResources_() { - this.impl_.Dispose(); - } - - public ICurlyBracketTextWriter EnterBlock(string prefix = "") { - if (prefix.Length > 0) { - prefix = $"{prefix} "; - } - - this.WriteLine($"{prefix}{{"); - return this; - } - - public ICurlyBracketTextWriter Write(string text) { - var lines = text.Split('\n'); - for (var i = 0; i < lines.Length; ++i) { - var line = lines[i]; - var isLastLine = !(i < lines.Length - 1); - - if (isLastLine && line.Length == 0) { - break; - } - - foreach (var c in line) { - if (c == '}') { - --this.indentLevel_; - - if (this.indentLevel_ < 0) { - throw new Exception("Exited an extra block!"); - } - } - } - - if (!isLastLine) { - this.TryToPrintIndent_(); - this.impl_.WriteLine(line); - this.hasIndentedOnCurrentLine_ = false; - } else { - this.TryToPrintIndent_(); - this.impl_.Write(line); - } - - foreach (var c in line) { - if (c == '{') { - ++this.indentLevel_; - } - } - } - - return this; - } - - public ICurlyBracketTextWriter ExitBlock() { - this.WriteLine("}"); - return this; - } - - public ICurlyBracketTextWriter WriteLine(string text) => Write(text + '\n'); - - private void TryToPrintIndent_() { - if (this.hasIndentedOnCurrentLine_) { - return; - } - - this.hasIndentedOnCurrentLine_ = true; - for (var i = 0; i < this.indentLevel_; ++i) { - this.impl_.Write(" "); - } - } - } -} \ No newline at end of file diff --git a/Schema/src/util/text/SourceWriter.cs b/Schema/src/util/text/SourceWriter.cs new file mode 100644 index 0000000..a41bd16 --- /dev/null +++ b/Schema/src/util/text/SourceWriter.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; + +using CommunityToolkit.HighPerformance; + +namespace schema.util.text { + public interface ISourceWriter : IDisposable { + ISourceWriter Write(string text); + } + + public sealed class SourceWriter(TextWriter impl) : ISourceWriter { + private int indentLevel_; + private bool hasIndentedOnCurrentLine_; + + ~SourceWriter() => this.ReleaseUnmanagedResources_(); + + public void Dispose() { + this.ReleaseUnmanagedResources_(); + GC.SuppressFinalize(this); + } + + private void ReleaseUnmanagedResources_() { + impl.Dispose(); + } + + public ISourceWriter Write(string text) { + var lines = text.Split('\n'); + for (var i = 0; i < lines.Length; ++i) { + var line = lines[i]; + var isLastLine = !(i < lines.Length - 1); + + if (isLastLine && line.Length == 0) { + break; + } + + this.indentLevel_ -= line.Count('}'); + if (this.indentLevel_ < 0) { + throw new Exception("Exited an extra block!"); + } + + if (!isLastLine) { + this.TryToPrintIndent_(); + impl.WriteLine(line); + this.hasIndentedOnCurrentLine_ = false; + } else { + this.TryToPrintIndent_(); + impl.Write(line); + } + + this.indentLevel_ += line.Count('{'); + } + + return this; + } + + private void TryToPrintIndent_() { + if (this.hasIndentedOnCurrentLine_) { + return; + } + + this.hasIndentedOnCurrentLine_ = true; + for (var i = 0; i < this.indentLevel_; ++i) { + impl.Write(" "); + } + } + } +} \ No newline at end of file diff --git a/Schema/src/util/text/SourceWriterExtensions.cs b/Schema/src/util/text/SourceWriterExtensions.cs new file mode 100644 index 0000000..8207558 --- /dev/null +++ b/Schema/src/util/text/SourceWriterExtensions.cs @@ -0,0 +1,18 @@ +namespace schema.util.text { + public static class SourceWriterExtensions { + public static ISourceWriter EnterBlock(this ISourceWriter sw, + string prefix = "") { + if (prefix.Length > 0) { + prefix = $"{prefix} "; + } + + return sw.WriteLine($"{prefix}{{"); + } + + public static ISourceWriter ExitBlock(this ISourceWriter sw) + => sw.WriteLine("}"); + + public static ISourceWriter WriteLine(this ISourceWriter sw, string text) + => sw.Write(text + '\n'); + } +} \ No newline at end of file diff --git a/Schema/src/util/text/SourceWriterSymbolExtensions.cs b/Schema/src/util/text/SourceWriterSymbolExtensions.cs new file mode 100644 index 0000000..37567e7 --- /dev/null +++ b/Schema/src/util/text/SourceWriterSymbolExtensions.cs @@ -0,0 +1,37 @@ +using System; + +using Microsoft.CodeAnalysis; + +using schema.util.symbols; + +namespace schema.util.text { + public static class SourceWriterSymbolExtensions { + public static void WriteNamespaceAndParentTypeBlocks( + this ISourceWriter sw, + INamedTypeSymbol symbol, + Action insideBlockHandler) { + var fullyQualifiedNamespace = symbol.GetFullyQualifiedNamespace(); + if (fullyQualifiedNamespace != null) { + sw.EnterBlock($"namespace {fullyQualifiedNamespace}"); + } + + var declaringTypes = symbol.GetDeclaringTypesDownward(); + foreach (var declaringType in declaringTypes) { + sw.EnterBlock(declaringType + .GetQualifiersAndNameAndGenericParametersFor()); + } + + insideBlockHandler(); + + // parent types + foreach (var _ in declaringTypes) { + sw.ExitBlock(); + } + + // namespace + if (fullyQualifiedNamespace != null) { + sw.ExitBlock(); + } + } + } +} \ No newline at end of file