#include "compiler.h" #include size_t string_hash_djb2(const char* value) { size_t hash = 5381; for (size_t i = 0; value[i] != '\0'; ++i) hash = ((hash << 5) + hash) + (unsigned char)value[i]; return hash; } int string_symbol_map_construct(StringSymbolMap* map) { const size_t start_capacity = 4; *map = (StringSymbolMap) { .data = malloc(sizeof(StringSymbolMap) * start_capacity), .length = 0, .capacity = start_capacity, }; if (map->data == NULL) { return -1; } return 0; } void string_symbol_map_destroy(StringSymbolMap* map) { if (map->data != NULL) { free(map->data); } } Symbol* string_symbol_map_get(const StringSymbolMap* map, size_t key_hash) { for (size_t i = 0; i < map->length; ++i) { if (map->data[i].key_hash == key_hash) { return &map->data[i].value; } } return NULL; } int string_symbol_map_set(StringSymbolMap* map, size_t key_hash, Symbol value) { Symbol* existing = string_symbol_map_get(map, key_hash); if (existing != NULL) { *existing = value; return 0; } if (map->length + 1 >= map->capacity) { map->capacity *= 2; StringSymbolMapEntry* data = realloc(map->data, sizeof(StringSymbolMapEntry) * map->capacity); if (data == NULL) { return -1; } map->data = data; } map->data[map->length] = (StringSymbolMapEntry) { key_hash, value }; map->length += 1; return 0; } int statements_symbols_vec_construct(StatementsSymbolsVec* vec) { const size_t start_capacity = 4; StatementsSymbols* data = malloc(start_capacity * sizeof(StatementsSymbols)); if (data == NULL) { return -1; } *vec = (StatementsSymbolsVec) { .data = data, .length = 0, .capacity = start_capacity, }; return 0; } void statements_symbols_vec_destroy(StatementsSymbolsVec* vec) { if (vec->data != NULL) { free(vec->data); } } int statements_symbols_vec_push( StatementsSymbolsVec* vec, StatementsSymbols pair) { if (vec->length + 1 > vec->capacity) { StatementsSymbols* new_data = realloc(vec->data, vec->capacity * 2 * sizeof(StatementsSymbols)); if (new_data == NULL) { return -1; } vec->capacity *= 2; vec->data = new_data; } vec->data[vec->length] = pair; vec->length += 1; return 0; } void symbol_table_construct(SymbolTable* table, SymbolTable* parent) { *table = (SymbolTable) { .parent = parent, .map = { 0 }, }; string_symbol_map_construct(&table->map); } void symbol_table_destroy(SymbolTable* table) { string_symbol_map_destroy(&table->map); } Symbol* symbol_table_resolve(SymbolTable* table, const char* id) { size_t hash = string_hash_djb2(id); return symbol_table_resolve_hash(table, hash); } Symbol* symbol_table_resolve_hash(SymbolTable* table, size_t hash) { Symbol* found = string_symbol_map_get(&table->map, hash); if (found != NULL) { return found; } if (table->parent != NULL) { return symbol_table_resolve_hash(table->parent, hash); } return NULL; } Symbol* symbol_table_resolve_local(SymbolTable* table, const char* id) { return string_symbol_map_get(&table->map, string_hash_djb2(id)); } void symbol_table_define(SymbolTable* table, const char* id, Symbol symbol) { size_t hash = string_hash_djb2(id); string_symbol_map_set(&table->map, hash, symbol); } void checker_construct(Checker* checker) { *checker = (Checker) { .failed = false, .head_table = { 0 }, .statements_symbols = { 0 }, }; symbol_table_construct(&checker->head_table, NULL); statements_symbols_vec_construct(&checker->statements_symbols); } void checker_destroy(Checker* checker) { (void)checker; } bool checker_failed(const Checker* checker) { return checker->failed; } CheckerResult checker_result(Checker* checker) { return (CheckerResult) { .head_table = checker->head_table, .statements_symbols = checker->statements_symbols, }; } void checker_check_statements( Checker* checker, SymbolTable* table, ASTNode* node) { SymbolTable statements_table; symbol_table_construct(&statements_table, table); for (size_t i = 0; i < node->statements.length; ++i) { checker_check_statement( checker, &statements_table, node->statements.data[i]); } statements_symbols_vec_push(&checker->statements_symbols, (StatementsSymbols) { .table = statements_table, .statements = node, }); } void checker_check_statement( Checker* checker, SymbolTable* table, ASTNode* node) { switch (node->node_type) { case ASTNodeType_Block: checker_check_statements(checker, table, node); break; case ASTNodeType_If: checker_check_expr(checker, table, node->if_node.condition); checker_check_statements(checker, table, node->if_node.truthy); if (node->if_node.falsy) { checker_check_statements(checker, table, node->if_node.falsy); } break; case ASTNodeType_Loop: checker_check_statements(checker, table, node->loop_node.body); break; case ASTNodeType_Assign: checker_check_assign(checker, table, node); break; case ASTNodeType_Let: checker_check_let(checker, table, node); break; case ASTNodeType_Break: break; case ASTNodeType_Fn: checker_check_fn(checker, table, node); break; case ASTNodeType_Return: if (node->return_node.value != NULL) { checker_check_expr(checker, table, node->return_node.value); } break; default: break; } } void checker_check_assign(Checker* checker, SymbolTable* table, ASTNode* node) { checker_check_expr(checker, table, node->assign_node.subject); switch (node->assign_node.subject->node_type) { case ASTNodeType_Id: case ASTNodeType_Index: break; default: checker->failed = true; print_error("checker: cannot assign to expression", node->pos); return; } checker_check_expr(checker, table, node->assign_node.value); } void checker_check_let(Checker* checker, SymbolTable* table, ASTNode* node) { Symbol* found = symbol_table_resolve_local(table, node->let_node.id->id_value); if (found != NULL) { checker->failed = true; print_error("checker: redefinition", node->pos); return; } checker_check_expr(checker, table, node->let_node.value); } void checker_check_fn(Checker* checker, SymbolTable* table, ASTNode* node) { } void checker_check_expr(Checker* checker, SymbolTable* table, ASTNode* node) { switch (node->node_type) { case ASTNodeType_Error: checker->failed = true; break; case ASTNodeType_Id: checker_check_id(checker, table, node); break; case ASTNodeType_Int: break; case ASTNodeType_Group: checker_check_expr(checker, table, node->group_value); break; case ASTNodeType_Block: checker_check_statements(checker, table, node->loop_node.body); break; case ASTNodeType_If: checker_check_expr(checker, table, node->if_node.condition); checker_check_statements(checker, table, node->if_node.truthy); if (node->if_node.falsy != NULL) { checker_check_statements(checker, table, node->if_node.falsy); } break; case ASTNodeType_Call: checker_check_expr(checker, table, node->call_node.subject); for (size_t i = 0; i < node->call_node.args.length; ++i) { checker_check_expr( checker, table, node->call_node.args.data[i]); } break; case ASTNodeType_Index: checker_check_expr(checker, table, node->index_node.subject); checker_check_expr(checker, table, node->index_node.value); break; case ASTNodeType_Unary: checker_check_expr(checker, table, node->unary_node.subject); break; case ASTNodeType_Binary: checker_check_expr(checker, table, node->binary_node.left); checker_check_expr(checker, table, node->binary_node.right); break; default: checker->failed = true; print_error("checker: unrecognzed expression", node->pos); break; } } void checker_check_id(Checker* checker, SymbolTable* table, ASTNode* node) { Symbol* found = symbol_table_resolve(table, node->id_value); if (found == NULL) { checker->failed = true; print_error("checker: undefined identifier", node->pos); return; } node->id_symbol = found; }