public override void ExitTypeSpec(GolangParser.TypeSpecContext context) { string identifier = context.IDENTIFIER().GetText(); if (m_interfaceMethods.TryGetValue(context.type()?.typeLit()?.interfaceType(), out List <FunctionSignature> methods)) { m_interfaces.Add(GetUniqueIdentifier(m_interfaces, identifier), new InterfaceInfo { Name = identifier, Methods = methods.ToArray() }); } else if (m_structFields.TryGetValue(context.type()?.typeLit()?.structType(), out List <FieldInfo> fields)) { m_structs.Add(GetUniqueIdentifier(m_structs, identifier), new StructInfo { Name = identifier, Fields = fields.ToArray() }); } }
public override void ExitTypeSpec(GolangParser.TypeSpecContext context) { // typeSpec // : IDENTIFIER type if (m_firstTypeSpec) { m_firstTypeSpec = false; string comments = CheckForCommentsLeft(context, preserveLineFeeds: m_inFunction); if (!string.IsNullOrEmpty(comments)) { m_targetFile.Append(FixForwardSpacing(comments)); } } string originalIdentifier = context.IDENTIFIER().GetText(); string scope = char.IsUpper(originalIdentifier[0]) ? "public" : "private"; string target = Path.GetFileNameWithoutExtension(TargetFileName); string identifier = SanitizedIdentifier(originalIdentifier); // TODO: Sub-function strategy, declare directly prior to function using PushBlock / PopBlock operations and a new replacement marker if (m_inFunction) { AddWarning(context, $"Type specification made from within function \"{m_currentFunctionName}\" - this is will not compile in C#"); } if (Metadata.Interfaces.TryGetValue(originalIdentifier, out InterfaceInfo interfaceInfo)) { // Handle interface type declaration string ancillaryInterfaceFileName = Path.Combine(TargetFilePath, $"{target}_{identifier}Interface.cs"); FunctionSignature[] localFunctions = interfaceInfo.GetLocalMethods().ToArray(); List <FunctionSignature> allFunctions = localFunctions.ToList(); RecurseInheritedInterfaces(context, originalIdentifier, interfaceInfo, allFunctions); using (StreamWriter writer = File.CreateText(ancillaryInterfaceFileName)) { writer.Write(new InterfaceTypeTemplate { NamespacePrefix = PackageNamespace, NamespaceHeader = m_namespaceHeader, NamespaceFooter = m_namespaceFooter, PackageName = Package, InterfaceName = identifier, Scope = scope, Interface = interfaceInfo, Functions = allFunctions, UsingStatements = m_usingStatements } .TransformText()); } // Track file name associated with package AddFileToPackage(Package, ancillaryInterfaceFileName, PackageNamespace); string inheritedInterfaces = interfaceInfo.GenerateInheritedInterfaceList(); if (inheritedInterfaces.Length > 0) { inheritedInterfaces = $" : {inheritedInterfaces}"; } m_targetFile.AppendLine($"{Spacing()}{scope} partial interface {identifier}{inheritedInterfaces}"); m_targetFile.AppendLine($"{Spacing()}{{"); foreach (FunctionSignature function in localFunctions) { m_targetFile.Append($"{Spacing(1)}{function.Signature.GenerateResultSignature()} {SanitizedIdentifier(function.Name)}({function.Signature.GenerateParametersSignature(false)});{(string.IsNullOrEmpty(function.Comments) ? Environment.NewLine : function.Comments)}"); } m_targetFile.Append($"{Spacing()}}}{CheckForBodyCommentsRight(context)}"); } else if (Metadata.Structs.TryGetValue(originalIdentifier, out StructInfo structInfo)) { // Handle struct type declaration string ancillaryStructFileName = Path.Combine(TargetFilePath, $"{target}_{identifier}Struct.cs"); Dictionary <string, List <FunctionSignature> > promotedFunctions = new Dictionary <string, List <FunctionSignature> >(StringComparer.Ordinal); HashSet <string> inheritedTypeNames = new HashSet <string>(StringComparer.Ordinal); RecurseInheritedInterfaces(context, originalIdentifier, structInfo, promotedFunctions, inheritedTypeNames); Dictionary <string, List <FieldInfo> > promotedFields = new Dictionary <string, List <FieldInfo> >(StringComparer.Ordinal); HashSet <string> promotedStructs = new HashSet <string>(StringComparer.Ordinal); SearchPromotedStructFields(context, originalIdentifier, structInfo, inheritedTypeNames, promotedFields, promotedStructs); // Mark private structures as internal so that conversion function can be accessed from builtin functions if (scope.Equals("private")) { scope = "internal"; } using (StreamWriter writer = File.CreateText(ancillaryStructFileName)) { writer.Write(new StructTypeTemplate { NamespacePrefix = PackageNamespace, NamespaceHeader = m_namespaceHeader, NamespaceFooter = m_namespaceFooter, PackageName = Package, StructName = identifier, Scope = scope, StructFields = structInfo.Fields, PromotedStructs = promotedStructs, PromotedFunctions = promotedFunctions, PromotedFields = promotedFields, UsingStatements = m_usingStatements } .TransformText()); } // Track file name associated with package AddFileToPackage(Package, ancillaryStructFileName, PackageNamespace); List <FieldInfo> fields = new List <FieldInfo>(); foreach (FieldInfo field in structInfo.Fields) { if (field.IsPromoted && !inheritedTypeNames.Contains(field.Name)) { FieldInfo promotedStruct = field.Clone(); promotedStruct.Type.TypeName = $"ref {promotedStruct.Type.Name}"; promotedStruct.Name = $"{promotedStruct.Name} => ref {promotedStruct.Name}_{(promotedStruct.Type.IsPointer ? "ptr" : "val")}"; fields.Add(promotedStruct); } else { fields.Add(field); } } m_targetFile.AppendLine($"{Spacing()}{scope} partial struct {identifier}{GetInheritedTypeList(inheritedTypeNames)}"); m_targetFile.AppendLine($"{Spacing()}{{"); foreach (FieldInfo field in fields) { StringBuilder fieldDecl = new StringBuilder(); if (!string.IsNullOrWhiteSpace(field.Description)) { string description = field.Description.Trim(); if (description.Length > 2) { RequiredUsings.Add("System.ComponentModel"); fieldDecl.AppendLine($"{Spacing(1)}[Description({description})]"); } } fieldDecl.Append($"{Spacing(1)}public {field.Type.TypeName} {field.Name};{(string.IsNullOrEmpty(field.Comments) ? Environment.NewLine : field.Comments)}"); m_targetFile.Append(fieldDecl); } m_targetFile.Append($"{Spacing()}}}{CheckForBodyCommentsRight(context)}"); } else if (Types.TryGetValue(context.type(), out TypeInfo typeInfo)) { if (typeInfo.TypeClass == TypeClass.Function) { RequiredUsings.Decrement("System"); // Handle delegate type declaration string signature = typeInfo.TypeName; if (signature.Equals("Action", StringComparison.Ordinal)) { m_targetFile.Append($"{Spacing()}public delegate void {identifier}();"); m_targetFile.Append(CheckForBodyCommentsRight(context)); } else if (signature.StartsWith("Action<", StringComparison.Ordinal)) { signature = RemoveSurrounding(signature.Substring(6), "<", ">"); m_targetFile.Append($"{Spacing()}public delegate void {identifier}({signature});"); m_targetFile.Append(CheckForBodyCommentsRight(context)); } else if (signature.StartsWith("Func<", StringComparison.Ordinal)) { signature = RemoveSurrounding(signature.Substring(4), "<", ">"); string[] parts = signature.Split(','); if (parts.Length > 0) { string result = parts[parts.Length - 1]; signature = string.Join(", ", parts.Take(parts.Length - 1)); m_targetFile.Append($"{Spacing()}public delegate {result} {identifier}({signature});"); m_targetFile.Append(CheckForBodyCommentsRight(context)); } else { AddWarning(context, $"Could not determine function based delegate signature from \"{signature}\""); } } else { AddWarning(context, $"Could not determine delegate signature from \"{signature}\""); } } else { // Handle named type declaration, e.g., "type MyFloat float64" string ancillaryInheritedTypeFileName = Path.Combine(TargetFilePath, $"{target}_{identifier}StructOf({RemoveInvalidCharacters(typeInfo.TypeName)}).cs"); // TODO: The following works OK for a primitive type re-definition, but new templates will be needed for other inherited types, e.g., Map / Pointer / Array etc. using (StreamWriter writer = File.CreateText(ancillaryInheritedTypeFileName)) { writer.Write(new InheritedTypeTemplate { NamespacePrefix = PackageNamespace, NamespaceHeader = m_namespaceHeader, NamespaceFooter = m_namespaceFooter, PackageName = Package, StructName = identifier, Scope = scope, TypeName = typeInfo.TypeName } .TransformText()); } // Track file name associated with package AddFileToPackage(Package, ancillaryInheritedTypeFileName, PackageNamespace); m_targetFile.AppendLine($"{Spacing()}{scope} partial struct {identifier} // : {typeInfo.TypeName}"); m_targetFile.AppendLine($"{Spacing()}{{"); m_targetFile.Append($"{Spacing()}}}{CheckForBodyCommentsRight(context)}"); } } }