diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2025-08-22 09:29:07 +0100 |
|---|---|---|
| committer | gingerBill <gingerBill@users.noreply.github.com> | 2025-08-22 09:29:07 +0100 |
| commit | 23689d0c01895aeb0f0faaee9ff1008732d6fd13 (patch) | |
| tree | c07e106442ef6dc28ab9f71688600e717fbb03cb /src | |
| parent | d5b1fc48fbc5f853e8995ca520417a69fbad701a (diff) | |
Improve the raddbg type views generated from `fmt`-based struct field tags
Diffstat (limited to 'src')
| -rw-r--r-- | src/checker.cpp | 415 |
1 files changed, 269 insertions, 146 deletions
diff --git a/src/checker.cpp b/src/checker.cpp index c6dd1643a..a1a668038 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -6581,6 +6581,273 @@ gb_internal void check_deferred_procedures(Checker *c) { } +gb_internal void handle_raddbg_type_view(Checker *c, RaddbgTypeView const &type_view) { + 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}; + value = string_trim_whitespace(value); + if (value_) *value_ = value; + return true; + } + } + return false; + }; + + auto const parse_int = [](String s, isize *offset_, u64 *result_) -> bool { + isize offset = *offset_; + isize new_offset = *offset_; + + u64 result = 0; + + while (new_offset < s.len) { + u8 c = s[new_offset]; + if (!('0' <= c && c <= '9')) { + break; + } + + new_offset += 1; + result *= 10; + result += u64(c)-'0'; + } + + *offset_ = new_offset; + *result_ = result; + return new_offset > offset; + }; + + Type *type = type_view.type; + if (type == nullptr || type == t_invalid) { + return; + } + String view = type_view.view; + if (view.len != 0) { + array_add(&c->info.raddbg_type_views, RaddbgTypeView{type, view}); + return; + } + + // 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) { + return; + } + + 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; + String tag = bt->Struct.tags[i]; + String value = {}; + bool custom_rule = false; + + bool raddbg_seen = false; + if (struct_tag_lookup(tag, "raddbg", &value)) { + raddbg_seen = true; + if (value == "-") { + // Ignore this field entirely; + continue; + } + } + + s = gb_string_appendc(s, ", "); + + if (raddbg_seen) { + if (value == "") { + // ignore + } else { + s = gb_string_append_length(s, value.text, value.len); + custom_rule = true; + } + } else if (struct_tag_lookup(tag, "fmt", &value)) { + if (value == "" || value == "-") { + // ignore + } else { + auto p = string_partition(value, make_string_c(",")); + String head = p.head; + String tail = p.tail; + + isize i = 0; + + for (bool ok = true; ok && i < head.len; i += 1) { + switch (head[i]) { + case '+': + case '-': + case ' ': + case '#': + case '0': + break; + default: + i -= 1; + ok = false; + break; + } + } + + u64 prec = 0; + u64 width = 0; + bool width_ok = parse_int(head, &i, &width); + bool prec_ok = false; + if (i < head.len && head[i] == '.') { + i += 1; + prec_ok = parse_int(head, &i, &prec); + } + + + Rune verb = 0; + if (i >= head.len || head[i] == ' ') { + verb = 'v'; + } else { + utf8_decode(head.text+i, head.len-i, &verb); + } + + isize paren_count = 0; + + + if (width_ok) { + s = gb_string_appendc(s, "digits("); + paren_count += 1; + } + + switch (verb) { + case 'b': + s = gb_string_appendc(s, "bin("); + paren_count += 1; + break; + case 'd': + s = gb_string_appendc(s, "dec("); + paren_count += 1; + break; + case 'x': + case 'X': + s = gb_string_appendc(s, "hex("); + paren_count += 1; + break; + case 'o': + s = gb_string_appendc(s, "oct("); + paren_count += 1; + break; + } + + + if (tail.len != 0 && tail != "0") { + s = gb_string_appendc(s, "array("); + s = gb_string_append_length(s, name.text, name.len); + if (is_type_slice(field->type) || is_type_dynamic_array(field->type)) { + s = gb_string_appendc(s, ".data"); + } + s = gb_string_appendc(s, ", "); + s = gb_string_append_length(s, tail.text, tail.len); + s = gb_string_appendc(s, ")"); + custom_rule = true; + } else { + s = gb_string_append_length(s, name.text, name.len); + custom_rule = true; + } + + if (width_ok) { + s = gb_string_append_fmt(s, ", %llu", cast(unsigned long long)width); + } + + for (isize j = 0; j < paren_count; j++) { + 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, ")"); + + + gb_printf_err("%s\n", s); + view = make_string((u8 const *)s, gb_string_length(s)); + } + } + + if (view.len == 0) { + // Ignore the type, it didn't anything custom + return; + } + + array_add(&c->info.raddbg_type_views, RaddbgTypeView{type, view}); +} + gb_internal void check_objc_context_provider_procedures(Checker *c) { for (Entity *e = nullptr; mpsc_dequeue(&c->procs_with_objc_context_provider_to_check, &e); /**/) { GB_ASSERT(e->kind == Entity_TypeName); @@ -7059,152 +7326,8 @@ 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}); - } + for (RaddbgTypeView type_view; mpsc_dequeue(&c->info.raddbg_type_views_queue, &type_view); /**/) { + handle_raddbg_type_view(c, type_view); } |