mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Improve the raddbg type views generated from fmt-based struct field tags
This commit is contained in:
+269
-146
@@ -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) {
|
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); /**/) {
|
for (Entity *e = nullptr; mpsc_dequeue(&c->procs_with_objc_context_provider_to_check, &e); /**/) {
|
||||||
GB_ASSERT(e->kind == Entity_TypeName);
|
GB_ASSERT(e->kind == Entity_TypeName);
|
||||||
@@ -7059,152 +7326,8 @@ gb_internal void check_parsed_files(Checker *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TIME_SECTION("collate type info stuff");
|
TIME_SECTION("collate type info stuff");
|
||||||
{
|
for (RaddbgTypeView type_view; mpsc_dequeue(&c->info.raddbg_type_views_queue, &type_view); /**/) {
|
||||||
auto const struct_tag_lookup = [](String tag, char const *key_c, String *value_) -> bool {
|
handle_raddbg_type_view(c, type_view);
|
||||||
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});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user