private static string CreateCSharp(BaseSchemaMember rootNode) { if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } var tablesNeedingSerializers = new List <TableOrStructDefinition>(); var rpcDefinitions = new List <RpcDefinition>(); FindItemsRequiringSecondCodePass(rootNode, tablesNeedingSerializers, rpcDefinitions); if (tablesNeedingSerializers.Count == 0 && rpcDefinitions.Count == 0) { // Hey, no serializers or RPCs. We're all done. Go ahead and return the code we already generated. CodeWriter tempWriter = new CodeWriter(); rootNode.WriteCode(tempWriter, CodeWritingPass.SecondPass, rootNode.DeclaringFile, new Dictionary <string, string>()); if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } return(tempWriter.ToString()); } // Compile the assembly so that we may generate serializers for the data contracts defined in this FBS file.; // Compile with firstpass here to include all data (even stuff from includes). CodeWriter writer = new CodeWriter(); rootNode.WriteCode(writer, CodeWritingPass.FirstPass, rootNode.DeclaringFile, new Dictionary <string, string>()); if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } string code = writer.ToString(); var(assembly, _, _) = RoslynSerializerGenerator.CompileAssembly(code, true); Dictionary <string, string> generatedSerializers = new Dictionary <string, string>(); foreach (var definition in tablesNeedingSerializers) { generatedSerializers[definition.FullName] = GenerateSerializerForType(assembly, definition); } writer = new CodeWriter(); rootNode.WriteCode(writer, CodeWritingPass.SecondPass, rootNode.DeclaringFile, generatedSerializers); if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } string rawCode = writer.ToString(); string formattedCode = RoslynSerializerGenerator.GetFormattedText(rawCode); return(formattedCode); }
public TableOrStructDefinition( string name, FlatBufferDeserializationOption?serializerFlags, BaseSchemaMember parent) : base(name, parent) { this.RequestedSerializer = serializerFlags; }
private static string CreateCSharp(BaseSchemaMember rootNode, CompilerOptions options) { ErrorContext.Current.ThrowIfHasErrors(); if (string.IsNullOrEmpty(rootNode.DeclaringFile)) { throw new InvalidFbsFileException("FlatSharp.Internal: RootNode missing declaring file"); } Assembly? assembly = null; CodeWriter writer = new CodeWriter(); var steps = new[] { CodeWritingPass.Initialization, CodeWritingPass.PropertyModeling, CodeWritingPass.SerializerGeneration, CodeWritingPass.RpcGeneration, }; foreach (var step in steps) { var localOptions = options; if (step <= CodeWritingPass.PropertyModeling) { localOptions = localOptions with { NullableWarnings = false }; } if (step > CodeWritingPass.Initialization) { string code = writer.ToString(); (assembly, _, _) = RoslynSerializerGenerator.CompileAssembly(code, true); } writer = new CodeWriter(); rootNode.WriteCode( writer, new CompileContext { CompilePass = step, Options = localOptions, RootFile = rootNode.DeclaringFile, PreviousAssembly = assembly, TypeModelContainer = TypeModelContainer.CreateDefault(), }); ErrorContext.Current.ThrowIfHasErrors(); } string rawCode = writer.ToString(); string formattedCode = RoslynSerializerGenerator.GetFormattedText(rawCode); return(formattedCode); } }
private static string CreateCSharp(string fbsSchema, string inputHash) { BaseSchemaMember rootNode = ParseSyntax(fbsSchema, inputHash); if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } // Create the first pass of the code. This pass includes the data contracts from the FBS file. // If the schema requests a pregenerated serializer, then we'll need to load this code, generate // the serializer, and then rebuild it. CodeWriter writer = new CodeWriter(); rootNode.WriteCode(writer, CodeWritingPass.FirstPass, null); if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } string code = writer.ToString(); var tablesNeedingSerializers = new List <TableOrStructDefinition>(); var rpcDefinitions = new List <RpcDefinition>(); FindItemsRequiringSecondCodePass(rootNode, tablesNeedingSerializers, rpcDefinitions); if (tablesNeedingSerializers.Count == 0 && rpcDefinitions.Count == 0) { // Hey, no serializers or RPCs. We're all done. Go ahead and return the code we already generated. return(code); } // Compile the assembly so that we may generate serializers for the data contracts defined in this FBS file. var(assembly, _, _) = RoslynSerializerGenerator.CompileAssembly(code, true); Dictionary <string, string> generatedSerializers = new Dictionary <string, string>(); foreach (var definition in tablesNeedingSerializers) { generatedSerializers[definition.FullName] = GenerateSerializerForType(assembly, definition); } writer = new CodeWriter(); rootNode.WriteCode(writer, CodeWritingPass.SecondPass, generatedSerializers); if (ErrorContext.Current.Errors.Any()) { throw new InvalidFbsFileException(ErrorContext.Current.Errors); } string rawCode = writer.ToString(); string formattedCode = RoslynSerializerGenerator.GetFormattedText(rawCode); return(formattedCode); }
protected BaseSchemaMember(string name, BaseSchemaMember parent) { this.children = new Dictionary <string, BaseSchemaMember>(); this.Parent = parent; this.Name = name; this.FullName = string.Empty; if (this.Parent != null) { this.FullName = this.Parent.GetType() != typeof(RootNodeDefinition) ? $"{this.Parent.FullName}.{this.Name}" : this.Name; } }
private string GetLinqSelectStatement(bool isBuiltIn, BaseSchemaMember nodeType) { if (isBuiltIn) { return(string.Empty); } else { string cloneStatement = nodeType.GetCopyExpression("x"); return($".Select(x => {cloneStatement})"); } }
public void WriteField(CodeWriter writer, BaseSchemaMember schemaDefinition) { ErrorContext.Current.WithScope(this.Name, () => { bool isVector = this.VectorType != VectorType.None; EnumDefinition enumDefinition = null; if (schemaDefinition.TryResolveName(this.FbsFieldType, out var typeDefinition)) { enumDefinition = typeDefinition as EnumDefinition; } string defaultValue = string.Empty; string clrType; bool isPrimitive = SchemaDefinition.TryResolveBuiltInScalarType(this.FbsFieldType, out IBuiltInScalarType builtInType); if (isPrimitive) { clrType = builtInType.CSharpTypeName; } else { clrType = typeDefinition?.GlobalName ?? this.FbsFieldType; } if (!string.IsNullOrEmpty(this.DefaultValue)) { if (isPrimitive) { defaultValue = builtInType.FormatLiteral(this.DefaultValue); } else if (enumDefinition != null) { if (enumDefinition.NameValuePairs.ContainsKey(this.DefaultValue)) { // Referenced by name. defaultValue = $"{clrType}.{this.DefaultValue}"; } else { defaultValue = $"({clrType}){enumDefinition.UnderlyingType.FormatLiteral(this.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}'."); } } this.WriteField(writer, this.GetClrTypeName(schemaDefinition), defaultValue, this.Name); }); }
public string GetClrTypeName(BaseSchemaMember baseMember) { string clrType; if (SchemaDefinition.TryResolveBuiltInScalarType(this.FbsFieldType, out IBuiltInScalarType builtInType)) { clrType = builtInType.CSharpTypeName; } else { if (baseMember.TryResolveName(this.FbsFieldType, out var typeDefinition)) { if (typeDefinition is UnionDefinition unionDef) { clrType = unionDef.ClrTypeName; } else { clrType = typeDefinition.GlobalName; } } else { clrType = this.FbsFieldType; } } switch (this.VectorType) { case VectorType.Array: return($"{clrType}[]"); case VectorType.IList: return($"IList<{clrType}>"); case VectorType.IReadOnlyList: return($"IReadOnlyList<{clrType}>"); case VectorType.Memory: return($"Memory<{clrType}>"); case VectorType.ReadOnlyMemory: return($"ReadOnlyMemory<{clrType}>"); case VectorType.None: return(clrType); default: throw new InvalidOperationException($"Unexpected value for vectortype: '{this.VectorType}'"); } }
private static BaseSchemaMember ParseSyntax(string fbsSchema, string inputHash) { AntlrInputStream input = new AntlrInputStream(fbsSchema); FlatBuffersLexer lexer = new FlatBuffersLexer(input); CommonTokenStream tokenStream = new CommonTokenStream(lexer); FlatBuffersParser parser = new FlatBuffersParser(tokenStream); parser.AddErrorListener(new CustomErrorListener()); SchemaVisitor visitor = new SchemaVisitor(inputHash); BaseSchemaMember rootNode = visitor.Visit(parser.schema()); return(rootNode); }
public void WriteCopyConstructorLine(CodeWriter writer, string sourceName, BaseSchemaMember parent) { bool isBuiltIn = SchemaDefinition.TryResolve(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.IIndexedVector: writer.AppendLine($"this.{this.Name} = {sourceName}.{this.Name}?.Clone(x => {nodeType.GetCopyExpression("x")});"); 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; } }
public void WriteField(CodeWriter writer, BaseSchemaMember schemaDefinition) { ErrorContext.Current.WithScope(this.Name, (Action)(() => { bool isVector = this.VectorType != VectorType.None; EnumDefinition enumDefinition = null; if (schemaDefinition.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}'."); } } this.WriteField(writer, this.GetClrTypeName(schemaDefinition), defaultValue, this.Name); })); }
private bool TryResolveDescendentsFromNode(BaseSchemaMember startNode, Span <string> parts, out BaseSchemaMember node) { node = startNode; while (node.Children.TryGetValue(parts[0], out node)) { if (parts.Length == 1) { return(true); } parts = parts.Slice(1); } return(false); }
public void AddChild(BaseSchemaMember child) { ErrorContext.Current.WithScope(this.Name, () => { if (!this.SupportsChildren) { ErrorContext.Current?.RegisterError($"Unable to add child to current context."); } if (this.children.ContainsKey(child.Name)) { ErrorContext.Current?.RegisterError($"Duplicate member name '{child.Name}'."); } this.children[child.Name] = child; }); }
/// <summary> /// Recursively find tables for which the schema has asked for us to generate serializers. /// </summary> private static void FindItemsRequiringSecondCodePass( BaseSchemaMember node, List <TableOrStructDefinition> tables, List <RpcDefinition> rpcs) { if (node is TableOrStructDefinition tableOrStruct) { if (tableOrStruct.RequestedSerializer != null) { tables.Add(tableOrStruct); } } else if (node is RpcDefinition rpc) { rpcs.Add(rpc); } foreach (var childNode in node.Children.Values) { FindItemsRequiringSecondCodePass(childNode, tables, rpcs); } }
/// <summary> /// Resolves a name according to the relative namespace path. /// </summary> public bool TryResolveName(string name, out BaseSchemaMember node) { Span <string> parts = name.Split('.'); // Go up to the first namespace node in the tree. BaseSchemaMember rootNode = this; while (!(rootNode is NamespaceDefinition) && !(rootNode is RootNodeDefinition)) { rootNode = rootNode.Parent; } if (this.TryResolveDescendentsFromNode(rootNode, parts, out node)) { return(true); } while (rootNode.Parent != null) { rootNode = rootNode.Parent; } return(this.TryResolveDescendentsFromNode(rootNode, parts, out node)); }
public EnumDefinition(string typeName, string underlyingTypeName, BaseSchemaMember parent) : base(typeName, parent) { this.FbsUnderlyingType = underlyingTypeName; this.ClrUnderlyingType = SchemaDefinition.ResolvePrimitiveType(underlyingTypeName); }
public EnumVisitor(BaseSchemaMember parent) { this.parent = parent; }
public NamespaceDefinition(string name, BaseSchemaMember parent) : base(name, parent) { }
public FileIdentifierVisitor(BaseSchemaMember parent) { this.parent = parent; }
public UnionVisitor(BaseSchemaMember parent) { this.parent = parent; }
public EnumDefinition(string typeName, string underlyingTypeName, BaseSchemaMember parent) : base(typeName, parent) { this.FbsUnderlyingType = underlyingTypeName; this.UnderlyingType = SchemaDefinition.ResolveBuiltInScalarType(underlyingTypeName); }
public string GetClrTypeName(BaseSchemaMember baseMember) { string clrType; string sortKeyType = null; if (SchemaDefinition.TryResolve(this.FbsFieldType, out ITypeModel builtInType)) { clrType = builtInType.ClrType.FullName; } else { if (baseMember.TryResolveName(this.FbsFieldType, out var typeDefinition)) { if (typeDefinition is UnionDefinition unionDef) { clrType = unionDef.ClrTypeName; } else { clrType = typeDefinition.GlobalName; } if (typeDefinition is TableOrStructDefinition tableOrStruct && tableOrStruct.IsTable) { sortKeyType = tableOrStruct.Fields.FirstOrDefault(x => x.IsKey)?.GetClrTypeName(baseMember); } } else { clrType = this.FbsFieldType; } } if (this.IsOptionalScalar) { // nullable. clrType = $"System.Nullable<{clrType}>"; } else if (this.SharedString) { clrType = $"global::{typeof(SharedString).FullName}"; } switch (this.VectorType) { case VectorType.Array: return($"{clrType}[]"); case VectorType.IList: return($"IList<{clrType}>"); case VectorType.IReadOnlyList: return($"IReadOnlyList<{clrType}>"); case VectorType.Memory: return($"Memory<{clrType}>"); case VectorType.ReadOnlyMemory: return($"ReadOnlyMemory<{clrType}>"); case VectorType.IIndexedVector: if (string.IsNullOrWhiteSpace(sortKeyType)) { ErrorContext.Current.RegisterError($"Unable to determine key type for table {clrType}. Please make sure a property has the 'Key' metadata."); } return($"IIndexedVector<{sortKeyType}, {clrType}>"); case VectorType.None: return(clrType); default: throw new InvalidOperationException($"Unexpected value for vectortype: '{this.VectorType}'"); } }
public FileIdentifierDefinition(string name, BaseSchemaMember parent) : base(name, parent) { }
public TypeVisitor(BaseSchemaMember parent) { this.parent = parent; }
public TableOrStructDefinition( string name, BaseSchemaMember parent) : base(name, parent) { }
public UnionDefinition(string name, BaseSchemaMember parent) : base(name, parent) { }
public EnumDefinition(string typeName, string underlyingTypeName, BaseSchemaMember parent) : base(typeName, parent) { this.FbsUnderlyingType = underlyingTypeName; }