aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-08-22 09:29:07 +0100
committergingerBill <gingerBill@users.noreply.github.com>2025-08-22 09:29:07 +0100
commit23689d0c01895aeb0f0faaee9ff1008732d6fd13 (patch)
treec07e106442ef6dc28ab9f71688600e717fbb03cb /src
parentd5b1fc48fbc5f853e8995ca520417a69fbad701a (diff)
Improve the raddbg type views generated from `fmt`-based struct field tags
Diffstat (limited to 'src')
-rw-r--r--src/checker.cpp415
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);
}