private static MethodDeclarationSyntax GenerateGetExecutorMember(CodeSchema.CodeFunction codeFunction)
        {
            List <string> argumentFetches = new List <string>();

            foreach (var argument in codeFunction.Arguments)
            {
                argumentFetches.Add($"await oDrive.PushValue<{argument.Type}>({argument.EndpointID}, {argument.Name});");
            }

            var  returnType = string.IsNullOrEmpty(codeFunction.ReturnType) ? "Task" : $"Task<{codeFunction.ReturnType}>";
            bool hasReturn  = !string.IsNullOrEmpty(codeFunction.ReturnType);
            var  parameters = string.Join(",", GetParameterList(codeFunction.Arguments));

            var oDriveMethod = hasReturn ? "RequestValue" : "InvokeEndpoint";

            // TODO: Figure out why this template is putting the last semicolon on a new line...
            // TODO: Could parallel the fetches if there are multiple arguments
            string template = $@"
                public ExecutionDelegate GetExecutor(IDevice oDrive) {{
                    return async ({parameters}) => 
                    {{
                        {string.Join(Environment.NewLine, argumentFetches)}
                        {(hasReturn ? "return " : "")} await oDrive.{oDriveMethod}{(hasReturn ? $"<{codeFunction.ReturnType}>" : "")}({codeFunction.EndpointID});
                    }};
                }}
            ";

            return(((CompilationUnitSyntax)ParseSyntaxTree(template).GetRoot()).Members[0] as MethodDeclarationSyntax);
        }
        private static MemberDeclarationSyntax GenerateDelegateMember(CodeSchema.CodeFunction codeFunction)
        {
            var    returnType = string.IsNullOrEmpty(codeFunction.ReturnType) ? "Task" : $"Task<{codeFunction.ReturnType}>";
            var    parameters = string.Join(",", GetParameterList(codeFunction.Arguments));
            string template   = $@"public delegate {returnType} ExecutionDelegate({parameters});";

            return(((CompilationUnitSyntax)ParseSyntaxTree(template).GetRoot()).Members[0] as MemberDeclarationSyntax);
        }
        public static ClassDeclarationSyntax Generate(CodeSchema.CodeFunction codeFunction)
        {
            string methodOrFunction = string.IsNullOrEmpty(codeFunction.ReturnType) ? "Method" : "Function";
            string className        = $"{codeFunction.Name}{methodOrFunction}";

            var classDeclaration = ClassDeclaration(className)
                                   .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.PartialKeyword))
                                   .AddBaseListTypes(SimpleBaseType(ParseTypeName($"IExecutableMember<{className}.ExecutionDelegate>")))
                                   .AddMembers(GenerateDelegateMember(codeFunction))
                                   .AddMembers(GenerateGetExecutorMember(codeFunction));

            // var currentCode = ((SyntaxNode)classDeclaration).NormalizeWhitespace().ToFullString();

            return(classDeclaration);
        }