From a70134ba38cb9d6ca9036a40d8922871899dfaf5 Mon Sep 17 00:00:00 2001 From: Iampete1 Date: Sun, 17 Oct 2021 01:07:11 +0100 Subject: [PATCH] AP_Scripting: generator: ouput Emmylua docs --- libraries/AP_Scripting/generator/src/main.c | 195 +++++++++++++++++++- 1 file changed, 194 insertions(+), 1 deletion(-) diff --git a/libraries/AP_Scripting/generator/src/main.c b/libraries/AP_Scripting/generator/src/main.c index ce37d7afbe..baa1848009 100644 --- a/libraries/AP_Scripting/generator/src/main.c +++ b/libraries/AP_Scripting/generator/src/main.c @@ -73,6 +73,7 @@ struct generator_state { FILE *description; FILE *header; FILE *source; +FILE *docs; static struct generator_state state; static struct header * headers; @@ -2076,13 +2077,175 @@ void emit_not_supported_helper(void) { fprintf(source, "}\n\n"); } +void emit_docs_type(struct type type, const char *prefix, const char *suffix) { + switch (type.type) { + case TYPE_BOOLEAN: + fprintf(docs, "%s boolean%s", prefix, suffix); + break; + case TYPE_FLOAT: + fprintf(docs, "%s number%s", prefix, suffix); + break; + case TYPE_INT8_T: + case TYPE_INT16_T: + case TYPE_INT32_T: + case TYPE_UINT8_T: + case TYPE_UINT16_T: + case TYPE_ENUM: + fprintf(docs, "%s integer%s", prefix, suffix); + break; + case TYPE_STRING: + fprintf(docs, "%s string%s", prefix, suffix); + break; + case TYPE_UINT32_T: + fprintf(docs, "%s uint32_t%s", prefix, suffix); + break; + case TYPE_USERDATA: { + // userdata may have alias + struct userdata *data = parsed_userdata; + int found = 0; + while (data) { + if (strcmp(type.data.ud.sanatized_name, data->sanatized_name) == 0) { + found = 1; + break; + } + data = data->next; + } + if (found == 0) { + error(ERROR_GENERAL, "Could not find userdata %s", type.data.ud.sanatized_name); + } + fprintf(docs, "%s %s%s", prefix, data->alias ? data->alias : data->sanatized_name, suffix); + break; + } + case TYPE_AP_OBJECT: + fprintf(docs, "%s %s%s", prefix, type.data.ud.sanatized_name, suffix); + break; + case TYPE_NONE: + case TYPE_LITERAL: + break; + } +} + +void emit_docs(struct userdata *node, int emit_creation) { + while(node) { + fprintf(docs, "-- desc\n"); + fprintf(docs, "---@class %s\n", node->alias ? node->alias : node->sanatized_name); + + // enums + if (node->enums != NULL) { + struct userdata_enum *ud_enum = node->enums; + while (ud_enum != NULL) { + fprintf(docs, "---@field %s number\n", ud_enum->name); + ud_enum = ud_enum->next; + } + } + + if (emit_creation) { + // creation function + fprintf(docs, "---@return %s\n", node->alias ? node->alias : node->sanatized_name); + fprintf(docs, "function %s() end\n\n", node->alias ? node->alias : node->sanatized_name); + } else { + // global + fprintf(docs, "%s = {}\n\n", node->alias ? node->alias : node->sanatized_name); + } + + + // fields + if (node->fields != NULL) { + struct userdata_field *field = node->fields; + while(field) { + if (field->array_len == NULL) { + // single value feild + if (field->access_flags & ACCESS_FLAG_READ) { + fprintf(docs, "-- get field\n"); + emit_docs_type(field->type, "---@return", "\n"); + fprintf(docs, "function %s:%s() end\n\n", node->alias ? node->alias : node->sanatized_name, field->name); + } + if (field->access_flags & ACCESS_FLAG_WRITE) { + fprintf(docs, "-- set field\n"); + emit_docs_type(field->type, "---@param value", "\n"); + fprintf(docs, "function %s:%s(value) end\n\n", node->alias ? node->alias : node->sanatized_name, field->name); + } + } else { + // array feild + if (field->access_flags & ACCESS_FLAG_READ) { + fprintf(docs, "-- get array field\n"); + fprintf(docs, "---@param index integer\n"); + emit_docs_type(field->type, "---@return", "\n"); + fprintf(docs, "function %s:%s(index) end\n\n", node->alias ? node->alias : node->sanatized_name, field->name); + } + if (field->access_flags & ACCESS_FLAG_WRITE) { + fprintf(docs, "-- set array field\n"); + fprintf(docs, "---@param index integer\n"); + emit_docs_type(field->type, "---@param value", "\n"); + fprintf(docs, "function %s:%s(index, value) end\n\n", node->alias ? node->alias : node->sanatized_name, field->name); + } + } + field = field->next; + } + } + + // methods + struct method *method = node->methods; + while(method) { + fprintf(docs, "-- desc\n"); + + struct argument *arg = method->arguments; + int count = 1; + // input arguments + while (arg != NULL) { + if ((arg->type.type != TYPE_LITERAL) && (arg->type.flags & (TYPE_FLAGS_NULLABLE | TYPE_FLAGS_REFERNCE)) == 0) { + char *param_name = (char *)allocate(20); + sprintf(param_name, "---@param param%i", count); + emit_docs_type(arg->type, param_name, "\n"); + free(param_name); + count++; + } + arg = arg->next; + } + + // return type + if ((method->flags & TYPE_FLAGS_NULLABLE) == 0) { + emit_docs_type(method->return_type, "---@return", "\n"); + } + + arg = method->arguments; + // nulable and refences returns + while (arg != NULL) { + if ((arg->type.type != TYPE_LITERAL) && (arg->type.flags & (TYPE_FLAGS_NULLABLE | TYPE_FLAGS_REFERNCE))) { + if (arg->type.flags & TYPE_FLAGS_NULLABLE) { + emit_docs_type(arg->type, "---@return", "|nil\n"); + } else { + emit_docs_type(arg->type, "---@return", "\n"); + } + } + arg = arg->next; + } + + // function name + fprintf(docs, "function %s:%s(", node->alias ? node->alias : node->sanatized_name, method->alias ? method->alias : method->name); + for (int i = 1; i < count; ++i) { + fprintf(docs, "param%i", i); + if (i < count-1) { + fprintf(docs, ", "); + } + } + fprintf(docs, ") end\n\n"); + method = method->next; + } + fprintf(docs, "\n"); + node = node->next; + } +} + + char * output_path = NULL; +char * docs_path = NULL; int main(int argc, char **argv) { state.line_num = -1; int c; - while ((c = getopt(argc, argv, "i:o:")) != -1) { + while ((c = getopt(argc, argv, "i:o:d:")) != -1) { switch (c) { case 'i': if (description != NULL) { @@ -2101,6 +2264,13 @@ int main(int argc, char **argv) { output_path = optarg; trace(TRACE_GENERAL, "Loading an output path of %s", output_path); break; + case 'd': + if (docs_path != NULL) { + error(ERROR_GENERAL, "An docs path was already selected."); + } + docs_path = optarg; + trace(TRACE_GENERAL, "Loading an docs path of %s", docs_path); + break; } } @@ -2216,5 +2386,28 @@ int main(int argc, char **argv) { fclose(header); header = NULL; + if (docs_path == NULL) { + // no docs to generate, all done + return 0; + } + + docs = fopen(docs_path, "w"); + if (docs == NULL) { + error(ERROR_GENERAL, "Unable to open the output docs file: %s", docs_path); + } + + fprintf(docs, "-- ArduPilot lua scripting documentation in EmmyLua Annotations\n"); + fprintf(docs, "-- This file should be auto generated and then manual edited\n"); + fprintf(docs, "-- generate with --scripting-docs, eg ./waf copter --scripting-docs\n"); + fprintf(docs, "-- see: https://github.com/sumneko/lua-language-server/wiki/EmmyLua-Annotations\n\n"); + + emit_docs(parsed_userdata, TRUE); + + emit_docs(parsed_ap_objects, FALSE); + + emit_docs(parsed_singletons, FALSE); + + fclose(docs); + return 0; }