diff options
Diffstat (limited to 'src/lsp/lsp_analysis.c')
| -rw-r--r-- | src/lsp/lsp_analysis.c | 702 |
1 files changed, 529 insertions, 173 deletions
diff --git a/src/lsp/lsp_analysis.c b/src/lsp/lsp_analysis.c index d455894..e63ae4a 100644 --- a/src/lsp/lsp_analysis.c +++ b/src/lsp/lsp_analysis.c @@ -1,13 +1,11 @@ - #include "json_rpc.h" -#include "lsp_index.h" -#include "parser.h" +#include "cJSON.h" +#include "lsp_project.h" // Includes lsp_index.h, parser.h #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> - -static LSPIndex *g_index = NULL; +#include <unistd.h> typedef struct Diagnostic { @@ -23,17 +21,28 @@ typedef struct Diagnostic *tail; } DiagnosticList; -static ParserContext *g_ctx = NULL; -static char *g_last_src = NULL; +// Helper to send JSON response +static void send_json_response(cJSON *root) +{ + char *str = cJSON_PrintUnformatted(root); + if (str) + { + fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(str), str); + fflush(stdout); + free(str); + } + cJSON_Delete(root); +} // Callback for parser errors. void lsp_on_error(void *data, Token t, const char *msg) { DiagnosticList *list = (DiagnosticList *)data; - Diagnostic *d = xmalloc(sizeof(Diagnostic)); + // Simple allocation for MVP + Diagnostic *d = calloc(1, sizeof(Diagnostic)); d->line = t.line > 0 ? t.line - 1 : 0; d->col = t.col > 0 ? t.col - 1 : 0; - d->message = xstrdup(msg); + d->message = strdup(msg); d->next = NULL; if (!list->head) @@ -50,79 +59,79 @@ void lsp_on_error(void *data, Token t, const char *msg) void lsp_check_file(const char *uri, const char *json_src) { - // Prepare ParserContext (persistent). - if (g_ctx) + if (!g_project) { - - free(g_ctx); + // Fallback or lazy init? current dir + char cwd[1024]; + if (getcwd(cwd, sizeof(cwd))) + { + lsp_project_init(cwd); + } + else + { + lsp_project_init("."); + } } - g_ctx = calloc(1, sizeof(ParserContext)); - g_ctx->is_fault_tolerant = 1; + // Setup error capture on the global project context DiagnosticList diagnostics = {0}; - g_ctx->error_callback_data = &diagnostics; - g_ctx->on_error = lsp_on_error; - // Prepare Lexer. - // Cache source. - if (g_last_src) - { - free(g_last_src); - } - g_last_src = strdup(json_src); + // We attach the callback to 'g_project->ctx'. + // NOTE: If we use lsp_project_update_file, it uses g_project->ctx. + void *old_data = g_project->ctx->error_callback_data; + void (*old_cb)(void *, Token, const char *) = g_project->ctx->on_error; - Lexer l; - lexer_init(&l, json_src); + g_project->ctx->error_callback_data = &diagnostics; + g_project->ctx->on_error = lsp_on_error; - ASTNode *root = parse_program(g_ctx, &l); + // Update and Parse + lsp_project_update_file(uri, json_src); - if (g_index) - { - lsp_index_free(g_index); - } - g_index = lsp_index_new(); - if (root) - { - lsp_build_index(g_index, root); - } + // Restore + g_project->ctx->on_error = old_cb; + g_project->ctx->error_callback_data = old_data; - // Construct JSON Response (notification) + // Construct JSON Response (publishDiagnostics) + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddStringToObject(root, "method", "textDocument/publishDiagnostics"); - char *notification = malloc(128 * 1024); - char *p = notification; - p += sprintf(p, - "{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/" - "publishDiagnostics\",\"params\":{\"uri\":\"%s\",\"diagnostics\":[", - uri); + cJSON *params = cJSON_CreateObject(); + cJSON_AddStringToObject(params, "uri", uri); + + cJSON *diag_array = cJSON_CreateArray(); Diagnostic *d = diagnostics.head; while (d) { + cJSON *diag = cJSON_CreateObject(); - p += sprintf(p, - "{\"range\":{\"start\":{\"line\":%d,\"character\":%d},\"end\":" - "{\"line\":%d," - "\"character\":%d}},\"severity\":1,\"message\":\"%s\"}", - d->line, d->col, d->line, d->col + 1, d->message); + cJSON *range = cJSON_CreateObject(); + cJSON *start = cJSON_CreateObject(); + cJSON_AddNumberToObject(start, "line", d->line); + cJSON_AddNumberToObject(start, "character", d->col); - if (d->next) - { - p += sprintf(p, ","); - } + cJSON *end = cJSON_CreateObject(); + cJSON_AddNumberToObject(end, "line", d->line); + cJSON_AddNumberToObject(end, "character", d->col + 1); + + cJSON_AddItemToObject(range, "start", start); + cJSON_AddItemToObject(range, "end", end); + + cJSON_AddItemToObject(diag, "range", range); + cJSON_AddNumberToObject(diag, "severity", 1); + cJSON_AddStringToObject(diag, "message", d->message); + + cJSON_AddItemToArray(diag_array, diag); d = d->next; } - p += sprintf(p, "]}}"); - - // Send notification. - long len = strlen(notification); - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", len, notification); - fflush(stdout); + cJSON_AddItemToObject(params, "diagnostics", diag_array); + cJSON_AddItemToObject(root, "params", params); - free(notification); + send_json_response(root); - // Cleanup. Diagnostic *cur = diagnostics.head; while (cur) { @@ -135,58 +144,126 @@ void lsp_check_file(const char *uri, const char *json_src) void lsp_goto_definition(const char *uri, int line, int col) { - if (!g_index) + ProjectFile *pf = lsp_project_get_file(uri); + LSPIndex *idx = pf ? pf->index : NULL; + + if (!idx) { return; } - LSPRange *r = lsp_find_at(g_index, line, col); - if (r && r->type == RANGE_REFERENCE) + LSPRange *r = lsp_find_at(idx, line, col); + const char *target_uri = uri; + int target_start_line = 0, target_start_col = 0; + int target_end_line = 0, target_end_col = 0; + int found = 0; + + // 1. Check Local Index + if (r) { - // Found reference, return definition - char resp[1024]; - sprintf(resp, - "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"uri\":\"%s\"," - "\"range\":{\"start\":{" - "\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%" - "d}}}}", - uri, r->def_line, r->def_col, r->def_line, r->def_col); - - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(resp), resp); - fflush(stdout); + if (r->type == RANGE_DEFINITION) + { + // Already at definition + target_start_line = r->start_line; + target_start_col = r->start_col; + target_end_line = r->end_line; + target_end_col = r->end_col; + found = 1; + } + else if (r->type == RANGE_REFERENCE && r->def_line >= 0) + { + LSPRange *def = lsp_find_at(idx, r->def_line, r->def_col); + int is_local = 0; + if (def && def->type == RANGE_DEFINITION) + { + // Check name congruence logic ... (simplified for now) + // Assume logic in previous version was correct about checking names + is_local = 1; + } + + if (is_local) + { + target_start_line = r->def_line; + target_start_col = r->def_col; + target_end_line = r->def_line; + target_end_col = r->def_col; // approx + found = 1; + } + } } - else if (r && r->type == RANGE_DEFINITION) + + // 2. Global Definition (if local failed) + if (!found && r && r->node) { - // Already at definition? Return itself. - char resp[1024]; - sprintf(resp, - "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"uri\":\"%s\"," - "\"range\":{\"start\":{" - "\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%" - "d}}}}", - uri, r->start_line, r->start_col, r->end_line, r->end_col); - - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(resp), resp); - fflush(stdout); + char *name = NULL; + if (r->node->type == NODE_EXPR_VAR) + { + name = r->node->var_ref.name; + } + else if (r->node->type == NODE_EXPR_CALL && r->node->call.callee->type == NODE_EXPR_VAR) + { + name = r->node->call.callee->var_ref.name; + } + + if (name) + { + DefinitionResult def = lsp_project_find_definition(name); + if (def.uri && def.range) + { + target_uri = def.uri; + target_start_line = def.range->start_line; + target_start_col = def.range->start_col; + target_end_line = def.range->end_line; + target_end_col = def.range->end_col; + found = 1; + } + } + } + + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(root, "id", 1); + + if (found) + { + cJSON *result = cJSON_CreateObject(); + cJSON_AddStringToObject(result, "uri", target_uri); + + cJSON *range = cJSON_CreateObject(); + cJSON *start = cJSON_CreateObject(); + cJSON_AddNumberToObject(start, "line", target_start_line); + cJSON_AddNumberToObject(start, "character", target_start_col); + + cJSON *end = cJSON_CreateObject(); + cJSON_AddNumberToObject(end, "line", target_end_line); + cJSON_AddNumberToObject(end, "character", target_end_col); + + cJSON_AddItemToObject(range, "start", start); + cJSON_AddItemToObject(range, "end", end); + cJSON_AddItemToObject(result, "range", range); + + cJSON_AddItemToObject(root, "result", result); } else { - // Null result - const char *null_resp = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":null}"; - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(null_resp), null_resp); - fflush(stdout); + cJSON_AddNullToObject(root, "result"); } + + send_json_response(root); } void lsp_hover(const char *uri, int line, int col) { (void)uri; - if (!g_index) + ProjectFile *pf = lsp_project_get_file(uri); + LSPIndex *idx = pf ? pf->index : NULL; + + if (!idx) { return; } - LSPRange *r = lsp_find_at(g_index, line, col); + LSPRange *r = lsp_find_at(idx, line, col); char *text = NULL; if (r) @@ -197,7 +274,7 @@ void lsp_hover(const char *uri, int line, int col) } else if (r->type == RANGE_REFERENCE) { - LSPRange *def = lsp_find_at(g_index, r->def_line, r->def_col); + LSPRange *def = lsp_find_at(idx, r->def_line, r->def_col); if (def && def->type == RANGE_DEFINITION) { text = def->hover_text; @@ -205,44 +282,59 @@ void lsp_hover(const char *uri, int line, int col) } } + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(root, "id", 1); + if (text) { - char *json = malloc(16384); - // content: { kind: markdown, value: text } - sprintf(json, - "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"contents\":{\"kind\":" - "\"markdown\"," - "\"value\":\"```c\\n%s\\n```\"}}}", - text); - - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(json), json); - fflush(stdout); - free(json); + cJSON *result = cJSON_CreateObject(); + cJSON *contents = cJSON_CreateObject(); + cJSON_AddStringToObject(contents, "kind", "markdown"); + + // Need to wrap in ```c code block + char *code_block = malloc(strlen(text) + 16); + sprintf(code_block, "```c\n%s\n```", text); + cJSON_AddStringToObject(contents, "value", code_block); + free(code_block); + + cJSON_AddItemToObject(result, "contents", contents); + cJSON_AddItemToObject(root, "result", result); } else { - const char *null_resp = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":null}"; - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(null_resp), null_resp); - fflush(stdout); + cJSON_AddNullToObject(root, "result"); } + + send_json_response(root); } void lsp_completion(const char *uri, int line, int col) { - (void)uri; - if (!g_ctx) + ProjectFile *pf = lsp_project_get_file(uri); + // Need global project context + if (!g_project || !g_project->ctx || !pf) { return; } - // Context-aware completion (Dot access) - if (g_last_src) + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(root, "id", 1); + cJSON *items = cJSON_CreateArray(); + + // 1. Context-aware completion (Dot access) + // ... [Same logic as before, just constructing cJSON] ... + // Note: To save space/complexity in this rewrite, I'll streamline the dot completion logic + // or just implement the global fallback for now if the regex parsing is too complex to inline + // perfectly here. However, the original code had significant line-scanning logic. I will + // attempt to preserve the dot completion logic by copying it and using cJSON. + + int dot_completed = 0; + if (pf->source) { - // Simple line access int cur_line = 0; - - char *ptr = g_last_src; - // Fast forward to line + char *ptr = pf->source; while (*ptr && cur_line < line) { if (*ptr == '\n') @@ -254,14 +346,12 @@ void lsp_completion(const char *uri, int line, int col) if (col > 0 && ptr[col - 1] == '.') { - // Found dot! - // Scan backwards for identifier: [whitespace] [ident] . + // Found dot logic int i = col - 2; while (i >= 0 && (ptr[i] == ' ' || ptr[i] == '\t')) { i--; } - if (i >= 0) { int end_ident = i; @@ -270,7 +360,6 @@ void lsp_completion(const char *uri, int line, int col) i--; } int start_ident = i + 1; - if (start_ident <= end_ident) { int len = end_ident - start_ident + 1; @@ -278,9 +367,8 @@ void lsp_completion(const char *uri, int line, int col) strncpy(var_name, ptr + start_ident, len); var_name[len] = 0; + Symbol *sym = find_symbol_in_all(g_project->ctx, var_name); char *type_name = NULL; - Symbol *sym = find_symbol_in_all(g_ctx, var_name); - if (sym) { if (sym->type_info) @@ -297,7 +385,7 @@ void lsp_completion(const char *uri, int line, int col) { char clean_name[256]; char *src = type_name; - if (0 == strncmp(src, "struct ", 7)) + if (strncmp(src, "struct ", 7) == 0) { src += 7; } @@ -308,88 +396,356 @@ void lsp_completion(const char *uri, int line, int col) } *dst = 0; - // Lookup struct. - StructDef *sd = g_ctx->struct_defs; + StructDef *sd = g_project->ctx->struct_defs; while (sd) { - if (0 == strcmp(sd->name, clean_name)) + if (strcmp(sd->name, clean_name) == 0) { - char *json_fields = malloc(1024 * 1024); - char *pj = json_fields; - pj += sprintf(pj, "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":["); - - int ffirst = 1; if (sd->node && sd->node->strct.fields) { ASTNode *field = sd->node->strct.fields; while (field) { - if (!ffirst) - { - pj += sprintf(pj, ","); - } - pj += sprintf( - pj, - "{\"label\":\"%s\",\"kind\":5,\"detail\":\"field %s\"}", - field->field.name, field->field.type); // Kind 5 = Field - ffirst = 0; + cJSON *item = cJSON_CreateObject(); + cJSON_AddStringToObject(item, "label", field->field.name); + cJSON_AddNumberToObject(item, "kind", 5); // Field + char detail[256]; + sprintf(detail, "field %s", field->field.type); + cJSON_AddStringToObject(item, "detail", detail); + cJSON_AddItemToArray(items, item); field = field->next; } } - - pj += sprintf(pj, "]}"); - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", - strlen(json_fields), json_fields); - fflush(stdout); - free(json_fields); - free(json); - return; // Done, yippee. + dot_completed = 1; + break; } sd = sd->next; } + if (sym && sym->type_info) + { + free(type_name); + } } } } } } - char *json = xmalloc(1024 * 1024); // 1MB buffer. - char *p = json; - p += sprintf(p, "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":["); + if (!dot_completed) + { + // Global Completion + FuncSig *f = g_project->ctx->func_registry; + while (f) + { + cJSON *item = cJSON_CreateObject(); + cJSON_AddStringToObject(item, "label", f->name); + cJSON_AddNumberToObject(item, "kind", 3); // Function + char detail[256]; + sprintf(detail, "fn %s", f->name); + cJSON_AddStringToObject(item, "detail", detail); + cJSON_AddItemToArray(items, item); + f = f->next; + } + + StructDef *s = g_project->ctx->struct_defs; + while (s) + { + cJSON *item = cJSON_CreateObject(); + cJSON_AddStringToObject(item, "label", s->name); + cJSON_AddNumberToObject(item, "kind", 22); // Struct + char detail[256]; + sprintf(detail, "struct %s", s->name); + cJSON_AddStringToObject(item, "detail", detail); + cJSON_AddItemToArray(items, item); + s = s->next; + } + } + + cJSON_AddItemToObject(root, "result", items); + send_json_response(root); +} + +void lsp_document_symbol(const char *uri) +{ + ProjectFile *pf = lsp_project_get_file(uri); + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(root, "id", 1); + + if (!pf || !pf->index) + { + cJSON_AddNullToObject(root, "result"); + send_json_response(root); + return; + } + + cJSON *items = cJSON_CreateArray(); + LSPRange *r = pf->index->head; + while (r) + { + if (r->type == RANGE_DEFINITION && r->node) + { + char *name = NULL; + int kind = 0; + + if (r->node->type == NODE_FUNCTION) + { + name = r->node->func.name; + kind = 12; + } + else if (r->node->type == NODE_STRUCT) + { + name = r->node->strct.name; + kind = 23; + } + else if (r->node->type == NODE_VAR_DECL) + { + name = r->node->var_decl.name; + kind = 13; + } + else if (r->node->type == NODE_CONST) + { + name = r->node->var_decl.name; + kind = 14; + } + + if (name) + { + cJSON *item = cJSON_CreateObject(); + cJSON_AddStringToObject(item, "name", name); + cJSON_AddNumberToObject(item, "kind", kind); + + cJSON *loc = cJSON_CreateObject(); + cJSON_AddStringToObject(loc, "uri", uri); + + cJSON *range = cJSON_CreateObject(); + cJSON *start = cJSON_CreateObject(); + cJSON_AddNumberToObject(start, "line", r->start_line); + cJSON_AddNumberToObject(start, "character", r->start_col); + + cJSON *end = cJSON_CreateObject(); + cJSON_AddNumberToObject(end, "line", r->end_line); + cJSON_AddNumberToObject(end, "character", r->end_col); + + cJSON_AddItemToObject(range, "start", start); + cJSON_AddItemToObject(range, "end", end); + cJSON_AddItemToObject(loc, "range", range); + + cJSON_AddItemToObject(item, "location", loc); + cJSON_AddItemToArray(items, item); + } + } + r = r->next; + } + + cJSON_AddItemToObject(root, "result", items); + send_json_response(root); +} + +void lsp_references(const char *uri, int line, int col) +{ + ProjectFile *pf = lsp_project_get_file(uri); + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(root, "id", 1); + cJSON *items = cJSON_CreateArray(); + + if (pf && pf->index) + { + LSPRange *r = lsp_find_at(pf->index, line, col); + if (r && r->node) + { + char *name = NULL; + if (r->node->type == NODE_FUNCTION) + { + name = r->node->func.name; + } + else if (r->node->type == NODE_VAR_DECL) + { + name = r->node->var_decl.name; + } + else if (r->node->type == NODE_CONST) + { + name = r->node->var_decl.name; + } + else if (r->node->type == NODE_STRUCT) + { + name = r->node->strct.name; + } + else if (r->node->type == NODE_EXPR_VAR) + { + name = r->node->var_ref.name; + } + else if (r->node->type == NODE_EXPR_CALL && r->node->call.callee->type == NODE_EXPR_VAR) + { + name = r->node->call.callee->var_ref.name; + } + + if (name) + { + ReferenceResult *refs = lsp_project_find_references(name); + ReferenceResult *curr = refs; + while (curr) + { + cJSON *item = cJSON_CreateObject(); + cJSON_AddStringToObject(item, "uri", curr->uri); + cJSON *range = cJSON_CreateObject(); + cJSON *start = cJSON_CreateObject(); + cJSON_AddNumberToObject(start, "line", curr->range->start_line); + cJSON_AddNumberToObject(start, "character", curr->range->start_col); + + cJSON *end = cJSON_CreateObject(); + cJSON_AddNumberToObject(end, "line", curr->range->end_line); + cJSON_AddNumberToObject(end, "character", curr->range->end_col); + + cJSON_AddItemToObject(range, "start", start); + cJSON_AddItemToObject(range, "end", end); + cJSON_AddItemToObject(item, "range", range); + cJSON_AddItemToArray(items, item); + + ReferenceResult *next = curr->next; + free(curr); + curr = next; + } + } + } + } + + cJSON_AddItemToObject(root, "result", items); + send_json_response(root); +} + +void lsp_signature_help(const char *uri, int line, int col) +{ + ProjectFile *pf = lsp_project_get_file(uri); + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(root, "id", 1); - int first = 1; + if (!g_project || !g_project->ctx || !pf || !pf->source) + { + cJSON_AddNullToObject(root, "result"); + send_json_response(root); + return; + } - // Functions - FuncSig *f = g_ctx->func_registry; - while (f) + // ... [Scan backwards logic same as before] ... + char *ptr = pf->source; + int cur_line = 0; + while (*ptr && cur_line < line) { - if (!first) + if (*ptr == '\n') { - p += sprintf(p, ","); + cur_line++; } - p += sprintf(p, "{\"label\":\"%s\",\"kind\":3,\"detail\":\"fn %s(...)\"}", f->name, - f->name); // Kind 3 = Function - first = 0; - f = f->next; + ptr++; + } + if (ptr && col > 0) + { + ptr += col; } - // Structs - StructDef *s = g_ctx->struct_defs; - while (s) + if (ptr > pf->source + strlen(pf->source)) { - if (!first) + cJSON_AddNullToObject(root, "result"); + send_json_response(root); + return; + } + + int found = 0; + char *p = ptr - 1; + while (p >= pf->source) + { + if (*p == ')') { - p += sprintf(p, ","); + break; } - p += sprintf(p, "{\"label\":\"%s\",\"kind\":22,\"detail\":\"struct %s\"}", s->name, - s->name); // Kind 22 = Struct - first = 0; - s = s->next; + if (*p == '(') + { + // Found open paren + char *ident_end = p - 1; + while (ident_end >= pf->source && isspace(*ident_end)) + { + ident_end--; + } + if (ident_end < pf->source) + { + break; + } + char *ident_start = ident_end; + while (ident_start >= pf->source && (isalnum(*ident_start) || *ident_start == '_')) + { + ident_start--; + } + ident_start++; + + int len = ident_end - ident_start + 1; + if (len > 0 && len < 255) + { + char func_name[256]; + strncpy(func_name, ident_start, len); + func_name[len] = 0; + // Lookup + FuncSig *fn = g_project->ctx->func_registry; + while (fn) + { + if (strcmp(fn->name, func_name) == 0) + { + // Found it + cJSON *result = cJSON_CreateObject(); + cJSON *sigs = cJSON_CreateArray(); + cJSON *sig = cJSON_CreateObject(); + + char label[2048]; + char params[1024] = ""; + int first = 1; + for (int i = 0; i < fn->total_args; i++) + { + if (!first) + { + strcat(params, ", "); + } + char *tstr = type_to_string(fn->arg_types[i]); + if (tstr) + { + strcat(params, tstr); + free(tstr); + } + else + { + strcat(params, "unknown"); + } + first = 0; + } + char *ret_str = type_to_string(fn->ret_type); + sprintf(label, "fn %s(%s) -> %s", fn->name, params, + ret_str ? ret_str : "void"); + if (ret_str) + { + free(ret_str); + } + + cJSON_AddStringToObject(sig, "label", label); + cJSON_AddItemToObject(sig, "parameters", cJSON_CreateArray()); + cJSON_AddItemToArray(sigs, sig); + + cJSON_AddItemToObject(result, "signatures", sigs); + cJSON_AddItemToObject(root, "result", result); + found = 1; + break; + } + fn = fn->next; + } + } + break; + } + p--; } - p += sprintf(p, "]}"); + if (!found) + { + cJSON_AddNullToObject(root, "result"); + } - fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(json), json); - fflush(stdout); - free(json); + send_json_response(root); } |
