b32 generate_foreign_info : 1;
b32 no_std : 1;
- b32 generate_tag_file : 1;
+ b32 generate_tag_file : 1;
+ b32 generate_symbol_info_file : 1;
Runtime runtime;
bh_arr(const char *) files;
const char* target_file;
const char* documentation_file;
+ const char* symbol_info_file;
b32 debug_enabled;
// present in this list when generating CTags.
bh_arr(AstNode *) tag_locations;
+ struct SymbolInfoTable *symbol_info;
+
u32 cycle_almost_detected : 2;
b32 cycle_detected : 1;
};
void track_declaration_for_tags(AstNode *);
+void track_declaration_for_symbol_info(OnyxFilePos, AstNode *);
+void track_resolution_for_symbol_info(AstNode *original, AstNode *resolved);
+
// NOTE: Useful inlined functions
static inline b32 is_lval(AstNode* node) {
node = strip_aliases(node);
OnyxDocumentation onyx_docs_generate();
void onyx_docs_emit(OnyxDocumentation* doc, const char* filename);
+
+// Tag generation
+
void onyx_docs_emit_tags(char *dest);
+
+
+// Symbol info file generation
+
+typedef struct SymbolInfo SymbolInfo;
+struct SymbolInfo {
+ u32 id;
+ u32 file_id;
+ u32 line;
+ u32 column;
+};
+
+typedef struct SymbolResolution SymbolResolution;
+struct SymbolResolution {
+ u32 file_id;
+ u32 line;
+ u32 column;
+ u32 length;
+ u32 symbol_id;
+};
+
+typedef struct SymbolInfoTable SymbolInfoTable;
+struct SymbolInfoTable {
+ // File name -> file id
+ Table(u32) files;
+ u32 next_file_id;
+
+ // Symbol id -> symbol info
+ bh_arr(SymbolInfo) symbols;
+ u32 next_symbol_id;
+
+ bh_arr(SymbolResolution) symbols_resolutions;
+
+ // Node * -> symbol_id
+ bh_imap node_to_id;
+};
+
+void onyx_docs_emit_symbol_info(const char *dest);
+
#endif
bh_file_close(&tags_file);
}
+void onyx_docs_emit_symbol_info(const char *dest) {
+ bh_file sym_file;
+ if (bh_file_create(&sym_file, dest) != BH_FILE_ERROR_NONE) {
+ bh_printf("Cannot create '%s'.\n", dest);
+ return;
+ }
+
+ SymbolInfoTable *syminfo = context.symbol_info;
+
+ bh_buffer file_section;
+ bh_buffer_init(&file_section, global_heap_allocator, 2048);
+ fori (i, 0, shlen(syminfo->files)) {
+ char *filename = syminfo->files[i].key;
+ u32 file_id = syminfo->files[i].value;
+ bh_buffer_write_u32(&file_section, file_id);
+ bh_buffer_write_u32(&file_section, strlen(filename));
+ bh_buffer_write_string(&file_section, filename);
+ }
+
+ bh_buffer sym_def_section;
+ bh_buffer_init(&sym_def_section, global_heap_allocator, 2048);
+ bh_arr_each(SymbolInfo, sym, syminfo->symbols) {
+ bh_buffer_write_u32(&sym_def_section, sym->id);
+ bh_buffer_write_u32(&sym_def_section, sym->file_id);
+ bh_buffer_write_u32(&sym_def_section, sym->line);
+ bh_buffer_write_u32(&sym_def_section, sym->column);
+ }
+
+ bh_buffer sym_res_section;
+ bh_buffer_init(&sym_res_section, global_heap_allocator, 2048);
+ bh_arr_each(SymbolResolution, sym, syminfo->symbols_resolutions) {
+ bh_buffer_write_u32(&sym_res_section, sym->file_id);
+ bh_buffer_write_u32(&sym_res_section, sym->line);
+ bh_buffer_write_u32(&sym_res_section, sym->column);
+ bh_buffer_write_u32(&sym_res_section, sym->length);
+ bh_buffer_write_u32(&sym_res_section, sym->symbol_id);
+ }
+
+ bh_buffer header_section;
+ bh_buffer_init(&header_section, global_heap_allocator, 16);
+ bh_buffer_append(&header_section, "OSYM", 4);
+ bh_buffer_write_u32(&header_section, 1);
+ bh_buffer_write_u32(&header_section, 32);
+ bh_buffer_write_u32(&header_section, shlenu(syminfo->files));
+ bh_buffer_write_u32(&header_section, 32 + file_section.length);
+ bh_buffer_write_u32(&header_section, bh_arr_length(syminfo->symbols));
+ bh_buffer_write_u32(&header_section, 32 + file_section.length + sym_def_section.length);
+ bh_buffer_write_u32(&header_section, bh_arr_length(syminfo->symbols_resolutions));
+
+ bh_file_write(&sym_file, header_section.data, header_section.length);
+ bh_file_write(&sym_file, file_section.data, file_section.length);
+ bh_file_write(&sym_file, sym_def_section.data, sym_def_section.length);
+ bh_file_write(&sym_file, sym_res_section.data, sym_res_section.length);
+
+ bh_file_close(&sym_file);
+
+ bh_buffer_free(&header_section);
+ bh_buffer_free(&file_section);
+ bh_buffer_free(&sym_def_section);
+ bh_buffer_free(&sym_res_section);
+
+
+ bh_arr_free(syminfo->symbols);
+ bh_arr_free(syminfo->symbols_resolutions);
+ shfree(syminfo->files);
+ bh_imap_free(&syminfo->node_to_id);
+}
+
// static i32 cmp_doc_entry(const void * a, const void * b) {
// DocEntry* d1 = (DocEntry *) a;
// DocEntry* d2 = (DocEntry *) b;
"\t--wasm-mvp Use only WebAssembly MVP features.\n"
"\t--multi-threaded Enables multi-threading for this compilation.\n"
"\t--tag Generates a C-Tag file.\n"
+ "\t--syminfo <target_file> Generates a symbol resolution information file. Used by onyx-lsp.\n"
// "\t--doc <doc_file>\n"
"\t--generate-foreign-info\n"
"\n"
.passthrough_argument_data = NULL,
.generate_tag_file = 0,
+ .generate_symbol_info_file = 0,
};
bh_arr_new(alloc, options.files, 2);
else if (!strcmp(argv[i], "--tag")) {
options.generate_tag_file = 1;
}
+ else if (!strcmp(argv[i], "--syminfo")) {
+ options.generate_symbol_info_file = 1;
+ options.symbol_info_file = argv[++i];
+ }
else if (!strcmp(argv[i], "--debug")) {
options.debug_enabled = 1;
}
.include = create_load(context.ast_alloc, "core/std"),
}));
}
+
+ if (context.options->generate_symbol_info_file) {
+ context.symbol_info = bh_alloc_item(global_heap_allocator, SymbolInfoTable);
+ bh_imap_init(&context.symbol_info->node_to_id, global_heap_allocator, 512);
+ bh_arr_new(global_heap_allocator, context.symbol_info->symbols, 128);
+ bh_arr_new(global_heap_allocator, context.symbol_info->symbols_resolutions, 128);
+ sh_new_arena(context.symbol_info->files);
+ }
}
static void context_free() {
onyx_docs_emit_tags("./tags");
}
+ if (context.options->generate_symbol_info_file) {
+ onyx_docs_emit_symbol_info(context.options->symbol_info_file);
+ }
+
return ONYX_COMPILER_PROGRESS_SUCCESS;
}
}
} else {
+ track_resolution_for_symbol_info(*symbol_node, res);
*symbol_node = res;
resolved_a_symbol = 1;
}
}
AstNode* resolution = try_symbol_resolve_from_node((AstNode *) expr, (*fa)->token);
- if (resolution) *((AstNode **) fa) = resolution;
- else if (expr->kind == Ast_Kind_Package) {
+ if (resolution) {
+ track_resolution_for_symbol_info((AstNode *) *fa, resolution);
+ *((AstNode **) fa) = resolution;
+
+ } else if (expr->kind == Ast_Kind_Package) {
if (report_unresolved_symbols) {
token_toggle_end((*fa)->token);
char *closest = find_closest_symbol_in_node((AstNode *) expr, (*fa)->token->text);
} else {
return Symres_Yield_Macro;
}
- }
- else if (force_a_lookup) {
+
+ } else if (force_a_lookup) {
if (context.cycle_detected || context.cycle_almost_detected >= 2) {
onyx_report_error((*fa)->token->pos, Error_Critical, "'%b' does not exist here. This is a bad error message.",
(*fa)->token->text,
#include "parser.h"
#include "astnodes.h"
#include "errors.h"
+#include "doc.h"
bh_scratch global_scratch;
bh_allocator global_scratch_allocator;
}
shput(scope->symbols, name, symbol);
+ track_declaration_for_symbol_info(pos, symbol);
return 1;
}
if (arg_pos < func_type->needed_param_count) {
if (error != NULL) {
error->pos = location->pos;
- error->text = "Too few arguments to function call.";
+ error->text = bh_aprintf(global_heap_allocator,
+ "Too few arguments to function call. Expected at least %d argument%s, but only got %d.",
+ func_type->needed_param_count, bh_num_plural(func_type->needed_param_count), arg_pos);
}
return TYPE_MATCH_FAILED;
}
if (arg_pos < (u32) arg_count) {
if (error != NULL) {
error->pos = location->pos;
- error->text = bh_aprintf(global_heap_allocator, "Too many arguments to function call. %d %d", arg_pos, arg_count);
+ error->text = bh_aprintf(global_heap_allocator,
+ "Too many arguments to function call. Expected at most %d argument%s, but got %d.",
+ arg_pos, bh_num_plural(arg_pos), arg_count);
}
return TYPE_MATCH_FAILED;
}
bh_arr_push(context.tag_locations, node);
}
}
+
+
+static u32 symbol_info_get_file_id(SymbolInfoTable *syminfo, const char *filename) {
+ u32 file_id;
+ if (shgeti(syminfo->files, filename) == -1) {
+ file_id = syminfo->next_file_id++;
+ shput(syminfo->files, filename, file_id);
+
+ } else {
+ file_id = shget(syminfo->files, filename);
+ }
+
+ return file_id;
+}
+
+void track_declaration_for_symbol_info(OnyxFilePos pos, AstNode *node) {
+ if (!context.options->generate_symbol_info_file) return;
+ if (pos.filename == NULL) return;
+
+ SymbolInfoTable *syminfo = context.symbol_info;
+ assert(syminfo);
+
+ u32 symbol_id = syminfo->next_symbol_id++;
+ u32 file_id = symbol_info_get_file_id(syminfo, pos.filename);
+
+ SymbolInfo symbol;
+ symbol.id = symbol_id;
+ symbol.file_id = file_id;
+ symbol.line = pos.line;
+ symbol.column = pos.column;
+ bh_arr_push(syminfo->symbols, symbol);
+
+ bh_imap_put(&syminfo->node_to_id, (u64) node, (u64) symbol_id);
+}
+
+void track_resolution_for_symbol_info(AstNode *original, AstNode *resolved) {
+ if (!context.options->generate_symbol_info_file) return;
+
+ SymbolInfoTable *syminfo = context.symbol_info;
+ assert(syminfo);
+
+ if (!bh_imap_has(&syminfo->node_to_id, (u64) resolved)) return;
+
+ u32 symbol_id = (u32) bh_imap_get(&syminfo->node_to_id, (u64) resolved);
+
+ u32 file_id = symbol_info_get_file_id(syminfo, original->token->pos.filename);
+
+ SymbolResolution res;
+ res.symbol_id = symbol_id;
+ res.file_id = file_id;
+ res.line = original->token->pos.line;
+ res.column = original->token->pos.column;
+ res.length = original->token->length;
+
+ bh_arr_push(syminfo->symbols_resolutions, res);
+}