mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-21 21:24:59 -07:00
Add @(raddbg_type_view=<optional-string>)
If no string parameter is provided, then one will be generated from the struct field tags. The attribute must be applied if the automatic struct field tag approach is to be used.
This commit is contained in:
+170
@@ -1451,6 +1451,9 @@ gb_internal void init_checker_info(CheckerInfo *i) {
|
||||
mpsc_init(&i->foreign_decls_to_check, a); // 1<<10);
|
||||
mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
|
||||
|
||||
mpsc_init(&i->raddbg_type_views_queue, a);
|
||||
array_init(&i->raddbg_type_views, a);
|
||||
|
||||
string_map_init(&i->load_directory_cache);
|
||||
map_init(&i->load_directory_map);
|
||||
}
|
||||
@@ -1479,6 +1482,9 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
|
||||
mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
|
||||
mpsc_destroy(&i->foreign_decls_to_check);
|
||||
|
||||
mpsc_destroy(&i->raddbg_type_views_queue);
|
||||
array_free(&i->raddbg_type_views);
|
||||
|
||||
map_destroy(&i->objc_msgSend_types);
|
||||
string_set_destroy(&i->obcj_class_name_set);
|
||||
mpsc_destroy(&i->objc_class_implementations);
|
||||
@@ -4066,6 +4072,21 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) {
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (name == "raddbg_type_view") {
|
||||
ExactValue ev = check_decl_attribute_value(c, value);
|
||||
if (ev.kind == ExactValue_Invalid) {
|
||||
ac->raddbg_type_view = true;
|
||||
} else if (ev.kind == ExactValue_String) {
|
||||
ac->raddbg_type_view = true;
|
||||
ac->raddbg_type_view_string = ev.value_string;
|
||||
|
||||
if (ev.value_string.len == 0) {
|
||||
error(elem, "Expected a non-empty string for '%.*s'", LIT(name));
|
||||
}
|
||||
} else {
|
||||
error(elem, "Expected a string or no value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -7037,6 +7058,155 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
}
|
||||
}
|
||||
|
||||
TIME_SECTION("collate type info stuff");
|
||||
{
|
||||
auto const struct_tag_lookup = [](String tag, char const *key_c, String *value_) -> bool {
|
||||
String t = tag;
|
||||
String key = make_string_c(key_c);
|
||||
while (t.len != 0) {
|
||||
isize i = 0;
|
||||
while (i < t.len && t[i] == ' ') { // Skip whitespace
|
||||
i += 1;
|
||||
}
|
||||
t.text += i;
|
||||
t.len -= i;
|
||||
if (t.len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < t.len) {
|
||||
u8 c = t[i];
|
||||
if (c == ':' || c == '"') {
|
||||
break;
|
||||
} else if ((0 <= c && c < ' ') || (0x7f <= c && c <= 0x9f)) {
|
||||
// break if control character is found
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
break;
|
||||
}
|
||||
if (i+1 >= t.len) {
|
||||
break;
|
||||
}
|
||||
if (t[i] != ':' || t[i+1] != '"') {
|
||||
break;
|
||||
}
|
||||
String name = {t.text, i};
|
||||
t = {t.text+i+1, t.len-(i+1)};
|
||||
|
||||
i = 1;
|
||||
while (i < t.len && t[i] != '"') { // find closing quote
|
||||
if (t[i] == '\\') {
|
||||
i += 1; // Skip escaped characters
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if (i >= t.len) {
|
||||
break;
|
||||
}
|
||||
|
||||
String value = {t.text, i+1};
|
||||
t = {t.text+i+1, t.len-(i+1)};
|
||||
|
||||
if (key == name) {
|
||||
value = {value.text+1, i-1};
|
||||
if (value_) *value_ = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (RaddbgTypeView type_view; mpsc_dequeue(&c->info.raddbg_type_views_queue, &type_view); /**/) {
|
||||
|
||||
Type *type = type_view.type;
|
||||
if (type == nullptr || type == t_invalid) {
|
||||
continue;
|
||||
}
|
||||
String view = type_view.view;
|
||||
if (view.len == 0) {
|
||||
// NOTE(bill): Generate one automatically from the struct field tags if they exist
|
||||
// If it cannot be generated, it'll be ignored/err
|
||||
|
||||
Type *bt = base_type(type);
|
||||
if (is_type_struct(type)) {
|
||||
GB_ASSERT(bt->kind == Type_Struct);
|
||||
if (bt->Struct.tags != nullptr) {
|
||||
bool found_any = false;
|
||||
|
||||
for (isize i = 0; i < bt->Struct.fields.count; i++) {
|
||||
String tag = bt->Struct.tags[i];
|
||||
String value = {};
|
||||
if (struct_tag_lookup(tag, "raddbg", &value)) {
|
||||
found_any = true;
|
||||
} else if (struct_tag_lookup(tag, "fmt", &value)) {
|
||||
found_any = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_any) {
|
||||
goto raddbg_type_view_end;
|
||||
}
|
||||
|
||||
gbString s = gb_string_make(heap_allocator(), "");
|
||||
|
||||
s = gb_string_appendc(s, "rows($");
|
||||
|
||||
for (isize i = 0; i < bt->Struct.fields.count; i++) {
|
||||
Entity *field = bt->Struct.fields[i];
|
||||
GB_ASSERT(field != nullptr);
|
||||
String name = field->token.string;
|
||||
|
||||
s = gb_string_appendc(s, ", ");
|
||||
|
||||
bool custom_rule = false;
|
||||
|
||||
String tag = bt->Struct.tags[i];
|
||||
String value = {};
|
||||
if (struct_tag_lookup(tag, "raddbg", &value)) {
|
||||
s = gb_string_append_length(s, value.text, value.len);
|
||||
custom_rule = true;
|
||||
} else if (struct_tag_lookup(tag, "fmt", &value)) {
|
||||
auto p = string_partition(value, make_string_c(","));
|
||||
String tail = p.tail;
|
||||
if (tail.len != 0 && tail != "0") {
|
||||
s = gb_string_appendc(s, "array(");
|
||||
s = gb_string_append_length(s, name.text, name.len);
|
||||
s = gb_string_appendc(s, ", ");
|
||||
s = gb_string_append_length(s, tail.text, tail.len);
|
||||
s = gb_string_appendc(s, ")");
|
||||
custom_rule = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!custom_rule) {
|
||||
s = gb_string_append_length(s, name.text, name.len);
|
||||
}
|
||||
}
|
||||
|
||||
s = gb_string_appendc(s, ")");
|
||||
|
||||
view = make_string((u8 const *)s, gb_string_length(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raddbg_type_view_end:;
|
||||
|
||||
if (view.len == 0) {
|
||||
// Ignore the type, it didn't anything custom
|
||||
continue;
|
||||
}
|
||||
|
||||
array_add(&c->info.raddbg_type_views, RaddbgTypeView{type, view});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TIME_SECTION("type check finish");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user