public override void ExitFunctionDecl(GoParser.FunctionDeclContext context)
        {
            bool signatureOnly = context.block() is null;

            FunctionSignature function        = CurrentFunction.Signature;
            bool      hasDefer                = CurrentFunction.HasDefer;
            bool      hasPanic                = CurrentFunction.HasPanic;
            bool      hasRecover              = CurrentFunction.HasRecover;
            bool      useFuncExecutionContext = hasDefer || hasPanic || hasRecover;
            Signature signature               = function.Signature;
            string    parametersSignature     = $"({signature.GenerateParametersSignature()})";
            string    resultSignature         = signature.GenerateResultSignature();
            string    blockPrefix             = "";

            if (!signatureOnly)
            {
                StringBuilder resultParameters = new StringBuilder();
                StringBuilder arrayClones      = new StringBuilder();
                StringBuilder implicitPointers = new StringBuilder();

                foreach (ParameterInfo parameter in signature.Result)
                {
                    if (!string.IsNullOrEmpty(parameter.Name))
                    {
                        resultParameters.AppendLine($"{Spacing(1)}{parameter.Type.TypeName} {parameter.Name} = default{(parameter.Type is PointerTypeInfo || parameter.Type.TypeClass == TypeClass.Interface ? "!" : "")};");
                    }
                }

                foreach (ParameterInfo parameter in signature.Parameters)
                {
                    // For any array parameters, Go copies the array by value
                    if (parameter.Type.TypeClass == TypeClass.Array)
                    {
                        arrayClones.AppendLine($"{Spacing(1)}{parameter.Name} = {parameter.Name}.Clone();");
                    }

                    // All pointers in Go can be implicitly dereferenced, so setup a "local ref" instance to each
                    if (parameter.Type is PointerTypeInfo pointer)
                    {
                        implicitPointers.AppendLine($"{Spacing(1)}ref {pointer.TargetTypeInfo.TypeName} {parameter.Name} = ref {AddressPrefix}{parameter.Name}.val;");
                    }
                }

                if (resultParameters.Length > 0)
                {
                    resultParameters.Insert(0, Environment.NewLine);
                    blockPrefix += resultParameters.ToString();
                }

                if (arrayClones.Length > 0)
                {
                    if (blockPrefix.Length == 0)
                    {
                        arrayClones.Insert(0, Environment.NewLine);
                    }

                    blockPrefix += arrayClones.ToString();
                }

                if (implicitPointers.Length > 0)
                {
                    if (blockPrefix.Length == 0)
                    {
                        implicitPointers.Insert(0, Environment.NewLine);
                    }

                    blockPrefix += implicitPointers.ToString();

                    StringBuilder updatedSignature = new StringBuilder();
                    bool          initialParam     = true;

                    foreach (ParameterInfo parameter in signature.Parameters)
                    {
                        if (!initialParam)
                        {
                            updatedSignature.Append(", ");
                        }

                        initialParam = false;
                        updatedSignature.Append($"{(parameter.IsVariadic ? "params " : "")}{parameter.Type.TypeName} ");

                        if (parameter.Type is PointerTypeInfo)
                        {
                            updatedSignature.Append(AddressPrefix);
                        }

                        updatedSignature.Append(parameter.Name);
                    }

                    parametersSignature = $"({updatedSignature})";
                }
            }

            // Replace function markers
            m_targetFile.Replace(m_functionResultTypeMarker, resultSignature);
            m_targetFile.Replace(m_functionParametersMarker, parametersSignature);

            if (useFuncExecutionContext)
            {
                Stack <string> unusedNames = new Stack <string>(new[] { "__", "_" });
                m_targetFile.Replace(m_functionExecContextMarker, $" => func(({(hasDefer ? "defer" : unusedNames.Pop())}, {(hasPanic ? "panic" : unusedNames.Pop())}, {(hasRecover ? "recover" : unusedNames.Pop())}) =>");
            }
            else
            {
                m_targetFile.Replace(m_functionExecContextMarker, "");
            }

            m_targetFile.Replace(string.Format(FunctionBlockPrefixMarker, CurrentFunctionName), blockPrefix);

            if (useFuncExecutionContext)
            {
                m_targetFile.Append(");");
            }
            else if (signatureOnly)
            {
                m_targetFile.Append(";");
            }

            m_targetFile.Append(CheckForCommentsRight(context));

            base.ExitFunctionDecl(context);
        }
        public override void ExitFunctionDecl(GoParser.FunctionDeclContext context)
        {
            bool signatureOnly = context.block() is null;

            FunctionSignature function        = m_currentFunction.Signature;
            bool      hasDefer                = m_currentFunction.HasDefer;
            bool      hasPanic                = m_currentFunction.HasPanic;
            bool      hasRecover              = m_currentFunction.HasRecover;
            bool      useFuncExecutionContext = hasDefer || hasPanic || hasRecover;
            Signature signature               = function.Signature;
            string    parametersSignature     = $"({signature.GenerateParametersSignature(useFuncExecutionContext)})";
            string    resultSignature         = signature.GenerateResultSignature();

            // Replace function markers
            m_targetFile.Replace(m_functionResultTypeMarker, resultSignature);
            m_targetFile.Replace(m_functionParametersMarker, parametersSignature);

            if (useFuncExecutionContext)
            {
                string[]       funcExecContextByRefParams = signature.GetByRefParameters(false).ToArray();
                Stack <string> unusedNames = new Stack <string>(new[] { "__", "_" });

                if (funcExecContextByRefParams.Length > 0)
                {
                    string[] lambdaByRefParameters = signature.GetByRefParameters(true).ToArray();
                    m_targetFile.Replace(m_functionExecContextMarker, $" => func({string.Join(", ", funcExecContextByRefParams)}, ({string.Join(", ", lambdaByRefParameters)}, Defer {(hasDefer ? "defer" : unusedNames.Pop())}, Panic {(hasPanic ? "panic" : unusedNames.Pop())}, Recover {(hasRecover ? "recover" : unusedNames.Pop())}) =>");
                }
                else
                {
                    m_targetFile.Replace(m_functionExecContextMarker, $" => func(({(hasDefer ? "defer" : unusedNames.Pop())}, {(hasPanic ? "panic" : unusedNames.Pop())}, {(hasRecover ? "recover" : unusedNames.Pop())}) =>");
                }
            }
            else
            {
                m_targetFile.Replace(m_functionExecContextMarker, "");
            }

            string blockPrefix = "";

            if (!signatureOnly)
            {
                // TODO: Double check if any other types need clone-type copy operations
                // For any array parameters, Go copies the array by value
                StringBuilder arrayClones = new StringBuilder();

                foreach (ParameterInfo parameter in signature.Parameters)
                {
                    if (parameter.Type.TypeClass == TypeClass.Array)
                    {
                        arrayClones.AppendLine($"{Spacing(1)}{parameter.Name} = {parameter.Name}.Clone();");
                    }
                }

                if (arrayClones.Length > 0)
                {
                    arrayClones.Insert(0, Environment.NewLine);
                    blockPrefix = arrayClones.ToString();
                }
            }

            m_targetFile.Replace(string.Format(FunctionBlockPrefixMarker, m_currentFunctionName), blockPrefix);

            m_currentFunction      = null;
            m_currentFunctionName  = null;
            m_originalFunctionName = null;
            m_inFunction           = false;

            if (useFuncExecutionContext)
            {
                m_targetFile.Append(");");
            }
            else if (signatureOnly)
            {
                m_targetFile.Append(";");
            }

            m_targetFile.Append(CheckForCommentsRight(context));
        }