예제 #1
0
        // TODO: consider moving to TableOrStructDefinition.
        private static string GenerateSerializerForType(Assembly assembly, TableOrStructDefinition tableOrStruct)
        {
            CSharpHelpers.ConvertProtectedInternalToProtected = false;
            try
            {
                Type type      = assembly.GetType(tableOrStruct.FullName);
                var  options   = new FlatBufferSerializerOptions(tableOrStruct.RequestedSerializer.Value);
                var  generator = new RoslynSerializerGenerator(options, TypeModelContainer.CreateDefault());

                var method = generator
                             .GetType()
                             .GetMethod(nameof(RoslynSerializerGenerator.GenerateCSharp), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                             .MakeGenericMethod(type);

                try
                {
                    string code = (string)method.Invoke(generator, new[] { "private" });
                    return(code);
                }
                catch (TargetInvocationException ex)
                {
                    ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                    throw;
                }
            }
            finally
            {
                CSharpHelpers.ConvertProtectedInternalToProtected = true;
            }
        }
예제 #2
0
        public void WriteField(CodeWriter writer, TableOrStructDefinition parent)
        {
            ErrorContext.Current.WithScope(this.Name, (Action)(() =>
            {
                bool isVector = this.VectorType != VectorType.None;
                EnumDefinition enumDefinition = null;

                if (parent.TryResolveName(this.FbsFieldType, out var typeDefinition))
                {
                    enumDefinition = typeDefinition as EnumDefinition;
                }

                string defaultValue = string.Empty;
                string clrType;
                bool isBuiltInType = SchemaDefinition.TryResolve(this.FbsFieldType, out ITypeModel builtInType);

                if (isBuiltInType)
                {
                    clrType = builtInType.ClrType.FullName;
                }
                else
                {
                    clrType = typeDefinition?.GlobalName ?? this.FbsFieldType;
                }

                if (!string.IsNullOrEmpty(this.DefaultValue))
                {
                    if (isBuiltInType && builtInType.TryFormatStringAsLiteral(this.DefaultValue, out defaultValue))
                    {
                        // intentionally left blank.
                    }
                    else if (enumDefinition?.NameValuePairs.ContainsKey(this.DefaultValue) == true)
                    {
                        // Also ok.
                        defaultValue = $"{clrType}.{this.DefaultValue}";
                    }
                    else if (enumDefinition?.UnderlyingType.TryFormatStringAsLiteral(this.DefaultValue, out defaultValue) == true)
                    {
                        defaultValue = $"({clrType})({defaultValue})";
                    }
                    else
                    {
                        ErrorContext.Current?.RegisterError($"Only primitive types and enums may have default values. Field '{this.Name}' declares a default value but has type '{this.FbsFieldType}'.");
                    }
                }

                if (this.SetterKind == SetterKind.None && this.NonVirtual == true)
                {
                    ErrorContext.Current?.RegisterError($"NonVirtual:true cannot be combined with setter:None.");
                }

                this.WriteField(writer, this.GetClrTypeName(parent), defaultValue, this.Name, parent);
            }));
        }
예제 #3
0
        // TODO: consider moving to TableOrStructDefinition.
        private static string GenerateSerializerForType(Assembly assembly, TableOrStructDefinition tableOrStruct)
        {
            Type type      = assembly.GetType(tableOrStruct.FullName);
            var  options   = new FlatBufferSerializerOptions(tableOrStruct.RequestedSerializer.Value);
            var  generator = new RoslynSerializerGenerator(options);

            var method = generator
                         .GetType()
                         .GetMethod(nameof(RoslynSerializerGenerator.GenerateCSharp), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                         .MakeGenericMethod(type);

            string code = (string)method.Invoke(generator, new[] { "private" });

            return(code);
        }
예제 #4
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}]);");
                        }
                    }
                }
            }
        }
예제 #5
0
 public FieldVisitor(TableOrStructDefinition parent)
 {
     this.parent = parent;
 }
예제 #6
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}");
        }
예제 #7
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;");
                    }
                }
            }
        }