|
@@ -1,1030 +0,0 @@
|
|
|
-struct QueryValue;
|
|
|
-struct QueryValuePair;
|
|
|
-
|
|
|
-gb_global gbAllocator query_value_allocator = {};
|
|
|
-
|
|
|
-enum QueryKind {
|
|
|
- Query_Invalid,
|
|
|
- Query_String,
|
|
|
- Query_Boolean,
|
|
|
- Query_Integer,
|
|
|
- Query_Float,
|
|
|
- Query_Array,
|
|
|
- Query_Map,
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValuePair {
|
|
|
- String key;
|
|
|
- QueryValue *value;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-struct QueryValue {
|
|
|
- QueryKind kind;
|
|
|
- bool packed;
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValueString : QueryValue {
|
|
|
- QueryValueString(String const &v) {
|
|
|
- kind = Query_String;
|
|
|
- value = v;
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- String value;
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValueBoolean : QueryValue {
|
|
|
- QueryValueBoolean(bool v) {
|
|
|
- kind = Query_Boolean;
|
|
|
- value = v;
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- bool value;
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValueInteger : QueryValue {
|
|
|
- QueryValueInteger(i64 v) {
|
|
|
- kind = Query_Integer;
|
|
|
- value = v;
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- i64 value;
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValueFloat : QueryValue {
|
|
|
- QueryValueFloat(f64 v) {
|
|
|
- kind = Query_Float;
|
|
|
- value = v;
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- f64 value;
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValueArray : QueryValue {
|
|
|
- QueryValueArray() {
|
|
|
- kind = Query_Array;
|
|
|
- array_init(&value, query_value_allocator);
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- QueryValueArray(Array<QueryValue *> const &v) {
|
|
|
- kind = Query_Array;
|
|
|
- value = v;
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- Array<QueryValue *> value;
|
|
|
-
|
|
|
- void reserve(isize cap) {
|
|
|
- array_reserve(&value, cap);
|
|
|
- }
|
|
|
- void add(QueryValue *v) {
|
|
|
- array_add(&value, v);
|
|
|
- }
|
|
|
- void add(char const *v) {
|
|
|
- add(make_string_c(cast(char *)v));
|
|
|
- }
|
|
|
- void add(String const &v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueString);
|
|
|
- *val = QueryValueString(v);
|
|
|
- add(val);
|
|
|
- }
|
|
|
- void add(bool v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueBoolean);
|
|
|
- *val = QueryValueBoolean(v);
|
|
|
- add(val);
|
|
|
- }
|
|
|
- void add(i64 v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueInteger);
|
|
|
- *val = QueryValueInteger(v);
|
|
|
- add(val);
|
|
|
- }
|
|
|
- void add(f64 v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueFloat);
|
|
|
- *val = QueryValueFloat(v);
|
|
|
- add(val);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-struct QueryValueMap : QueryValue {
|
|
|
- QueryValueMap() {
|
|
|
- kind = Query_Map;
|
|
|
- array_init(&value, query_value_allocator);
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- QueryValueMap(Array<QueryValuePair> const &v) {
|
|
|
- kind = Query_Map;
|
|
|
- value = v;
|
|
|
- packed = false;
|
|
|
- }
|
|
|
- Array<QueryValuePair> value;
|
|
|
-
|
|
|
-
|
|
|
- void reserve(isize cap) {
|
|
|
- array_reserve(&value, cap);
|
|
|
- }
|
|
|
- void add(char const *k, QueryValue *v) {
|
|
|
- add(make_string_c(cast(char *)k), v);
|
|
|
- }
|
|
|
- void add(String const &k, QueryValue *v) {
|
|
|
- QueryValuePair kv = {k, v};
|
|
|
- array_add(&value, kv);
|
|
|
- }
|
|
|
-
|
|
|
- void add(char const *k, String const &v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueString);
|
|
|
- *val = QueryValueString(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(char const *k, char const *v) {
|
|
|
- add(k, make_string_c(cast(char *)v));
|
|
|
- }
|
|
|
- void add(char const *k, bool v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueBoolean);
|
|
|
- *val = QueryValueBoolean(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(char const *k, i64 v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueInteger);
|
|
|
- *val = QueryValueInteger(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(char const *k, f64 v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueFloat);
|
|
|
- *val = QueryValueFloat(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(String const &k, String const &v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueString);
|
|
|
- *val = QueryValueString(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(String const &k, char const *v) {
|
|
|
- add(k, make_string_c(cast(char *)v));
|
|
|
- }
|
|
|
- void add(String const &k, bool v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueBoolean);
|
|
|
- *val = QueryValueBoolean(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(String const &k, i64 v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueInteger);
|
|
|
- *val = QueryValueInteger(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
- void add(String const &k, f64 v) {
|
|
|
- auto val = gb_alloc_item(query_value_allocator, QueryValueFloat);
|
|
|
- *val = QueryValueFloat(v);
|
|
|
- add(k, val);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-#define DEF_QUERY_PROC(TYPE, VALUETYPE, NAME) TYPE *NAME(VALUETYPE value) { \
|
|
|
- auto v = gb_alloc_item(query_value_allocator, TYPE); \
|
|
|
- *v = TYPE(value); \
|
|
|
- return v; \
|
|
|
-}
|
|
|
-#define DEF_QUERY_PROC0(TYPE, NAME) TYPE *NAME() { \
|
|
|
- auto v = gb_alloc_item(query_value_allocator, TYPE); \
|
|
|
- *v = TYPE(); \
|
|
|
- return v; \
|
|
|
-}
|
|
|
-
|
|
|
-gb_internal DEF_QUERY_PROC(QueryValueString, String const &, query_value_string);
|
|
|
-gb_internal DEF_QUERY_PROC(QueryValueBoolean, bool, query_value_boolean);
|
|
|
-gb_internal DEF_QUERY_PROC(QueryValueInteger, i64, query_value_integer);
|
|
|
-gb_internal DEF_QUERY_PROC(QueryValueFloat, f64, query_value_float);
|
|
|
-gb_internal DEF_QUERY_PROC(QueryValueArray, Array<QueryValue *> const &, query_value_array);
|
|
|
-gb_internal DEF_QUERY_PROC(QueryValueMap, Array<QueryValuePair> const &, query_value_map);
|
|
|
-gb_internal DEF_QUERY_PROC0(QueryValueArray, query_value_array);
|
|
|
-gb_internal DEF_QUERY_PROC0(QueryValueMap, query_value_map);
|
|
|
-
|
|
|
-gb_internal isize qprintf(bool format, isize indent, char const *fmt, ...) {
|
|
|
- if (format) while (indent --> 0) {
|
|
|
- gb_printf("\t");
|
|
|
- }
|
|
|
- va_list va;
|
|
|
- va_start(va, fmt);
|
|
|
- isize res = gb_printf_va(fmt, va);
|
|
|
- va_end(va);
|
|
|
- return res;
|
|
|
-}
|
|
|
-
|
|
|
-gb_internal bool qv_valid_char(u8 c) {
|
|
|
- if (c >= 0x80) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- switch (c) {
|
|
|
- case '\"':
|
|
|
- case '\n':
|
|
|
- case '\r':
|
|
|
- case '\t':
|
|
|
- case '\v':
|
|
|
- case '\f':
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-gb_internal void print_query_data_as_json(QueryValue *value, bool format = true, isize indent = 0) {
|
|
|
- if (value == nullptr) {
|
|
|
- gb_printf("null");
|
|
|
- return;
|
|
|
- }
|
|
|
- switch (value->kind) {
|
|
|
- case Query_String: {
|
|
|
- auto v = cast(QueryValueString *)value;
|
|
|
- String name = v->value;
|
|
|
- isize extra = 0;
|
|
|
- for (isize i = 0; i < name.len; i++) {
|
|
|
- u8 c = name[i];
|
|
|
- if (!qv_valid_char(c)) {
|
|
|
- extra += 5;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (extra == 0) {
|
|
|
- gb_printf("\"%.*s\"", LIT(name));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- char const hex_table[] = "0123456789ABCDEF";
|
|
|
- isize buf_len = name.len + extra + 2 + 1;
|
|
|
-
|
|
|
- u8 *buf = gb_alloc_array(temporary_allocator(), u8, buf_len);
|
|
|
-
|
|
|
- isize j = 0;
|
|
|
-
|
|
|
- for (isize i = 0; i < name.len; i++) {
|
|
|
- u8 c = name[i];
|
|
|
- if (qv_valid_char(c)) {
|
|
|
- buf[j+0] = c;
|
|
|
- j += 1;
|
|
|
- } else if (c == '"') {
|
|
|
- buf[j+0] = '\\';
|
|
|
- buf[j+1] = '\"';
|
|
|
- j += 2;
|
|
|
- } else {
|
|
|
- switch (c) {
|
|
|
- case '\n': buf[j+0] = '\\'; buf[j+1] = 'n'; j += 2; break;
|
|
|
- case '\r': buf[j+0] = '\\'; buf[j+1] = 'r'; j += 2; break;
|
|
|
- case '\t': buf[j+0] = '\\'; buf[j+1] = 't'; j += 2; break;
|
|
|
- case '\v': buf[j+0] = '\\'; buf[j+1] = 'v'; j += 2; break;
|
|
|
- case '\f':
|
|
|
- default:
|
|
|
- buf[j+0] = '\\';
|
|
|
- buf[j+1] = hex_table[0];
|
|
|
- buf[j+2] = hex_table[0];
|
|
|
- buf[j+3] = hex_table[c >> 4];
|
|
|
- buf[j+4] = hex_table[c & 0x0f];
|
|
|
- j += 5;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- gb_printf("\"%s\"", buf);
|
|
|
- return;
|
|
|
- }
|
|
|
- case Query_Boolean: {
|
|
|
- auto v = cast(QueryValueBoolean *)value;
|
|
|
- if (v->value) {
|
|
|
- gb_printf("true");
|
|
|
- } else {
|
|
|
- gb_printf("false");
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- case Query_Integer: {
|
|
|
- auto v = cast(QueryValueInteger *)value;
|
|
|
- gb_printf("%lld", cast(long long)v->value);
|
|
|
- return;
|
|
|
- }
|
|
|
- case Query_Float: {
|
|
|
- auto v = cast(QueryValueFloat *)value;
|
|
|
- gb_printf("%f", v->value);
|
|
|
- return;
|
|
|
- }
|
|
|
- case Query_Array: {
|
|
|
- auto v = cast(QueryValueArray *)value;
|
|
|
- if (v->value.count > 0) {
|
|
|
- bool ff = format && !v->packed;
|
|
|
- gb_printf("[");
|
|
|
- if (ff) gb_printf("\n");
|
|
|
- for_array(i, v->value) {
|
|
|
- qprintf(ff, indent+1, "");
|
|
|
- print_query_data_as_json(v->value[i], ff, indent+1);
|
|
|
- if (i < v->value.count-1) {
|
|
|
- gb_printf(",");
|
|
|
- if (!ff && format) {
|
|
|
- gb_printf(" ");
|
|
|
- }
|
|
|
- }
|
|
|
- if (ff) gb_printf("\n");
|
|
|
- }
|
|
|
- qprintf(ff, indent, "]");
|
|
|
- } else {
|
|
|
- gb_printf("[]");
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- case Query_Map: {
|
|
|
- auto v = cast(QueryValueMap *)value;
|
|
|
- if (v->value.count > 0) {
|
|
|
- bool ff = format && !v->packed;
|
|
|
- gb_printf("{");
|
|
|
- if (ff) gb_printf("\n");
|
|
|
- for_array(i, v->value) {
|
|
|
- auto kv = v->value[i];
|
|
|
- qprintf(ff, indent+1, "\"%.*s\":", LIT(kv.key));
|
|
|
- if (format) gb_printf(" ");
|
|
|
- print_query_data_as_json(kv.value, ff, indent+1);
|
|
|
- if (i < v->value.count-1) {
|
|
|
- gb_printf(",");
|
|
|
- if (!ff && format) {
|
|
|
- gb_printf(" ");
|
|
|
- }
|
|
|
- }
|
|
|
- if (ff) gb_printf("\n");
|
|
|
- }
|
|
|
- qprintf(ff, indent, "}");
|
|
|
- } else {
|
|
|
- gb_printf("{}");
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-gb_internal int query_data_package_compare(void const *a, void const *b) {
|
|
|
- AstPackage *x = *cast(AstPackage *const *)a;
|
|
|
- AstPackage *y = *cast(AstPackage *const *)b;
|
|
|
-
|
|
|
- if (x == y) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (x != nullptr && y != nullptr) {
|
|
|
- return string_compare(x->name, y->name);
|
|
|
- } else if (x != nullptr && y == nullptr) {
|
|
|
- return -1;
|
|
|
- } else if (x == nullptr && y != nullptr) {
|
|
|
- return +1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-gb_internal int query_data_definition_compare(void const *a, void const *b) {
|
|
|
- Entity *x = *cast(Entity *const *)a;
|
|
|
- Entity *y = *cast(Entity *const *)b;
|
|
|
-
|
|
|
- if (x == y) {
|
|
|
- return 0;
|
|
|
- } else if (x != nullptr && y == nullptr) {
|
|
|
- return -1;
|
|
|
- } else if (x == nullptr && y != nullptr) {
|
|
|
- return +1;
|
|
|
- }
|
|
|
-
|
|
|
- if (x->pkg != y->pkg) {
|
|
|
- i32 res = query_data_package_compare(&x->pkg, &y->pkg);
|
|
|
- if (res != 0) {
|
|
|
- return res;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return string_compare(x->token.string, y->token.string);
|
|
|
-}
|
|
|
-
|
|
|
-gb_internal int entity_name_compare(void const *a, void const *b) {
|
|
|
- Entity *x = *cast(Entity *const *)a;
|
|
|
- Entity *y = *cast(Entity *const *)b;
|
|
|
- if (x == y) {
|
|
|
- return 0;
|
|
|
- } else if (x != nullptr && y == nullptr) {
|
|
|
- return -1;
|
|
|
- } else if (x == nullptr && y != nullptr) {
|
|
|
- return +1;
|
|
|
- }
|
|
|
- return string_compare(x->token.string, y->token.string);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-gb_internal void generate_and_print_query_data_global_definitions(Checker *c, Timings *timings);
|
|
|
-gb_internal void generate_and_print_query_data_go_to_definitions(Checker *c);
|
|
|
-
|
|
|
-gb_internal void generate_and_print_query_data(Checker *c, Timings *timings) {
|
|
|
- query_value_allocator = heap_allocator();
|
|
|
- switch (build_context.query_data_set_settings.kind) {
|
|
|
- case QueryDataSet_GlobalDefinitions:
|
|
|
- generate_and_print_query_data_global_definitions(c, timings);
|
|
|
- return;
|
|
|
- case QueryDataSet_GoToDefinitions:
|
|
|
- generate_and_print_query_data_go_to_definitions(c);
|
|
|
- return;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-gb_internal void generate_and_print_query_data_global_definitions(Checker *c, Timings *timings) {
|
|
|
- auto *root = query_value_map();
|
|
|
-
|
|
|
- if (global_error_collector.errors.count > 0) {
|
|
|
- auto *errors = query_value_array();
|
|
|
- root->add("errors", errors);
|
|
|
- for_array(i, global_error_collector.errors) {
|
|
|
- String err = string_trim_whitespace(global_error_collector.errors[i]);
|
|
|
- errors->add(err);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- { // Packages
|
|
|
- auto *packages = query_value_array();
|
|
|
- root->add("packages", packages);
|
|
|
-
|
|
|
- auto sorted_packages = array_make<AstPackage *>(query_value_allocator, 0, c->info.packages.entries.count);
|
|
|
- defer (array_free(&sorted_packages));
|
|
|
-
|
|
|
- for (auto const &entry : c->info.packages) {
|
|
|
- AstPackage *pkg = entry.value;
|
|
|
- if (pkg != nullptr) {
|
|
|
- array_add(&sorted_packages, pkg);
|
|
|
- }
|
|
|
- }
|
|
|
- gb_sort_array(sorted_packages.data, sorted_packages.count, query_data_package_compare);
|
|
|
- packages->reserve(sorted_packages.count);
|
|
|
-
|
|
|
- for_array(i, sorted_packages) {
|
|
|
- AstPackage *pkg = sorted_packages[i];
|
|
|
- String name = pkg->name;
|
|
|
- String fullpath = pkg->fullpath;
|
|
|
-
|
|
|
- auto *files = query_value_array();
|
|
|
- files->reserve(pkg->files.count);
|
|
|
- for_array(j, pkg->files) {
|
|
|
- AstFile *f = pkg->files[j];
|
|
|
- files->add(f->fullpath);
|
|
|
- }
|
|
|
-
|
|
|
- auto *package = query_value_map();
|
|
|
- package->reserve(3);
|
|
|
- packages->add(package);
|
|
|
-
|
|
|
- package->add("name", pkg->name);
|
|
|
- package->add("fullpath", pkg->fullpath);
|
|
|
- package->add("files", files);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (c->info.definitions.count > 0) {
|
|
|
- auto *definitions = query_value_array();
|
|
|
- root->add("definitions", definitions);
|
|
|
-
|
|
|
- auto sorted_definitions = array_make<Entity *>(query_value_allocator, 0, c->info.definitions.count);
|
|
|
- defer (array_free(&sorted_definitions));
|
|
|
-
|
|
|
- for_array(i, c->info.definitions) {
|
|
|
- Entity *e = c->info.definitions[i];
|
|
|
- String name = e->token.string;
|
|
|
- if (is_blank_ident(name)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if ((e->scope->flags & (ScopeFlag_Pkg|ScopeFlag_File)) == 0) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (e->parent_proc_decl != nullptr) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- switch (e->kind) {
|
|
|
- case Entity_Builtin:
|
|
|
- case Entity_Nil:
|
|
|
- case Entity_Label:
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (e->pkg == nullptr) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (e->token.pos.line == 0) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (e->kind == Entity_Procedure) {
|
|
|
- Type *t = base_type(e->type);
|
|
|
- if (t->kind != Type_Proc) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (t->Proc.is_poly_specialized) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- if (e->kind == Entity_TypeName) {
|
|
|
- Type *t = base_type(e->type);
|
|
|
- if (t->kind == Type_Struct) {
|
|
|
- if (t->Struct.is_poly_specialized) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- if (t->kind == Type_Union) {
|
|
|
- if (t->Union.is_poly_specialized) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- array_add(&sorted_definitions, e);
|
|
|
- }
|
|
|
-
|
|
|
- gb_sort_array(sorted_definitions.data, sorted_definitions.count, query_data_definition_compare);
|
|
|
- definitions->reserve(sorted_definitions.count);
|
|
|
-
|
|
|
- for_array(i, sorted_definitions) {
|
|
|
- Entity *e = sorted_definitions[i];
|
|
|
- String name = e->token.string;
|
|
|
-
|
|
|
- auto *def = query_value_map();
|
|
|
- def->reserve(16);
|
|
|
- definitions->add(def);
|
|
|
-
|
|
|
- def->add("package", e->pkg->name);
|
|
|
- def->add("name", name);
|
|
|
- def->add("filepath", get_file_path_string(e->token.pos.file_id));
|
|
|
- def->add("line", cast(i64)e->token.pos.line);
|
|
|
- def->add("column", cast(i64)e->token.pos.column);
|
|
|
- def->add("file_offset", cast(i64)e->token.pos.offset);
|
|
|
-
|
|
|
- switch (e->kind) {
|
|
|
- case Entity_Constant: def->add("kind", str_lit("constant")); break;
|
|
|
- case Entity_Variable: def->add("kind", str_lit("variable")); break;
|
|
|
- case Entity_TypeName: def->add("kind", str_lit("type name")); break;
|
|
|
- case Entity_Procedure: def->add("kind", str_lit("procedure")); break;
|
|
|
- case Entity_ProcGroup: def->add("kind", str_lit("procedure group")); break;
|
|
|
- case Entity_ImportName: def->add("kind", str_lit("import name")); break;
|
|
|
- case Entity_LibraryName: def->add("kind", str_lit("library name")); break;
|
|
|
- default: GB_PANIC("Invalid entity kind to be added");
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (e->type != nullptr && e->type != t_invalid) {
|
|
|
- Type *t = e->type;
|
|
|
- Type *bt = t;
|
|
|
-
|
|
|
- switch (e->kind) {
|
|
|
- case Entity_TypeName:
|
|
|
- if (!e->TypeName.is_type_alias) {
|
|
|
- bt = base_type(t);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- {
|
|
|
- gbString str = type_to_string(t);
|
|
|
- String type_str = make_string(cast(u8 *)str, gb_string_length(str));
|
|
|
- def->add("type", type_str);
|
|
|
- }
|
|
|
- if (t != bt) {
|
|
|
- gbString str = type_to_string(bt);
|
|
|
- String type_str = make_string(cast(u8 *)str, gb_string_length(str));
|
|
|
- def->add("base_type", type_str);
|
|
|
- }
|
|
|
- {
|
|
|
- String type_kind = {};
|
|
|
- Type *bt = base_type(t);
|
|
|
- switch (bt->kind) {
|
|
|
- case Type_Pointer: type_kind = str_lit("pointer"); break;
|
|
|
- case Type_Array: type_kind = str_lit("array"); break;
|
|
|
- case Type_Slice: type_kind = str_lit("slice"); break;
|
|
|
- case Type_DynamicArray: type_kind = str_lit("dynamic array"); break;
|
|
|
- case Type_Map: type_kind = str_lit("map"); break;
|
|
|
- case Type_Struct: type_kind = str_lit("struct"); break;
|
|
|
- case Type_Union: type_kind = str_lit("union"); break;
|
|
|
- case Type_Enum: type_kind = str_lit("enum"); break;
|
|
|
- case Type_Proc: type_kind = str_lit("procedure"); break;
|
|
|
- case Type_BitSet: type_kind = str_lit("bit set"); break;
|
|
|
- case Type_SimdVector: type_kind = str_lit("simd vector"); break;
|
|
|
-
|
|
|
- case Type_Generic:
|
|
|
- case Type_Tuple:
|
|
|
- GB_PANIC("Invalid definition type");
|
|
|
- break;
|
|
|
- }
|
|
|
- if (type_kind.len > 0) {
|
|
|
- def->add("type_kind", type_kind);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (e->kind == Entity_TypeName) {
|
|
|
- def->add("size", type_size_of(e->type));
|
|
|
- def->add("align", type_align_of(e->type));
|
|
|
-
|
|
|
-
|
|
|
- if (is_type_struct(e->type)) {
|
|
|
- auto *data = query_value_map();
|
|
|
- data->reserve(6);
|
|
|
-
|
|
|
- def->add("data", data);
|
|
|
-
|
|
|
- Type *t = base_type(e->type);
|
|
|
- GB_ASSERT(t->kind == Type_Struct);
|
|
|
-
|
|
|
- if (t->Struct.is_polymorphic) {
|
|
|
- data->add("polymorphic", cast(bool)t->Struct.is_polymorphic);
|
|
|
- }
|
|
|
- if (t->Struct.is_poly_specialized) {
|
|
|
- data->add("polymorphic_specialized", cast(bool)t->Struct.is_poly_specialized);
|
|
|
- }
|
|
|
- if (t->Struct.is_packed) {
|
|
|
- data->add("packed", cast(bool)t->Struct.is_packed);
|
|
|
- }
|
|
|
- if (t->Struct.is_raw_union) {
|
|
|
- data->add("raw_union", cast(bool)t->Struct.is_raw_union);
|
|
|
- }
|
|
|
-
|
|
|
- auto *fields = query_value_array();
|
|
|
- data->add("fields", fields);
|
|
|
- fields->reserve(t->Struct.fields.count);
|
|
|
- fields->packed = true;
|
|
|
-
|
|
|
- for_array(j, t->Struct.fields) {
|
|
|
- Entity *e = t->Struct.fields[j];
|
|
|
- String name = e->token.string;
|
|
|
- if (is_blank_ident(name)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- fields->add(name);
|
|
|
- }
|
|
|
- } else if (is_type_union(e->type)) {
|
|
|
- auto *data = query_value_map();
|
|
|
- data->reserve(4);
|
|
|
-
|
|
|
- def->add("data", data);
|
|
|
- Type *t = base_type(e->type);
|
|
|
- GB_ASSERT(t->kind == Type_Union);
|
|
|
-
|
|
|
- if (t->Union.is_polymorphic) {
|
|
|
- data->add("polymorphic", cast(bool)t->Union.is_polymorphic);
|
|
|
- }
|
|
|
- if (t->Union.is_poly_specialized) {
|
|
|
- data->add("polymorphic_specialized", cast(bool)t->Union.is_poly_specialized);
|
|
|
- }
|
|
|
-
|
|
|
- auto *variants = query_value_array();
|
|
|
- variants->reserve(t->Union.variants.count);
|
|
|
- data->add("variants", variants);
|
|
|
-
|
|
|
- for_array(j, t->Union.variants) {
|
|
|
- Type *vt = t->Union.variants[j];
|
|
|
-
|
|
|
- gbString str = type_to_string(vt);
|
|
|
- String type_str = make_string(cast(u8 *)str, gb_string_length(str));
|
|
|
- variants->add(type_str);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (e->kind == Entity_Procedure) {
|
|
|
- Type *t = base_type(e->type);
|
|
|
- GB_ASSERT(t->kind == Type_Proc);
|
|
|
-
|
|
|
- bool is_polymorphic = t->Proc.is_polymorphic;
|
|
|
- bool is_poly_specialized = t->Proc.is_poly_specialized;
|
|
|
- bool ok = is_polymorphic || is_poly_specialized;
|
|
|
- if (ok) {
|
|
|
- auto *data = query_value_map();
|
|
|
- data->reserve(4);
|
|
|
-
|
|
|
- def->add("data", data);
|
|
|
- if (is_polymorphic) {
|
|
|
- data->add("polymorphic", cast(bool)is_polymorphic);
|
|
|
- }
|
|
|
- if (is_poly_specialized) {
|
|
|
- data->add("polymorphic_specialized", cast(bool)is_poly_specialized);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (e->kind == Entity_ProcGroup) {
|
|
|
- auto *procedures = query_value_array();
|
|
|
- procedures->reserve(e->ProcGroup.entities.count);
|
|
|
-
|
|
|
- for_array(j, e->ProcGroup.entities) {
|
|
|
- Entity *p = e->ProcGroup.entities[j];
|
|
|
-
|
|
|
- auto *procedure = query_value_map();
|
|
|
- procedure->reserve(2);
|
|
|
- procedure->packed = true;
|
|
|
-
|
|
|
- procedures->add(procedure);
|
|
|
-
|
|
|
- procedure->add("package", p->pkg->name);
|
|
|
- procedure->add("name", p->token.string);
|
|
|
- }
|
|
|
- def->add("procedures", procedures);
|
|
|
- }
|
|
|
-
|
|
|
- DeclInfo *di = e->decl_info;
|
|
|
- if (di != nullptr) {
|
|
|
- if (di->is_using) {
|
|
|
- def->add("using", query_value_boolean(true));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (build_context.show_timings) {
|
|
|
- Timings *t = timings;
|
|
|
- timings__stop_current_section(t);
|
|
|
- t->total.finish = time_stamp_time_now();
|
|
|
- isize max_len = gb_min(36, t->total.label.len);
|
|
|
- for_array(i, t->sections) {
|
|
|
- TimeStamp ts = t->sections[i];
|
|
|
- max_len = gb_max(max_len, ts.label.len);
|
|
|
- }
|
|
|
- t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
|
|
|
-
|
|
|
- auto *tims = query_value_map();
|
|
|
- tims->reserve(8);
|
|
|
- root->add("timings", tims);
|
|
|
- tims->add("time_unit", str_lit("s"));
|
|
|
-
|
|
|
- tims->add(t->total.label, cast(f64)t->total_time_seconds);
|
|
|
-
|
|
|
-
|
|
|
- Parser *p = c->parser;
|
|
|
- if (p != nullptr) {
|
|
|
- isize lines = p->total_line_count;
|
|
|
- isize tokens = p->total_token_count;
|
|
|
- isize files = 0;
|
|
|
- isize packages = p->packages.count;
|
|
|
- isize total_file_size = 0;
|
|
|
- for_array(i, p->packages) {
|
|
|
- files += p->packages[i]->files.count;
|
|
|
- for_array(j, p->packages[i]->files) {
|
|
|
- AstFile *file = p->packages[i]->files[j];
|
|
|
- total_file_size += file->tokenizer.end - file->tokenizer.start;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- tims->add("total_lines", cast(i64)lines);
|
|
|
- tims->add("total_tokens", cast(i64)tokens);
|
|
|
- tims->add("total_files", cast(i64)files);
|
|
|
- tims->add("total_packages", cast(i64)packages);
|
|
|
- tims->add("total_file_size", cast(i64)total_file_size);
|
|
|
-
|
|
|
- auto *sections = query_value_map();
|
|
|
- sections->reserve(t->sections.count);
|
|
|
- tims->add("sections", sections);
|
|
|
- for_array(i, t->sections) {
|
|
|
- TimeStamp ts = t->sections[i];
|
|
|
- f64 section_time = time_stamp_as_s(ts, t->freq);
|
|
|
-
|
|
|
- auto *section = query_value_map();
|
|
|
- section->reserve(2);
|
|
|
- sections->add(ts.label, section);
|
|
|
- section->add("time", cast(f64)section_time);
|
|
|
- section->add("total_fraction", cast(f64)(section_time/t->total_time_seconds));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- print_query_data_as_json(root, !build_context.query_data_set_settings.compact);
|
|
|
- gb_printf("\n");
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-template <typename T>
|
|
|
-struct BinaryArray {
|
|
|
- u32 offset; // Offset in bytes from the top of the file
|
|
|
- u32 length; // Number of elements in array of type T
|
|
|
-};
|
|
|
-
|
|
|
-template <typename T>
|
|
|
-gb_internal Array<T> binary_array_from_data(BinaryArray<T> ba, void *data) {
|
|
|
- Array<T> res = {};
|
|
|
- res.data = cast(T *)(cast(u8 *)data + ba.offset);
|
|
|
- res.count = ba.length;
|
|
|
- res.capacity = ba.length;
|
|
|
- return res;
|
|
|
-}
|
|
|
-
|
|
|
-typedef BinaryArray<u8> BinaryString;
|
|
|
-
|
|
|
-struct GoToDefIdent {
|
|
|
- u64 use_offset; // offset of identifier use in bytes from the start of the file that contains it
|
|
|
- u32 len; // length in bytes of the identifier
|
|
|
- u32 def_file_id;
|
|
|
- u64 def_offset; // offset of entity definition in bytes from the start of the file that contains it
|
|
|
-};
|
|
|
-
|
|
|
-struct GoToDefFile {
|
|
|
- u32 id;
|
|
|
- BinaryString path;
|
|
|
- BinaryArray<GoToDefIdent> idents;
|
|
|
-};
|
|
|
-
|
|
|
-struct GoToDefHeader {
|
|
|
- u8 magic[4]; // ogtd (odin-go-to-definitions)
|
|
|
- u32 version; // 1
|
|
|
- BinaryArray<GoToDefFile> files;
|
|
|
-};
|
|
|
-
|
|
|
-struct GoToDefFileMap {
|
|
|
- AstFile *f;
|
|
|
- u32 id;
|
|
|
- Array<Ast *> idents;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-gb_internal int go_to_def_file_map_compare(void const *a, void const *b) {
|
|
|
- GoToDefFileMap const *x = cast(GoToDefFileMap const *)a;
|
|
|
- GoToDefFileMap const *y = cast(GoToDefFileMap const *)b;
|
|
|
- if (x == y) {
|
|
|
- return 0;
|
|
|
- } else if (x != nullptr && y == nullptr) {
|
|
|
- return -1;
|
|
|
- } else if (x == nullptr && y != nullptr) {
|
|
|
- return +1;
|
|
|
- }
|
|
|
- if (x->f->id < y->f->id) {
|
|
|
- return -1;
|
|
|
- } else if (x->f->id > y->f->id) {
|
|
|
- return +1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-gb_internal int quick_ident_compare(void const *a, void const *b) {
|
|
|
- Ast *x = *cast(Ast **)a;
|
|
|
- Ast *y = *cast(Ast **)b;
|
|
|
-
|
|
|
- // NOTE(bill): This assumes that the file is same
|
|
|
- if (x->Ident.token.pos.offset < y->Ident.token.pos.offset) {
|
|
|
- return -1;
|
|
|
- } else if (x->Ident.token.pos.offset > y->Ident.token.pos.offset) {
|
|
|
- return +1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-gb_internal void generate_and_print_query_data_go_to_definitions(Checker *c) {
|
|
|
- GB_ASSERT(c->info.allow_identifier_uses);
|
|
|
-
|
|
|
- gbAllocator a = query_value_allocator;
|
|
|
-
|
|
|
- isize file_path_memory_needed = 0;
|
|
|
- auto files = array_make<GoToDefFileMap>(a, 0, c->info.files.entries.count);
|
|
|
- for (auto const &entry : c->info.files) {
|
|
|
- AstFile *f = entry.value;
|
|
|
- file_path_memory_needed += f->fullpath.len+1; // add NUL terminator
|
|
|
-
|
|
|
-
|
|
|
- GoToDefFileMap x = {};
|
|
|
- x.f = f;
|
|
|
- array_init(&x.idents, a);
|
|
|
- array_add(&files, x);
|
|
|
- }
|
|
|
- gb_sort_array(files.data, files.count, go_to_def_file_map_compare);
|
|
|
-
|
|
|
- auto file_id_map_to_index = array_make<isize>(a, files[files.count-1].f->id + 1);
|
|
|
- for_array(i, file_id_map_to_index) {
|
|
|
- file_id_map_to_index[i] = -1;
|
|
|
- }
|
|
|
- for_array(i, files) {
|
|
|
- file_id_map_to_index[files[i].f->id] = i;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- for_array(i, c->info.identifier_uses) {
|
|
|
- Ast *ast = c->info.identifier_uses[i];
|
|
|
- GB_ASSERT(ast->kind == Ast_Ident);
|
|
|
- TokenPos pos = ast->Ident.token.pos;
|
|
|
- Entity *e = ast->Ident.entity;
|
|
|
- if (e == nullptr) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- AstFile **use_file_found = string_map_get(&c->info.files, get_file_path_string(pos.file_id));
|
|
|
- GB_ASSERT(use_file_found != nullptr);
|
|
|
- AstFile *use_file = *use_file_found;
|
|
|
- GB_ASSERT(use_file != nullptr);
|
|
|
-
|
|
|
- if (e->scope == nullptr) {
|
|
|
- GB_ASSERT(e->flags & EntityFlag_Field);
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (e->scope->flags & ScopeFlag_Global) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- isize idx = file_id_map_to_index[use_file->id];
|
|
|
- if (idx >= 0) {
|
|
|
- array_add(&files[idx].idents, ast);
|
|
|
- } else {
|
|
|
- // TODO(bill): Handle invalid map case?
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for_array(i, files) {
|
|
|
- GoToDefFileMap *f = &files[i];
|
|
|
- gb_sort_array(f->idents.data, f->idents.count, quick_ident_compare);
|
|
|
- // gb_printf_err("%lld %.*s -> %lld\n", f->f->id, LIT(f->f->fullpath), f->idents.count);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- isize data_min_size = 0;
|
|
|
-
|
|
|
- u32 header_offset = cast(u32)data_min_size; gb_unused(header_offset);
|
|
|
- data_min_size += gb_size_of(GoToDefHeader);
|
|
|
- data_min_size = align_formula_isize(data_min_size, 8);
|
|
|
-
|
|
|
- u32 file_offset = cast(u32)data_min_size;
|
|
|
- data_min_size += gb_size_of(GoToDefFile) * files.count;
|
|
|
- data_min_size = align_formula_isize(data_min_size, 8);
|
|
|
-
|
|
|
- u32 file_path_offset = cast(u32)data_min_size;
|
|
|
- data_min_size += file_path_memory_needed;
|
|
|
- data_min_size = align_formula_isize(data_min_size, 8);
|
|
|
-
|
|
|
- u32 idents_offset = cast(u32)data_min_size;
|
|
|
- data_min_size += gb_size_of(GoToDefIdent) * c->info.identifier_uses.count;
|
|
|
-
|
|
|
-
|
|
|
- auto data = array_make<u8>(a, 0, data_min_size);
|
|
|
- defer (array_free(&data));
|
|
|
-
|
|
|
- GoToDefHeader header = {};
|
|
|
- gb_memmove(header.magic, "ogtd", 4);
|
|
|
- header.version = 1;
|
|
|
- header.files.length = cast(u32)files.count;
|
|
|
- header.files.offset = file_offset;
|
|
|
-
|
|
|
- array_add_elems(&data, cast(u8 *)&header, gb_size_of(header));
|
|
|
-
|
|
|
- array_resize(&data, data_min_size);
|
|
|
-
|
|
|
- auto binary_files = binary_array_from_data(header.files, data.data);
|
|
|
-
|
|
|
- u32 file_path_offset_index = file_path_offset;
|
|
|
- u32 idents_offset_index = idents_offset;
|
|
|
- for_array(i, files) {
|
|
|
- GoToDefFileMap *f_map = &files[i];
|
|
|
- AstFile *f = f_map->f;
|
|
|
- binary_files[i].id = cast(u32)f->id;
|
|
|
-
|
|
|
- binary_files[i].path.offset = file_path_offset_index;
|
|
|
- binary_files[i].path.length = cast(u32)f->fullpath.len;
|
|
|
-
|
|
|
- binary_files[i].idents.offset = idents_offset_index;
|
|
|
- binary_files[i].idents.length = cast(u32)f_map->idents.count;
|
|
|
-
|
|
|
- auto path = binary_array_from_data(binary_files[i].path, data.data);
|
|
|
- gb_memmove(path.data, f->fullpath.text, f->fullpath.len);
|
|
|
- path.data[f->fullpath.len] = 0;
|
|
|
-
|
|
|
-
|
|
|
- auto idents = binary_array_from_data(binary_files[i].idents, data.data);
|
|
|
- for_array(j, f_map->idents) {
|
|
|
- Ast *ast = f_map->idents[j];
|
|
|
- GB_ASSERT(ast->kind == Ast_Ident);
|
|
|
-
|
|
|
- Entity *e = ast->Ident.entity;
|
|
|
- TokenPos def = e->token.pos;
|
|
|
- AstFile *def_file = e->file;
|
|
|
-
|
|
|
- if (def_file == nullptr) {
|
|
|
- auto *def_file_found = string_map_get(&c->info.files, get_file_path_string(e->token.pos.file_id));
|
|
|
- if (def_file_found == nullptr) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- def_file = *def_file_found;
|
|
|
- }
|
|
|
-
|
|
|
- isize file_index = file_id_map_to_index[def_file->id];
|
|
|
- GB_ASSERT(file_index >= 0);
|
|
|
-
|
|
|
- idents[j].use_offset = cast(u64)ast->Ident.token.pos.offset;
|
|
|
- idents[j].len = cast(u32)ast->Ident.token.string.len;
|
|
|
- idents[j].def_file_id = cast(u32)def_file->id;
|
|
|
- idents[j].def_offset = cast(u64)e->token.pos.offset;
|
|
|
-
|
|
|
- // gb_printf_err("%llu %llu %llu %llu\n", idents[j].len, idents[j].use_offset, idents[j].def_file_id, idents[j].def_offset);
|
|
|
- }
|
|
|
-
|
|
|
- file_path_offset_index += cast(u32)(f->fullpath.len + 1);
|
|
|
- idents_offset_index += cast(u32)(f_map->idents.count * gb_size_of(GoToDefIdent));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- gb_file_write(gb_file_get_standard(gbFileStandard_Output), data.data, data.count*gb_size_of(*data.data));
|
|
|
-}
|
|
|
-
|