Ejemplo n.º 1
0
        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)}");
                }
            }
        }
Ejemplo n.º 2
0
        public override void ExitTypeSpec(GoParser.TypeSpecContext context)
        {
            // typeSpec
            //     : IDENTIFIER type

            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 (InFunction)
            {
                AddWarning(context, $"Type specification made from within function \"{CurrentFunctionName}\" - this is will not compile in C#");
            }

            if (m_typeIdentifierCount == 0 && m_typeMultipleDeclaration)
            {
                m_targetFile.Append(RemoveFirstLineFeed(CheckForCommentsLeft(context)));
            }

            if (Metadata.Interfaces.TryGetValue(originalIdentifier, out InterfaceInfo interfaceInfo))
            {
                // Handle interface type declaration
                string ancillaryInterfaceFileName = Path.Combine(TargetFilePath, $"{GetValidPathName($"{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()});{(string.IsNullOrWhiteSpace(function.Comments) ? Environment.NewLine : $" {function.Comments.TrimStart()}")}");
                }

                m_targetFile.Append($"{Spacing()}}}{CheckForCommentsRight(context)}");
            }
            else if (Metadata.Structs.TryGetValue(originalIdentifier, out StructInfo structInfo))
            {
                // Handle struct type declaration
                string ancillaryStructFileName = Path.Combine(TargetFilePath, $"{GetValidPathName($"{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);

                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 is PointerTypeInfo ? "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.IsNullOrWhiteSpace(field.Comments) ? Environment.NewLine : $" {field.Comments.TrimStart()}")}");
                    m_targetFile.Append(fieldDecl);
                }

                m_targetFile.Append($"{Spacing()}}}{CheckForCommentsRight(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(CheckForCommentsRight(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(CheckForCommentsRight(context));
                    }
                    else if (signature.StartsWith("Func<", StringComparison.Ordinal))
                    {
                        signature = RemoveSurrounding(signature.Substring(4), "<", ">");
                        string[] parts = signature.Split(',');

                        if (parts.Length > 0)
                        {
                            string result = parts[^ 1];