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)); }