private string GenerateAll() { var allCode = new CodeBuilder(); var classInfo = _classInfo; var classSyntax = _classInfo.ContainingClassSyntax; var namespaceName = classInfo.ContainingClassSymbol.ContainingNamespace.ToDisplayString(); var methodGens = _methodInfos.Select(mi => new CalculatorMethodGenerator(_context, classInfo, mi)).ToList(); var targetMethods = new TargetMethodsInfo(_methodInfos); // copy all the usings from the original file var root = (CompilationUnitSyntax)classSyntax.SyntaxTree.GetRoot(); allCode.AddHeaderLine(root.Usings.ToFullString()); allCode.AddHeaderLine(); // namespace allCode.AddBlockHeader($"namespace {namespaceName}"); // class declaration var classModifiersString = classSyntax.Modifiers.ToFullString(); if (!classModifiersString.Contains("partial")) { _context.ReportUnsupportedSyntaxError(classSyntax, $"Target class '{_classInfo.ContainingClassSymbol.Name}' for '{classInfo.RecursionId}' is not partial"); return(null); } allCode.AddBlockHeader($"{classModifiersString} class {_classInfo.ContainingClassSymbol.Name}"); allCode.AddHeaderLine(); allCode.AddHeaderLine(GenerateProxyMethods(methodGens)); allCode.AddHeaderLine(); allCode.AddHeaderLine(GenerateParamsStructs(classInfo, methodGens)); allCode.AddHeaderLine(); allCode.AddHeaderLine(GenerateCalculatorClass(classInfo, methodGens, targetMethods)); return(allCode.BuildString()); }
private SyntaxNode ReplaceReturn(TargetMethodsInfo targetMethods, ReturnStatementSyntax origNode, ReturnStatementSyntax curNode) { //Support cases of "return RecursiveCall(different params)" like GCD if (curNode.Expression.Kind() == SyntaxKind.InvocationExpression) { var inv = (InvocationExpressionSyntax)curNode.Expression; var targetMethod = GetInvocationRecursiveCallTarget(targetMethods, inv); if (targetMethod != null) { // only needed for mutual recursion where fields might be different var copyReturnValueLine = (_methodInfo != targetMethod) && _methodInfo.ShouldGenerateReturnField ? $"{_methodInfo.ReturnFieldName} = {targetMethod.ReturnFieldName}; // copy the return value" : ""; return(SyntaxUtils.GetBlockFromCodeString(origNode, @$ " yield return new {targetMethod.MethodParamsStructName}{targetMethod.GenericParams}{inv.ArgumentList.ToFullString()}; {copyReturnValueLine} yield break;")); } } return(SyntaxUtils.GetBlockFromCodeString(origNode, @$ " {_methodInfo.ReturnFieldName} = {origNode.Expression.ToFullString()};
internal string GenerateCalculatorMethodBody(TargetMethodsInfo targetMethods) { var code = new CodeBuilder(); // unpack params code.AddHeaderLine("\t\t// unpack params"); code.AddHeaderLine(string.Join("\n", _methodInfo.MethodSyntax.ParameterList.Parameters.Select(parameterSyntax => { var paramSymbol = _methodInfo.MethodModel.GetDeclaredSymbol(parameterSyntax); return($"\t\tvar {paramSymbol.Name} = {ParamsVarName}.{paramSymbol.Name};"); }))); // find all recursive invocations var nodesToReplace = CollectInvocationsWalker.CollectInvocations(_context, _methodInfo, targetMethods); if (nodesToReplace.ContainsCriticalFailure) { _context.Log(_methodInfo.MethodSyntax.GetLocation(), $"An unsupported code was found for '{_methodInfo.MethodSymbol.Name}'. Abort processing."); return(null); } _context.Log(_methodInfo.MethodSyntax.GetLocation(), $"'{_methodInfo.MethodSymbol.Name}':" + $" {nodesToReplace.VoidCalls.Count} void call(s)" + $" {nodesToReplace.Assignments.Count} assignment(s)" + $", {nodesToReplace.DeclarationAndAssignments.Count} var declaration(s)" + $", {nodesToReplace.ReturnsRecursive.Count} recursive call(s) in return(s)" + $", {nodesToReplace.Returns.Count} return(s)"); // process all supported kinds of recursive invocations var allNodesToReplace = nodesToReplace.Returns.Cast <StatementSyntax>() .Concat(nodesToReplace.ReturnsRecursive) .Concat(nodesToReplace.VoidCalls.Select(t => t.containingStatement)) .Concat(nodesToReplace.Assignments.Select((t) => t.containingStatement)) .Concat(nodesToReplace.DeclarationAndAssignments.Select(t => t.containingStatement)); var newRoot = _methodInfo.MethodSyntax.Body.ReplaceNodes(allNodesToReplace, (origNode, curNode) => { // _context.Log("!! " + origNode.Kind() + " " + origNode.ToFullStringTrimmed()); switch (origNode.Kind()) { case SyntaxKind.ReturnStatement: return(ReplaceReturn(targetMethods, (ReturnStatementSyntax)origNode, (ReturnStatementSyntax)curNode)); case SyntaxKind.ExpressionStatement: var origExpressionNode = (ExpressionStatementSyntax)origNode; var expression = origExpressionNode.Expression; switch (expression.Kind()) { case SyntaxKind.InvocationExpression: return(ReplaceVoidCall(targetMethods, origExpressionNode, (ExpressionStatementSyntax)curNode)); case SyntaxKind.SimpleAssignmentExpression: return(ReplaceAssignment(targetMethods, origExpressionNode, (ExpressionStatementSyntax)curNode)); default: throw new AntiSOGenException($"Unexpected expression kind {expression.Kind()} to replace {origNode.ToFullStringTrimmed()}"); } case SyntaxKind.LocalDeclarationStatement: return(ReplaceLocalVarDeclrAssignment(targetMethods, (LocalDeclarationStatementSyntax)origNode, (LocalDeclarationStatementSyntax)curNode)); default: throw new AntiSOGenException($"Unexpected statement kind {origNode.Kind()} to replace {origNode.ToFullStringTrimmed()}"); } }); code.AddHeaderLine("\t\t// method body"); code.AddHeader(newRoot.ToFullString()); return(code.BuildString()); }
private string GenerateSimpleCalculatorClass(RecursiveCalculatorClassInfo classInfo, List <CalculatorMethodGenerator> methodGens, TargetMethodsInfo targetMethods) { var code = new CodeBuilder(); var methodGen = methodGens.Single(); var methodInfo = methodGen.MethodInfo; code.AddBlockHeader(@$ " private class {classInfo.CalculatorClassName}{classInfo.GenericParams} : AntiSO.Infrastructure.SimpleRecursionRunner<{methodInfo.MethodParamsStructName}{methodInfo.GenericParams}>
private string GenerateCalculatorClass(RecursiveCalculatorClassInfo classInfo, List <CalculatorMethodGenerator> methodGens, TargetMethodsInfo targetMethods) { if (classInfo.IsMultiSite) { // mutual recursion with a dispatcher method return(GenerateMultiSiteCalculatorClass(classInfo, methodGens, targetMethods)); } else { // simple recursion return(GenerateSimpleCalculatorClass(classInfo, methodGens, targetMethods)); } }