diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-25 17:45:27 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-25 17:45:27 +0200 |
commit | bc9aa6e8ad03cd739cd54a9b97f78a14287b9fbd (patch) | |
tree | 03f4fa7387a931ea62c7999e3bc4f8839ccce355 /src | |
parent | 1980bc35c8d161089d3f996abcce80bc67056736 (diff) | |
download | bdl-bc9aa6e8ad03cd739cd54a9b97f78a14287b9fbd.tar.gz bdl-bc9aa6e8ad03cd739cd54a9b97f78a14287b9fbd.zip |
Add inner struct typechecking
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 206 |
1 files changed, 133 insertions, 73 deletions
@@ -9,11 +9,10 @@ | |||
9 | 9 | ||
10 | // TODO: in a let/set expression if the type is a struct check that we | 10 | // TODO: in a let/set expression if the type is a struct check that we |
11 | // are assigning a struct literal, not just a symbol. | 11 | // are assigning a struct literal, not just a symbol. |
12 | // TODO: nested structs | ||
13 | // TODO: unions | 12 | // TODO: unions |
14 | // TODO: match deconstruct structs | 13 | // TODO: match deconstruct structs |
15 | // TODO: arrays and pointers | 14 | // TODO: arrays and pointers |
16 | // TODO: struct literals | 15 | // TODO: struct literals with compound types |
17 | 16 | ||
18 | typedef enum ExecMode { | 17 | typedef enum ExecMode { |
19 | RUN_NORMAL, | 18 | RUN_NORMAL, |
@@ -68,20 +67,15 @@ typedef struct Fun { | |||
68 | Str return_type; | 67 | Str return_type; |
69 | } Fun; | 68 | } Fun; |
70 | 69 | ||
71 | typedef struct Field { | ||
72 | Str name; | ||
73 | Str type; | ||
74 | Node *val; | ||
75 | } Field; | ||
76 | |||
77 | typedef struct Enum { | 70 | typedef struct Enum { |
78 | Str name; | 71 | Str name; |
79 | struct FieldMap *fields; | 72 | Node *val; |
80 | } Enum; | 73 | } Enum; |
81 | 74 | ||
82 | typedef struct Struct { | 75 | typedef struct Struct { |
83 | Str name; | 76 | Str name; |
84 | struct FieldMap *fields; | 77 | Str type; |
78 | Node *val; | ||
85 | } Struct; | 79 | } Struct; |
86 | 80 | ||
87 | MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) | 81 | MAPDEF(SymbolMap, symmap, Str, Symbol, str_hash, str_eq) |
@@ -89,7 +83,6 @@ MAPDEF(TypeMap, typemap, Str, Type, str_hash, str_eq) | |||
89 | MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq) | 83 | MAPDEF(FunMap, funmap, Str, Fun, str_hash, str_eq) |
90 | MAPDEF(EnumMap, enummap, Str, Enum, str_hash, str_eq) | 84 | MAPDEF(EnumMap, enummap, Str, Enum, str_hash, str_eq) |
91 | MAPDEF(StructMap, structmap, Str, Struct, str_hash, str_eq) | 85 | MAPDEF(StructMap, structmap, Str, Struct, str_hash, str_eq) |
92 | MAPDEF(FieldMap, fieldmap, Str, Field, str_hash, str_eq) | ||
93 | 86 | ||
94 | typedef struct Scope { | 87 | typedef struct Scope { |
95 | sz id; | 88 | sz id; |
@@ -382,6 +375,65 @@ emit_semantic_error(Analyzer *a, Node *n, Str msg) { | |||
382 | eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg); | 375 | eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg); |
383 | } | 376 | } |
384 | 377 | ||
378 | Type type_inference(Analyzer *a, Node *node, TypeScope *scope); | ||
379 | |||
380 | void | ||
381 | typecheck_field(Analyzer *a, | ||
382 | Node *node, | ||
383 | TypeScope *scope, | ||
384 | Str symbol, | ||
385 | StructMap *map) { | ||
386 | // TODO: ensure the tables are filled properly. | ||
387 | if (node->field_type->kind == NODE_COMPOUND_TYPE) { | ||
388 | Str field_name = str_concat(symbol, cstr("."), a->storage); | ||
389 | field_name = str_concat(field_name, node->value.str, a->storage); | ||
390 | if (structmap_lookup(&map, field_name)) { | ||
391 | eprintln("%s:%d:%d: error: struct field '%s' already exists", | ||
392 | a->file_name, node->line, node->col, field_name); | ||
393 | } | ||
394 | Str type = cstr("\\{ "); | ||
395 | for (sz i = 0; i < array_size(node->field_type->elements); i++) { | ||
396 | Node *field = node->field_type->elements[i]; | ||
397 | typecheck_field(a, field, scope, field_name, map); | ||
398 | type = str_concat(type, field->type, a->storage); | ||
399 | type = str_concat(type, cstr(" "), a->storage); | ||
400 | } | ||
401 | type = str_concat(type, cstr("\\}"), a->storage); | ||
402 | node->type = type; | ||
403 | } else { | ||
404 | Str field_name = str_concat(symbol, cstr("."), a->storage); | ||
405 | field_name = str_concat(field_name, node->value.str, a->storage); | ||
406 | Str field_type = node->field_type->value.str; | ||
407 | if (!find_type(scope, field_type)) { | ||
408 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | ||
409 | node->field_type->line, node->field_type->col, field_type); | ||
410 | } | ||
411 | if (structmap_lookup(&map, field_name)) { | ||
412 | eprintln("%s:%d:%d: error: struct field '%s' already exists", | ||
413 | a->file_name, node->line, node->col, field_name); | ||
414 | } | ||
415 | if (node->field_val) { | ||
416 | Type type = type_inference(a, node->field_val, scope); | ||
417 | if (!str_eq(type, field_type)) { | ||
418 | eprintln( | ||
419 | "%s:%d:%d: error: mismatched types in struct " | ||
420 | "value " | ||
421 | "for '%s': %s expected %s", | ||
422 | a->file_name, node->line, node->col, field_name, type, | ||
423 | field_type); | ||
424 | } | ||
425 | } | ||
426 | structmap_insert(&map, field_name, | ||
427 | (Struct){ | ||
428 | .name = field_name, | ||
429 | .type = field_type, | ||
430 | .val = node->field_val, | ||
431 | }, | ||
432 | a->storage); | ||
433 | node->type = field_type; | ||
434 | } | ||
435 | } | ||
436 | |||
385 | void | 437 | void |
386 | typecheck_returns(Analyzer *a, Node *node, Str expected) { | 438 | typecheck_returns(Analyzer *a, Node *node, Str expected) { |
387 | if (!node) { | 439 | if (!node) { |
@@ -534,35 +586,10 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
534 | // TODO: make sure it didn't exist before. | 586 | // TODO: make sure it didn't exist before. |
535 | StructMap *e = structmap_insert( | 587 | StructMap *e = structmap_insert( |
536 | &scope->structs, symbol, (Struct){.name = symbol}, a->storage); | 588 | &scope->structs, symbol, (Struct){.name = symbol}, a->storage); |
537 | // for (sz i = 0; i < array_size(node->struct_field); i++) { | 589 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
538 | // Node *field = node->struct_field[i]; | 590 | Node *field = node->struct_field[i]; |
539 | // // TODO: handle compound types | 591 | typecheck_field(a, field, scope, symbol, e); |
540 | // Str field_name = field->value.str; | 592 | } |
541 | // Str field_type = field->field_type->value.str; | ||
542 | // if (fieldmap_lookup(&e->val.fields, field_name)) { | ||
543 | // eprintln( | ||
544 | // "%s:%d:%d: error: struct field '%s.%s' already exists", | ||
545 | // a->file_name, field->line, field->col, symbol, | ||
546 | // field_name); | ||
547 | // } | ||
548 | // if (field->field_val) { | ||
549 | // Type type = type_inference(a, field->field_val, scope); | ||
550 | // if (!str_eq(type, field_type)) { | ||
551 | // eprintln( | ||
552 | // "%s:%d:%d: error: mismatched types in struct " | ||
553 | // "value " | ||
554 | // "for '%s.%s': %s expected %s", | ||
555 | // a->file_name, field->line, field->col, symbol, | ||
556 | // field_name, type, field_type); | ||
557 | // } | ||
558 | // } | ||
559 | // fieldmap_insert(&e->val.fields, field_name, | ||
560 | // (Field){.name = field_name, | ||
561 | // .type = field_type, | ||
562 | // .val = field->field_val}, | ||
563 | // a->storage); | ||
564 | // field->type = field_type; | ||
565 | // } | ||
566 | typemap_insert(&scope->types, symbol, symbol, a->storage); | 593 | typemap_insert(&scope->types, symbol, symbol, a->storage); |
567 | return node->type; | 594 | return node->type; |
568 | } break; | 595 | } break; |
@@ -574,12 +601,12 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
574 | (Enum){.name = symbol}, a->storage); | 601 | (Enum){.name = symbol}, a->storage); |
575 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 602 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
576 | Node *field = node->struct_field[i]; | 603 | Node *field = node->struct_field[i]; |
577 | Str field_name = field->value.str; | 604 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
578 | if (fieldmap_lookup(&e->val.fields, field_name)) { | 605 | field_name = |
579 | eprintln( | 606 | str_concat(field_name, field->value.str, a->storage); |
580 | "%s:%d:%d: error: enum field '%s.%s' already exists", | 607 | if (enummap_lookup(&e, field_name)) { |
581 | a->file_name, field->line, field->col, symbol, | 608 | eprintln("%s:%d:%d: error: enum field '%s' already exists", |
582 | field_name); | 609 | a->file_name, field->line, field->col, field_name); |
583 | } | 610 | } |
584 | if (field->field_val) { | 611 | if (field->field_val) { |
585 | Type type = type_inference(a, field->field_val, scope); | 612 | Type type = type_inference(a, field->field_val, scope); |
@@ -590,11 +617,8 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
590 | field_name); | 617 | field_name); |
591 | } | 618 | } |
592 | } | 619 | } |
593 | fieldmap_insert(&e->val.fields, field_name, | 620 | enummap_insert(&e, field_name, (Enum){.name = field_name}, |
594 | (Field){.name = field_name, | 621 | a->storage); |
595 | .type = cstr("int"), | ||
596 | .val = field->field_val}, | ||
597 | a->storage); | ||
598 | field->type = cstr("int"); | 622 | field->type = cstr("int"); |
599 | } | 623 | } |
600 | typemap_insert(&scope->types, symbol, symbol, a->storage); | 624 | typemap_insert(&scope->types, symbol, symbol, a->storage); |
@@ -825,11 +849,14 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
825 | return cstr(""); | 849 | return cstr(""); |
826 | } | 850 | } |
827 | // Check if there is a next and it matches the enum field. | 851 | // Check if there is a next and it matches the enum field. |
828 | if (!fieldmap_lookup(&e->val.fields, node->next->value.str)) { | 852 | Str field = str_concat(type->val, cstr("."), a->storage); |
853 | field = str_concat(field, node->next->value.str, a->storage); | ||
854 | if (!find_enum(scope, field)) { | ||
829 | eprintln( | 855 | eprintln( |
830 | "%s:%d:%d: error: unknown enum field for symbol " | 856 | "%s:%d:%d: error: unknown enum field for " |
831 | "'%s'", | 857 | "'%s': %s", |
832 | a->file_name, node->line, node->col, symbol); | 858 | a->file_name, node->line, node->col, symbol, |
859 | node->next->value.str); | ||
833 | return cstr(""); | 860 | return cstr(""); |
834 | } | 861 | } |
835 | node->next->type = cstr("int"); | 862 | node->next->type = cstr("int"); |
@@ -1159,7 +1186,7 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { | |||
1159 | Str field_name = field->value.str; | 1186 | Str field_name = field->value.str; |
1160 | if (symmap_lookup(&map->val.fields, field_name) != NULL) { | 1187 | if (symmap_lookup(&map->val.fields, field_name) != NULL) { |
1161 | eprintln( | 1188 | eprintln( |
1162 | "%s:%d:%d: error: enum field '%s.%s' already exists", | 1189 | "%s:%d:%d: error: struct field '%s.%s' already exists", |
1163 | a->file_name, field->line, field->col, symbol, | 1190 | a->file_name, field->line, field->col, symbol, |
1164 | field_name); | 1191 | field_name); |
1165 | return; | 1192 | return; |
@@ -1439,26 +1466,59 @@ process_file(Str path) { | |||
1439 | } | 1466 | } |
1440 | 1467 | ||
1441 | #if DEBUG == 1 | 1468 | #if DEBUG == 1 |
1442 | for (sz i = 0; i < array_size(analyzer.scopes); i++) { | 1469 | println("======== enums ========"); |
1470 | for (sz i = 0; i < array_size(analyzer.types); i++) { | ||
1443 | Arena scratch = lexer_arena; | 1471 | Arena scratch = lexer_arena; |
1444 | Scope *scope = analyzer.scopes[i]; | 1472 | TypeScope *scope = analyzer.types[i]; |
1445 | SymbolMapIter iter = symmap_iterator(scope->symbols, &scratch); | 1473 | EnumMapIter iter = enummap_iterator(scope->enums, &scratch); |
1446 | SymbolMap *sym = symmap_next(&iter, &scratch); | 1474 | EnumMap *m = enummap_next(&iter, &scratch); |
1447 | while (sym) { | 1475 | while (m) { |
1448 | println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id, | 1476 | println("%s: enum: %s", path, m->val.name); |
1449 | scope->depth, sym_kind_str[sym->val.kind], sym->val.name); | 1477 | m = enummap_next(&iter, &scratch); |
1450 | SymbolMapIter field_iter = | ||
1451 | symmap_iterator(sym->val.fields, &scratch); | ||
1452 | SymbolMap *field = symmap_next(&field_iter, &scratch); | ||
1453 | while (field) { | ||
1454 | println("%s: SCOPE: %d DEPTH: %d\t%s %s.%s", path, scope->id, | ||
1455 | scope->depth, sym_kind_str[field->val.kind], | ||
1456 | sym->val.name, field->val.name); | ||
1457 | field = symmap_next(&field_iter, &scratch); | ||
1458 | } | ||
1459 | sym = symmap_next(&iter, &lexer_arena); | ||
1460 | } | 1478 | } |
1461 | } | 1479 | } |
1480 | println("======== structs ========"); | ||
1481 | for (sz i = 0; i < array_size(analyzer.types); i++) { | ||
1482 | Arena scratch = lexer_arena; | ||
1483 | TypeScope *scope = analyzer.types[i]; | ||
1484 | StructMapIter iter = structmap_iterator(scope->structs, &scratch); | ||
1485 | StructMap *m = structmap_next(&iter, &scratch); | ||
1486 | while (m) { | ||
1487 | println("%s: struct: %s", path, m->val.name); | ||
1488 | m = structmap_next(&iter, &scratch); | ||
1489 | } | ||
1490 | } | ||
1491 | println("======== functions ========"); | ||
1492 | for (sz i = 0; i < array_size(analyzer.types); i++) { | ||
1493 | Arena scratch = lexer_arena; | ||
1494 | TypeScope *scope = analyzer.types[i]; | ||
1495 | FunMapIter iter = funmap_iterator(scope->funcs, &scratch); | ||
1496 | FunMap *m = funmap_next(&iter, &scratch); | ||
1497 | while (m) { | ||
1498 | println("%s: func: %s(%s): (%s)", path, m->val.name, | ||
1499 | m->val.param_type, m->val.return_type); | ||
1500 | m = funmap_next(&iter, &scratch); | ||
1501 | } | ||
1502 | } | ||
1503 | // println("======== symbols ========"); | ||
1504 | // SymbolMapIter iter = symmap_iterator(scope->symbols, &scratch); | ||
1505 | // SymbolMap *sym = symmap_next(&iter, &scratch); | ||
1506 | // while (sym) { | ||
1507 | // println("%s: SCOPE: %d DEPTH: %d\t%s %s", path, scope->id, | ||
1508 | // scope->depth, sym_kind_str[sym->val.kind], | ||
1509 | // sym->val.name); | ||
1510 | // SymbolMapIter field_iter = | ||
1511 | // symmap_iterator(sym->val.fields, &scratch); | ||
1512 | // SymbolMap *field = symmap_next(&field_iter, &scratch); | ||
1513 | // while (field) { | ||
1514 | // println("%s: SCOPE: %d DEPTH: %d\t%s %s.%s", path, scope->id, | ||
1515 | // scope->depth, sym_kind_str[field->val.kind], | ||
1516 | // sym->val.name, field->val.name); | ||
1517 | // field = symmap_next(&field_iter, &scratch); | ||
1518 | // } | ||
1519 | // sym = symmap_next(&iter, &lexer_arena); | ||
1520 | // } | ||
1521 | // } | ||
1462 | #endif | 1522 | #endif |
1463 | 1523 | ||
1464 | // TODO: Type checking. | 1524 | // TODO: Type checking. |