/// <summary> /// Generates a standard error checking sequence. /// E.g. if err != nil return err /// </summary> /// <param name="errorVar">The name of the error variable.</param> /// <param name="onError">How the error should be handled.</param> /// <returns>The root node of this error checking AST.</returns> public static Node Generate(string errorVar, OnError onError) { if (string.IsNullOrWhiteSpace(errorVar)) { throw new ArgumentException(nameof(errorVar)); } Node handler = null; switch (onError) { case OnError.Panic: handler = FunctionCall.Generate("panic", new[] { new FuncCallParam(new Identifier(errorVar), TypeModifier.ByValue) }); break; case OnError.ReturnError: var ret = new Return(); ret.AddChild(new Identifier(errorVar)); handler = ret; break; default: throw new NotImplementedException($"OnError state {onError} NYI"); } var node = IfBlock.Generate(BinaryOpSequence.Generate(BinaryOperatorType.NotEqualTo, new Identifier(errorVar), new Nil()), new[] { handler }); return(node); }
/// <summary> /// Generates a standard error checking sequence. /// E.g. if err != nil return var1, var2, varN /// </summary> /// <param name="errorVar">The name of the error variable.</param> /// <param name="toReturn"> /// List of variables to return. All variables in /// this list will be returned in the specified order. /// </param> /// <returns>The root node of this error checking AST.</returns> public static Node Generate(string errorVar, IReadOnlyList <Node> toReturn) { var ret = new Return(); ret.AddChild(DelimitedSequence.Generate(UnaryDelimiterType.Comma, toReturn)); var node = IfBlock.Generate(BinaryOpSequence.Generate(BinaryOperatorType.NotEqualTo, new Identifier(errorVar), new Nil()), new[] { ret }); return(node); }
/// <summary> /// Generates a test case function for the specified method. /// </summary> /// <param name="mg">The method for which a test case will be generated.</param> /// <param name="rpcTypeName">The type name use for RPC dispatch.</param> /// <returns>The root node in this test case function AST.</returns> public static Tuple <Node, string> Generate(MethodGo mg, string rpcTypeName, string replyTypeName, string replyConvFuncName, string loggerVarName) { if (mg == null) { throw new ArgumentNullException(nameof(mg)); } if (string.IsNullOrWhiteSpace(replyTypeName)) { throw new ArgumentException(nameof(replyTypeName)); } if (string.IsNullOrWhiteSpace(replyConvFuncName)) { throw new ArgumentException(nameof(replyConvFuncName)); } var errorVar = "err"; var jsonParamVar = "parameters"; var replyVar = "reply"; var operationId = mg.SerializedName.ToString(); if (!char.IsUpper(operationId[0])) { operationId = $"{char.ToUpperInvariant(operationId[0])}{operationId.Substring(1)}"; } var rpcTypeVar = char.ToLowerInvariant(rpcTypeName[0]).ToString(); var func = FunctionSignature.Generate(new FuncParamSig(rpcTypeVar, TypeModifier.ByReference, rpcTypeName), operationId, new[] { new FuncParamSig(jsonParamVar, TypeModifier.ByValue, "json.RawMessage"), new FuncParamSig(replyVar, TypeModifier.ByReference, replyTypeName) }, new[] { new FuncReturnSig(null, TypeModifier.ByValue, "error") }); var funcBody = new OpenDelimiter(BinaryDelimiterType.Brace); // generate a type used to unmarshal the parameters string unmarshalVar = null; var unmarshalType = GenerateTypeForParamsUnmarshal(mg); funcBody.AddChild(unmarshalType.Item1); funcBody.AddChild(new Terminal()); unmarshalVar = unmarshalType.Item2.ToLowerInvariant(); // do the unmarshaling and return on failure funcBody.AddChild(VariableDecl.Generate(unmarshalVar, unmarshalType.Item2)); funcBody.AddChild(new Terminal()); funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign, new Identifier(errorVar), FunctionCall.Generate("json.Unmarshal", new[] { new FuncCallParam(new Identifier(jsonParamVar), TypeModifier.ByValue), new FuncCallParam(new Identifier(unmarshalVar), TypeModifier.ByReference) }))); funcBody.AddChild(new Terminal()); funcBody.AddChild(ErrorCheck.Generate(errorVar, OnError.ReturnError)); funcBody.AddChild(new Terminal()); var authVar = "auth"; funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign, DelimitedSequence.Generate(UnaryDelimiterType.Comma, new[] { new Identifier(authVar), new Identifier(errorVar) }), FunctionCall.Generate($"{unmarshalVar}.{ReservedParamsFieldName}.Credentials.CreateBearerAuthorizer", null))); funcBody.AddChild(new Terminal()); funcBody.AddChild(ErrorCheck.Generate(errorVar, OnError.ReturnError)); funcBody.AddChild(new Terminal()); // create the client and call the target function var clientVar = "client"; // check if the client ctor has any parameters List <FuncCallParam> clientParams = null; if (!string.IsNullOrWhiteSpace(((MethodGroupGo)mg.MethodGroup).GlobalParameters)) { clientParams = new List <FuncCallParam>(); var globalParams = ((MethodGroupGo)mg.MethodGroup).GlobalParameters.Split(new[] { ',' }); // each param is the var name followed by the type name, e.g. "subscriptionID string" foreach (var globalParam in globalParams) { var paramName = globalParam.Substring(0, globalParam.IndexOf(' ')); clientParams.Add(new FuncCallParam(new Identifier($"{unmarshalVar}.{paramName.Capitalize()}"), TypeModifier.ByValue)); } } funcBody.AddChild(FunctionCall.Generate($"{loggerVarName}.Println", new[] { new FuncCallParam(new Literal <string>(operationId), TypeModifier.ByValue) })); funcBody.AddChild(new Terminal()); funcBody.AddChild(FunctionCall.Generate($"{loggerVarName}.Printf", new[] { new FuncCallParam(new Literal <string>("received %v\\n"), TypeModifier.ByValue), new FuncCallParam(new Identifier(unmarshalVar), TypeModifier.ByValue) })); funcBody.AddChild(new Terminal()); // the client creation function name prefix is hard-coded in the Go generator var clientCtorName = $"{mg.CodeModel.Namespace}.New"; if (!string.IsNullOrWhiteSpace(mg.MethodGroup.Name)) { clientCtorName = $"{clientCtorName}{((MethodGroupGo)mg.MethodGroup).ClientName}"; } funcBody.AddChild(BinaryOpSequence.Generate( BinaryOperatorType.DeclareAndAssign, new Identifier(clientVar), FunctionCall.Generate(clientCtorName, clientParams))); funcBody.AddChild(new Terminal()); funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.Assignment, new Identifier($"{clientVar}.Authorizer"), new Identifier(authVar))); funcBody.AddChild(new Terminal()); var rChanVar = "rChan"; var eChanVar = "eChan"; var responseVar = "resp"; var rawResponseVar = "rawResp"; var isLro = mg.IsLongRunningOperation() && !mg.IsPageable; funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign, DelimitedSequence.Generate(UnaryDelimiterType.Comma, new[] { new Identifier(isLro ? rChanVar : responseVar), new Identifier(isLro ? eChanVar : errorVar) }), FunctionCall.Generate($"{clientVar}.{mg.Name}", GenerateApiCallParams(mg, unmarshalVar)))); funcBody.AddChild(new Terminal()); if (isLro) { funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.Assignment, new Identifier(errorVar), new Identifier($"<-{eChanVar}"))); funcBody.AddChild(new Terminal()); } funcBody.AddChild(ErrorCheck.Generate(errorVar, OnError.ReturnError)); funcBody.AddChild(new Terminal()); if (isLro) { funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign, new Identifier(responseVar), new Identifier($"<-{rChanVar}"))); funcBody.AddChild(new Terminal()); } funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign, DelimitedSequence.Generate(UnaryDelimiterType.Comma, new[] { new Identifier(rawResponseVar), new Identifier(errorVar) }), FunctionCall.Generate(replyConvFuncName, new[] { new FuncCallParam(new Identifier(mg.HasReturnValue() ? $"{responseVar}.Response" : $"{responseVar}"), TypeModifier.ByReference), new FuncCallParam(mg.HasReturnValue() ? (Node) new Identifier(responseVar) : new Nil(), TypeModifier.ByValue) }))); funcBody.AddChild(new Terminal()); funcBody.AddChild(FunctionCall.Generate($"{loggerVarName}.Printf", new[] { new FuncCallParam(new Literal <string>("response %v\\n"), TypeModifier.ByValue), new FuncCallParam(new Identifier($"*{rawResponseVar}"), TypeModifier.ByValue) })); funcBody.AddChild(new Terminal()); funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.Assignment, new Identifier($"*{replyVar}"), new Identifier($"*{rawResponseVar}"))); funcBody.AddChild(new Terminal()); funcBody.AddChild(ReturnStatement.Generate(new[] { errorVar })); funcBody.AddClosingDelimiter(); func.AddChild(funcBody); return(new Tuple <Node, string>(func, operationId)); }