Exemplo n.º 1
0
        private static void GenerateCloneMethod(
            CodeWriter codeWriter,
            CompilerOptions options,
            ITypeModel typeModel,
            Dictionary <Type, string> methodNameMap)
        {
            string typeName            = CSharpHelpers.GetCompilableTypeName(typeModel.ClrType);
            CodeGeneratedMethod method = typeModel.CreateCloneMethodBody(new CloneCodeGenContext("item", methodNameMap));

            if (!typeModel.ClrType.IsValueType)
            {
                typeName += "?";

                if (options.NullableWarnings == true)
                {
                    codeWriter.AppendLine("[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(\"item\")]");
                }
            }

            codeWriter.AppendLine(method.GetMethodImplAttribute());
            codeWriter.AppendLine($"public static {typeName} Clone({typeName} item)");
            using (codeWriter.WithBlock())
            {
                codeWriter.AppendLine(method.MethodBody);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Returns the fully qualified clone method name.
        /// </summary>
        public static string GenerateCloneMethodsForAssembly(
            CodeWriter writer,
            CompilerOptions options,
            Assembly assembly,
            TypeModelContainer container)
        {
            string @namespace = $"FlatSharp.Compiler.Generated";
            string className  = $"CloneHelpers_{Guid.NewGuid():n}";
            string methodName = "Clone";

            string fullyQualifiedMethodName = $"{@namespace}.{className}.{methodName}";

            HashSet <Type> seenTypes = new HashSet <Type>();

            foreach (var type in assembly.GetTypes())
            {
                if (type.IsNested)
                {
                    continue;
                }

                if (container.TryCreateTypeModel(type, out var typeModel))
                {
                    typeModel.TraverseObjectGraph(seenTypes);
                }
            }

            Dictionary <Type, string> methodNameMap = new Dictionary <Type, string>();

            foreach (var seenType in seenTypes)
            {
                methodNameMap[seenType] = fullyQualifiedMethodName;
            }

            writer.AppendLine($"namespace {@namespace}");
            using (writer.WithBlock())
            {
                writer.AppendLine($"internal static class {className}");
                using (writer.WithBlock())
                {
                    foreach (var seenType in seenTypes)
                    {
                        if (!container.TryCreateTypeModel(seenType, out ITypeModel? model))
                        {
                            ErrorContext.Current.RegisterError($"Unable to create type model for Type '{seenType.FullName}.'");
                            continue;
                        }

                        GenerateCloneMethod(writer, options, model, methodNameMap);
                    }
                }
            }

            return(fullyQualifiedMethodName);
        }
Exemplo n.º 3
0
 protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, string forFile, IReadOnlyDictionary <string, string> precompiledSerailizers)
 {
     writer.AppendLine($"namespace {this.Name}");
     writer.AppendLine($"{{");
     using (writer.IncreaseIndent())
     {
         foreach (var type in this.Children.Values)
         {
             type.WriteCode(writer, pass, forFile, precompiledSerailizers);
         }
     }
     writer.AppendLine($"}}");
 }
Exemplo n.º 4
0
 protected override void OnWriteCode(CodeWriter writer, CompileContext context)
 {
     writer.AppendLine($"namespace {this.Name}");
     writer.AppendLine($"{{");
     using (writer.IncreaseIndent())
     {
         foreach (var type in this.Children.Values)
         {
             type.WriteCode(writer, context);
         }
     }
     writer.AppendLine($"}}");
 }
Exemplo n.º 5
0
        public void WriteCopyConstructorLine(CodeWriter writer, string sourceName, BaseSchemaMember parent)
        {
            bool isBuiltIn = SchemaDefinition.TryResolveBuiltInType(this.FbsFieldType, out _);

            bool foundNodeType = parent.TryResolveName(this.FbsFieldType, out var nodeType);

            if (!isBuiltIn && !foundNodeType)
            {
                ErrorContext.Current.RegisterError($"Unable to resolve type '{this.FbsFieldType}' as a built in or defined type");
                return;
            }

            string selectStatement = this.GetLinqSelectStatement(isBuiltIn, nodeType);

            switch (this.VectorType)
            {
            case VectorType.IList:
            case VectorType.IReadOnlyList:
                writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}?{selectStatement}.ToList();");
                break;

            case VectorType.Array:
                writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}?{selectStatement}.ToArray();");
                break;

            case VectorType.Memory:
            case VectorType.ReadOnlyMemory:
                writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}.ToArray();");
                break;

            case VectorType.None:
            {
                if (isBuiltIn)
                {
                    writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name};");
                }
                else
                {
                    string cloneStatement = nodeType.GetCopyExpression($"{sourceName}.{this.Name}");
                    writer.AppendLine($"this.{this.Name} = {cloneStatement};");
                }
            }
            break;
            }
        }
Exemplo n.º 6
0
        protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, IReadOnlyDictionary <string, string> precompiledSerailizers)
        {
            writer.AppendLine($@"
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the FlatSharp FBS to C# compiler (source hash: {this.inputHash})
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
");

            writer.AppendLine("using System;");
            writer.AppendLine("using System.Collections.Generic;");
            writer.AppendLine("using System.Linq;");
            writer.AppendLine("using System.Runtime.CompilerServices;");
            writer.AppendLine("using FlatSharp;");
            writer.AppendLine("using FlatSharp.Attributes;");

            foreach (var child in this.Children.Values)
            {
                child.WriteCode(writer, pass, precompiledSerailizers);
            }
        }
        protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, IReadOnlyDictionary <string, string> precompiledSerailizers)
        {
            this.AssignIndexes();

            string attribute = this.IsTable ? "[FlatBufferTable]" : "[FlatBufferStruct]";

            writer.AppendLine(attribute);
            writer.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]");
            writer.AppendLine($"public partial class {this.Name} : object");
            writer.AppendLine($"{{");

            using (writer.IncreaseIndent())
            {
                foreach (var field in this.Fields)
                {
                    if (!this.IsTable && field.Deprecated)
                    {
                        ErrorContext.Current?.RegisterError($"FlatBuffer structs may not have deprecated fields.");
                    }

                    field.WriteField(writer, this);
                }

                if (pass == CodeWritingPass.SecondPass && precompiledSerailizers != null && this.RequestedSerializer != null)
                {
                    if (precompiledSerailizers.TryGetValue(this.FullName, out string serializer))
                    {
                        writer.AppendLine($"public static ISerializer<{this.FullName}> Serializer {{ get; }} = new {RoslynSerializerGenerator.GeneratedSerializerClassName}().AsISerializer();");
                        writer.AppendLine(string.Empty);
                        writer.AppendLine($"#region Serializer for {this.FullName}");
                        writer.AppendLine(serializer);
                        writer.AppendLine($"#endregion");
                    }
                    else
                    {
                        ErrorContext.Current.RegisterError($"Table {this.FullName} requested serializer, but none was found.");
                    }
                }
            }

            writer.AppendLine($"}}");
        }
Exemplo n.º 8
0
        private void WriteField(
            CodeWriter writer,
            string clrTypeName,
            string defaultValue,
            string name,
            string accessModifier = "public")
        {
            string defaultValueAttribute  = string.Empty;
            string defaultValueAssignment = string.Empty;
            string isKey        = string.Empty;
            string sortedVector = string.Empty;
            string isDeprecated = string.Empty;

            if (!string.IsNullOrEmpty(defaultValue))
            {
                defaultValueAttribute  = $", DefaultValue = {defaultValue}";
                defaultValueAssignment = $" = {defaultValue};";
            }

            if (this.SortedVector)
            {
                sortedVector = ", SortedVector = true";
            }

            if (this.IsKey)
            {
                isKey = ", Key = true";
            }

            if (this.Deprecated)
            {
                isDeprecated = ", Deprecated = true";
            }

            writer.AppendLine($"[FlatBufferItem({this.Index}{defaultValueAttribute}{isDeprecated}{sortedVector}{isKey})]");
            writer.AppendLine($"{accessModifier} virtual {clrTypeName} {name} {{ get; set; }}{defaultValueAssignment}");
        }
Exemplo n.º 9
0
 protected override void OnWriteCode(CodeWriter writer, CodeWritingPass pass, IReadOnlyDictionary <string, string> precompiledSerailizers)
 {
     writer.AppendLine($"[FlatBufferEnum(typeof({this.ClrUnderlyingType}))]");
     writer.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]");
     writer.AppendLine($"public enum {this.Name} : {this.ClrUnderlyingType}");
     writer.AppendLine($"{{");
     using (writer.IncreaseIndent())
     {
         foreach (var item in this.nameValuePairs)
         {
             writer.AppendLine($"{item.Key} = {item.Value},");
         }
     }
     writer.AppendLine($"}}");
     writer.AppendLine(string.Empty);
 }
Exemplo n.º 10
0
        public void EmitStructVector(TableOrStructDefinition parent, CodeWriter writer, CompileContext context)
        {
            string typeName = parent.ResolveTypeName(this.FbsTypeName, context, out ITypeModel? typeModel);

            writer.AppendLine($"public {this.ClassName} {this.Name} {{ get; }}");
            writer.AppendLine();

            // class is next.
            writer.AppendLine($"public sealed partial class {this.ClassName} : System.Collections.Generic.IEnumerable<{typeName}>");
            using (writer.WithBlock())
            {
                writer.AppendLine($"private readonly {parent.Name} item;");

                // ctor
                writer.AppendLine();
                writer.AppendLine($"public {this.ClassName}({parent.Name} item)");
                using (writer.WithBlock())
                {
                    writer.AppendLine($"this.item = item;");
                }

                writer.AppendLine($"public int Count => {this.PropertyNames.Count};");

                // indexer
                writer.AppendLine();
                writer.AppendLine($"public {typeName} this[int index]");
                using (writer.WithBlock())
                {
                    writer.AppendLine("get");
                    using (writer.WithBlock())
                    {
                        writer.AppendLine("var thisItem = this.item;");
                        writer.AppendLine("switch (index)");
                        using (writer.WithBlock())
                        {
                            for (int i = 0; i < this.PropertyNames.Count; ++i)
                            {
                                writer.AppendLine($"case {i}: return thisItem.{this.PropertyNames[i]};");
                            }

                            writer.AppendLine($"default: throw new IndexOutOfRangeException();");
                        }
                    }

                    writer.AppendLine();

                    writer.AppendLine("set");
                    using (writer.WithBlock())
                    {
                        writer.AppendLine("var thisItem = this.item;");
                        writer.AppendLine("switch (index)");
                        using (writer.WithBlock())
                        {
                            for (int i = 0; i < this.PropertyNames.Count; ++i)
                            {
                                writer.AppendLine($"case {i}: thisItem.{this.PropertyNames[i]} = value; break;");
                            }

                            writer.AppendLine($"default: throw new IndexOutOfRangeException();");
                        }
                    }
                }

                writer.AppendLine("System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();");
                writer.AppendLine();
                writer.AppendLine($"public System.Collections.Generic.IEnumerator<{typeName}> GetEnumerator()");
                using (writer.WithBlock())
                {
                    writer.AppendLine("var thisItem = this.item;");
                    for (int i = 0; i < this.PropertyNames.Count; ++i)
                    {
                        writer.AppendLine($"yield return thisItem.{this.PropertyNames[i]};");
                    }

                    if (this.PropertyNames.Count == 0)
                    {
                        writer.AppendLine("yield break;");
                    }
                }

                string arrayOrSpanType = $"{typeName}[]";
                if (typeModel is not null &&
                    typeModel.ClassifyContextually(FlatBufferSchemaType.Struct).IsRequiredValue())
                {
                    arrayOrSpanType = $"ReadOnlySpan<{typeName}>";
                }

                foreach (var collectionType in new[] { arrayOrSpanType, $"IReadOnlyList<{typeName}>" })
                {
                    writer.AppendMethodSummaryComment($"Deep copies the first {this.PropertyNames.Count} items from the source into this struct vector.");
                    writer.AppendLine($"public void CopyFrom({collectionType} source)");
                    using (writer.WithBlock())
                    {
                        writer.AppendLine("var thisItem = this.item;");

                        // Load in reverse so that the JIT can just do a bounds check on the very first item.
                        // This also requries the parameter being a local variable instead of a param.
                        writer.AppendLine("var s = source;");
                        for (int i = this.PropertyNames.Count - 1; i >= 0; --i)
                        {
                            writer.AppendLine($"thisItem.{this.PropertyNames[i]} = {context.FullyQualifiedCloneMethodName}(s[{i}]);");
                        }
                    }
                }
            }
        }
Exemplo n.º 11
0
 public void EmitStructVectorInitializer(CodeWriter writer)
 {
     writer.AppendLine($"this.{this.Name} = new {this.ClassName}(this);");
 }
Exemplo n.º 12
0
        protected override void OnWriteCode(CodeWriter writer, CompileContext context)
        {
            this.AssignIndexes();

            string attribute = "[FlatBufferStruct]";

            if (this.IsTable)
            {
                if (string.IsNullOrEmpty(this.FileIdentifier))
                {
                    attribute = "[FlatBufferTable]";
                }
                else
                {
                    attribute = $"[FlatBufferTable({nameof(FlatBufferTableAttribute.FileIdentifier)} = \"{this.FileIdentifier}\")]";
                }
            }

            writer.AppendLine(attribute);
            writer.AppendLine("[System.Runtime.CompilerServices.CompilerGenerated]");
            writer.AppendLine($"public partial class {this.Name} : object");
            writer.AppendLine($"{{");

            using (writer.IncreaseIndent())
            {
                // Default ctor.
                var defaultCtorKind = this.DefaultConstructorKind ?? Compiler.DefaultConstructorKind.Public;
                if (defaultCtorKind != Compiler.DefaultConstructorKind.None)
                {
                    if (defaultCtorKind == Compiler.DefaultConstructorKind.PublicObsolete)
                    {
                        writer.AppendLine("[Obsolete]");
                    }

                    writer.AppendLine($"public {this.Name}()");
                    using (writer.WithBlock())
                    {
                        foreach (var field in this.Fields)
                        {
                            field.WriteDefaultConstructorLine(writer, context);
                        }

                        this.EmitStructVectorInitializations(writer);
                        writer.AppendLine("this.OnInitialized(null);");
                    }
                }
                else if (!this.IsTable)
                {
                    ErrorContext.Current.RegisterError("Structs must have default constructors.");
                }

                writer.AppendLine("#pragma warning disable CS8618"); // NULL FORGIVING
                writer.AppendLine($"protected {this.Name}({nameof(FlatBufferDeserializationContext)} context)");
                using (writer.WithBlock())
                {
                    this.EmitStructVectorInitializations(writer);
                    writer.AppendLine("this.OnInitialized(context);");
                }
                writer.AppendLine("#pragma warning restore CS8618"); // NULL FORGIVING

                // Copy constructor.
                writer.AppendLine($"public {this.Name}({this.Name} source)");
                using (writer.WithBlock())
                {
                    foreach (var field in this.Fields)
                    {
                        field.WriteCopyConstructorLine(writer, "source", context);
                    }

                    this.EmitStructVectorInitializations(writer);
                    writer.AppendLine("this.OnInitialized(null);");
                }

                writer.AppendLine($"partial void OnInitialized({nameof(FlatBufferDeserializationContext)}? context);");

                foreach (var field in this.Fields)
                {
                    field.WriteField(writer, this, context);
                }

                foreach (var structVector in this.StructVectors)
                {
                    structVector.EmitStructVector(this, writer, context);
                }

                if (context.CompilePass >= CodeWritingPass.SerializerGeneration && this.RequestedSerializer is not null)
                {
                    // generate the serializer.
                    string serializer = this.GenerateSerializerForType(
                        context,
                        this.RequestedSerializer.Value);

                    writer.AppendLine($"public static ISerializer<{this.FullName}> {SerializerPropertyName} {{ get; }} = new {RoslynSerializerGenerator.GeneratedSerializerClassName}().AsISerializer();");
                    writer.AppendLine(string.Empty);
                    writer.AppendLine($"#region Serializer for {this.FullName}");
                    writer.AppendLine(serializer);
                    writer.AppendLine($"#endregion");
                }
            }

            writer.AppendLine($"}}");
        }
Exemplo n.º 13
0
        private void WriteField(
            CodeWriter writer,
            string clrTypeName,
            string defaultValue,
            string name,
            TableOrStructDefinition parent)
        {
            string defaultValueAttribute  = string.Empty;
            string defaultValueAssignment = string.Empty;
            string isKey        = string.Empty;
            string sortedVector = string.Empty;
            string isDeprecated = string.Empty;

            if (!string.IsNullOrEmpty(defaultValue))
            {
                defaultValueAttribute  = $", DefaultValue = {defaultValue}";
                defaultValueAssignment = $" = {defaultValue};";
            }

            if (this.SortedVector)
            {
                sortedVector = ", SortedVector = true";
            }

            if (this.IsKey)
            {
                isKey = ", Key = true";
            }

            if (this.Deprecated)
            {
                isDeprecated = ", Deprecated = true";
            }

            bool isNonVirtual = false;

            if (this.NonVirtual != null)
            {
                isNonVirtual = this.NonVirtual.Value;
            }
            else if (parent.NonVirtual != null)
            {
                isNonVirtual = parent.NonVirtual.Value;
            }

            string accessModifier = this.SetterKind switch
            {
                SetterKind.Public => string.Empty, // setter has same access as getter.
                SetterKind.Protected => "protected",
                SetterKind.ProtectedInternal => "protected internal",
                SetterKind.None => null,
                _ => string.Empty,
            };

            string setter = $"{accessModifier} set;";

            if (accessModifier == null)
            {
                setter = string.Empty;
            }

            writer.AppendLine($"[FlatBufferItem({this.Index}{defaultValueAttribute}{isDeprecated}{sortedVector}{isKey})]");
            writer.AppendLine($"public {(isNonVirtual ? string.Empty : "virtual ")}{clrTypeName} {name} {{ get; {setter} }}{defaultValueAssignment}");
        }
Exemplo n.º 14
0
        public void EmitStructVector(TableOrStructDefinition parent, CodeWriter writer, CompileContext context)
        {
            string typeName = parent.ResolveTypeName(this.FbsTypeName, context);

            string className = $"{this.Name}Vector";

            // two parts: property definition and class definition.
            writer.AppendLine($"private {className}? _{this.Name};");
            writer.AppendLine($"public {className} {this.Name} => (this._{this.Name} ??= new {className}(this));");
            writer.AppendLine();

            // class is next.
            writer.AppendLine($"public sealed partial class {className} : System.Collections.Generic.IEnumerable<{typeName}>");
            using (writer.WithBlock())
            {
                writer.AppendLine($"private readonly {parent.Name} item;");

                // ctor
                writer.AppendLine();
                writer.AppendLine($"public {className}({parent.Name} item)");
                using (writer.WithBlock())
                {
                    writer.AppendLine($"this.item = item;");
                }

                writer.AppendLine($"public int Count => {this.PropertyNames.Count};");

                // indexer
                writer.AppendLine();
                writer.AppendLine($"public {typeName} this[int index]");
                using (writer.WithBlock())
                {
                    writer.AppendLine("get");
                    using (writer.WithBlock())
                    {
                        writer.AppendLine("switch (index)");
                        using (writer.WithBlock())
                        {
                            for (int i = 0; i < this.PropertyNames.Count; ++i)
                            {
                                writer.AppendLine($"case {i}: return this.item.{this.PropertyNames[i]};");
                            }

                            writer.AppendLine($"default: throw new IndexOutOfRangeException();");
                        }
                    }

                    writer.AppendLine();

                    writer.AppendLine("set");
                    using (writer.WithBlock())
                    {
                        writer.AppendLine("switch (index)");
                        using (writer.WithBlock())
                        {
                            for (int i = 0; i < this.PropertyNames.Count; ++i)
                            {
                                writer.AppendLine($"case {i}: this.item.{this.PropertyNames[i]} = value; break;");
                            }

                            writer.AppendLine($"default: throw new IndexOutOfRangeException();");
                        }
                    }
                }

                writer.AppendLine("System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();");
                writer.AppendLine();
                writer.AppendLine($"public System.Collections.Generic.IEnumerator<{typeName}> GetEnumerator()");
                using (writer.WithBlock())
                {
                    for (int i = 0; i < this.PropertyNames.Count; ++i)
                    {
                        writer.AppendLine($"yield return this.item.{this.PropertyNames[i]};");
                    }

                    if (this.PropertyNames.Count == 0)
                    {
                        writer.AppendLine("yield break;");
                    }
                }
            }
        }