diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-25 19:21:04 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-25 19:21:04 +0200 |
commit | e61947196d898232d40a63d5bbe40ec82b260c03 (patch) | |
tree | 878b580d6403143bcca43392c28a1ef525f2b02a /src | |
parent | 90507290b8b6f9d15605c53480225f5a10a36ca7 (diff) | |
download | bdl-e61947196d898232d40a63d5bbe40ec82b260c03.tar.gz bdl-e61947196d898232d40a63d5bbe40ec82b260c03.zip |
Bugfixes for struct accessors
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 96 |
1 files changed, 45 insertions, 51 deletions
@@ -13,6 +13,8 @@ | |||
13 | // TODO: match deconstruct structs | 13 | // TODO: match deconstruct structs |
14 | // TODO: arrays and pointers | 14 | // TODO: arrays and pointers |
15 | // TODO: struct literals with compound types | 15 | // TODO: struct literals with compound types |
16 | // FIXME: there may be an issue with shadowed structs sharing fields... we may | ||
17 | // want to consider moving the fields to separate maps again... | ||
16 | 18 | ||
17 | typedef enum ExecMode { | 19 | typedef enum ExecMode { |
18 | RUN_NORMAL, | 20 | RUN_NORMAL, |
@@ -378,23 +380,19 @@ emit_semantic_error(Analyzer *a, Node *n, Str msg) { | |||
378 | Type type_inference(Analyzer *a, Node *node, TypeScope *scope); | 380 | Type type_inference(Analyzer *a, Node *node, TypeScope *scope); |
379 | 381 | ||
380 | void | 382 | void |
381 | typecheck_field(Analyzer *a, | 383 | typecheck_field(Analyzer *a, Node *node, TypeScope *scope, Str symbol) { |
382 | Node *node, | ||
383 | TypeScope *scope, | ||
384 | Str symbol, | ||
385 | StructMap *map) { | ||
386 | // TODO: ensure the tables are filled properly. | 384 | // TODO: ensure the tables are filled properly. |
387 | if (node->field_type->kind == NODE_COMPOUND_TYPE) { | 385 | if (node->field_type->kind == NODE_COMPOUND_TYPE) { |
388 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 386 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
389 | field_name = str_concat(field_name, node->value.str, a->storage); | 387 | field_name = str_concat(field_name, node->value.str, a->storage); |
390 | if (structmap_lookup(&map, field_name)) { | 388 | if (structmap_lookup(&scope->structs, field_name)) { |
391 | eprintln("%s:%d:%d: error: struct field '%s' already exists", | 389 | eprintln("%s:%d:%d: error: struct field '%s' already exists", |
392 | a->file_name, node->line, node->col, field_name); | 390 | a->file_name, node->line, node->col, field_name); |
393 | } | 391 | } |
394 | Str type = cstr("\\{ "); | 392 | Str type = cstr("\\{ "); |
395 | for (sz i = 0; i < array_size(node->field_type->elements); i++) { | 393 | for (sz i = 0; i < array_size(node->field_type->elements); i++) { |
396 | Node *field = node->field_type->elements[i]; | 394 | Node *field = node->field_type->elements[i]; |
397 | typecheck_field(a, field, scope, field_name, map); | 395 | typecheck_field(a, field, scope, field_name); |
398 | type = str_concat(type, field->type, a->storage); | 396 | type = str_concat(type, field->type, a->storage); |
399 | type = str_concat(type, cstr(" "), a->storage); | 397 | type = str_concat(type, cstr(" "), a->storage); |
400 | } | 398 | } |
@@ -408,7 +406,7 @@ typecheck_field(Analyzer *a, | |||
408 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | 406 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, |
409 | node->field_type->line, node->field_type->col, field_type); | 407 | node->field_type->line, node->field_type->col, field_type); |
410 | } | 408 | } |
411 | if (structmap_lookup(&map, field_name)) { | 409 | if (structmap_lookup(&scope->structs, field_name)) { |
412 | eprintln("%s:%d:%d: error: struct field '%s' already exists", | 410 | eprintln("%s:%d:%d: error: struct field '%s' already exists", |
413 | a->file_name, node->line, node->col, field_name); | 411 | a->file_name, node->line, node->col, field_name); |
414 | } | 412 | } |
@@ -423,7 +421,7 @@ typecheck_field(Analyzer *a, | |||
423 | field_type); | 421 | field_type); |
424 | } | 422 | } |
425 | } | 423 | } |
426 | structmap_insert(&map, field_name, | 424 | structmap_insert(&scope->structs, field_name, |
427 | (Struct){ | 425 | (Struct){ |
428 | .name = field_name, | 426 | .name = field_name, |
429 | .type = field_type, | 427 | .type = field_type, |
@@ -584,11 +582,11 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
584 | node->type = cstr("nil"); | 582 | node->type = cstr("nil"); |
585 | Str symbol = node->value.str; | 583 | Str symbol = node->value.str; |
586 | // TODO: make sure it didn't exist before. | 584 | // TODO: make sure it didn't exist before. |
587 | StructMap *e = structmap_insert( | 585 | structmap_insert(&scope->structs, symbol, (Struct){.name = symbol}, |
588 | &scope->structs, symbol, (Struct){.name = symbol}, a->storage); | 586 | a->storage); |
589 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 587 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
590 | Node *field = node->struct_field[i]; | 588 | Node *field = node->struct_field[i]; |
591 | typecheck_field(a, field, scope, symbol, e); | 589 | typecheck_field(a, field, scope, symbol); |
592 | } | 590 | } |
593 | typemap_insert(&scope->types, symbol, symbol, a->storage); | 591 | typemap_insert(&scope->types, symbol, symbol, a->storage); |
594 | return node->type; | 592 | return node->type; |
@@ -597,18 +595,18 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
597 | node->type = cstr("nil"); | 595 | node->type = cstr("nil"); |
598 | Str symbol = node->value.str; | 596 | Str symbol = node->value.str; |
599 | // TODO: make sure it didn't exist before. | 597 | // TODO: make sure it didn't exist before. |
600 | EnumMap *e = enummap_insert(&scope->enums, symbol, | 598 | enummap_insert(&scope->enums, symbol, |
601 | (Enum){ | 599 | (Enum){ |
602 | .name = symbol, | 600 | .name = symbol, |
603 | .val = node->field_val, | 601 | .val = node->field_val, |
604 | }, | 602 | }, |
605 | a->storage); | 603 | a->storage); |
606 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 604 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
607 | Node *field = node->struct_field[i]; | 605 | Node *field = node->struct_field[i]; |
608 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 606 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
609 | field_name = | 607 | field_name = |
610 | str_concat(field_name, field->value.str, a->storage); | 608 | str_concat(field_name, field->value.str, a->storage); |
611 | if (enummap_lookup(&e, field_name)) { | 609 | if (enummap_lookup(&scope->enums, field_name)) { |
612 | eprintln("%s:%d:%d: error: enum field '%s' already exists", | 610 | eprintln("%s:%d:%d: error: enum field '%s' already exists", |
613 | a->file_name, field->line, field->col, field_name); | 611 | a->file_name, field->line, field->col, field_name); |
614 | } | 612 | } |
@@ -621,8 +619,8 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
621 | field_name); | 619 | field_name); |
622 | } | 620 | } |
623 | } | 621 | } |
624 | enummap_insert(&e, field_name, (Enum){.name = field_name}, | 622 | enummap_insert(&scope->enums, field_name, |
625 | a->storage); | 623 | (Enum){.name = field_name}, a->storage); |
626 | field->type = cstr("int"); | 624 | field->type = cstr("int"); |
627 | } | 625 | } |
628 | typemap_insert(&scope->types, symbol, symbol, a->storage); | 626 | typemap_insert(&scope->types, symbol, symbol, a->storage); |
@@ -899,28 +897,39 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
899 | a->file_name, node->line, node->col, name); | 897 | a->file_name, node->line, node->col, name); |
900 | return cstr(""); | 898 | return cstr(""); |
901 | } | 899 | } |
900 | |||
901 | StrSet *set = NULL; | ||
902 | for (sz i = 0; i < array_size(node->elements); i++) { | 902 | for (sz i = 0; i < array_size(node->elements); i++) { |
903 | Node *next = node->elements[i]; | 903 | Node *next = node->elements[i]; |
904 | Str field_name = next->value.str; | 904 | Str field_name = str_concat(name, cstr("."), a->storage); |
905 | FieldMap *field = fieldmap_lookup(&s->val.fields, field_name); | 905 | field_name = |
906 | if (!field) { | 906 | str_concat(field_name, next->value.str, a->storage); |
907 | |||
908 | if (strset_lookup(&set, field_name)) { | ||
907 | eprintln( | 909 | eprintln( |
908 | "%s:%d:%d: error: unknown struct field for symbol '%s'", | 910 | "%s:%d:%d: error: field '%s' already present in struct " |
911 | "literal", | ||
909 | a->file_name, next->line, next->col, field_name); | 912 | a->file_name, next->line, next->col, field_name); |
910 | } else { | 913 | } else { |
911 | if (next->field_val) { | 914 | strset_insert(&set, field_name, a->storage); |
912 | Type type = type_inference(a, next->field_val, scope); | 915 | } |
913 | if (!str_eq(type, field->val.type)) { | 916 | |
914 | eprintln( | 917 | StructMap *field = find_struct(scope, field_name); |
915 | "%s:%d:%d: error: mismatched types in struct " | 918 | if (!field) { |
916 | "value " | 919 | eprintln("%s:%d:%d: error: unknown struct field '%s'", |
917 | "for '%s.%s': %s expected %s", | 920 | a->file_name, next->line, next->col, field_name); |
918 | a->file_name, next->line, next->col, name, | 921 | } else { |
919 | field_name, type, field->val.type); | 922 | Type type = type_inference(a, next->field_val, scope); |
920 | } | 923 | if (!str_eq(type, field->val.type)) { |
924 | eprintln( | ||
925 | "%s:%d:%d: error: mismatched types in struct " | ||
926 | "literal for '%s': %s expected %s ", | ||
927 | a->file_name, next->line, next->col, field_name, | ||
928 | type, field->val.type); | ||
921 | } | 929 | } |
922 | next->type = field->val.type; | 930 | next->type = type; |
923 | } | 931 | } |
932 | // TODO: nested fields. | ||
924 | } | 933 | } |
925 | node->type = name; | 934 | node->type = name; |
926 | return node->type; | 935 | return node->type; |
@@ -1088,21 +1097,6 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
1088 | 1097 | ||
1089 | void | 1098 | void |
1090 | analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { | 1099 | analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { |
1091 | // TODO: Struct field initializers need to be checked... when we | ||
1092 | // get to that. Note that for checking symbol chains, we need to | ||
1093 | // first perform type analysis to know the variable is a certain | ||
1094 | // type: | ||
1095 | // | ||
1096 | // struct T { | ||
1097 | // field_a: int | ||
1098 | // field_b: int | ||
1099 | // } | ||
1100 | // let a:my_struct | ||
1101 | // set a.field_a = 1 | ||
1102 | // | ||
1103 | // In this case we need to know that variable a is of type `T` which | ||
1104 | // contains fields `field_a` and `field_b`. | ||
1105 | // | ||
1106 | assert(a); | 1100 | assert(a); |
1107 | assert(scope); | 1101 | assert(scope); |
1108 | if (!node) { | 1102 | if (!node) { |