diff --git a/checker.c b/checker.c index e78c0bb..791679b 100644 --- a/checker.c +++ b/checker.c @@ -1,11 +1,11 @@ #include "compiler.h" #include -size_t common_string_hash_djb2(const unsigned char* value, size_t length) +size_t string_hash_djb2(const char* value) { size_t hash = 5381; - for (size_t i = 0; i < length && value[i] != '\0'; ++i) - hash = ((hash << 5) + hash) + value[i]; + for (size_t i = 0; value[i] != '\0'; ++i) + hash = ((hash << 5) + hash) + (unsigned char)value[i]; return hash; } @@ -115,12 +115,43 @@ 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); } @@ -136,16 +167,18 @@ CheckerResult checker_result(Checker* checker) }; } -void checker_check_statements(Checker* checker, ASTNode* node) +void checker_check_statements( + Checker* checker, SymbolTable* table, ASTNode* node) { - SymbolTable table; - symbol_table_construct(&table, &checker->head_table); + SymbolTable statements_table; + symbol_table_construct(&statements_table, table); for (size_t i = 0; i < node->statements.length; ++i) { - checker_check_statement(checker, &table, node->statements.data[i]); + checker_check_statement( + checker, &statements_table, node->statements.data[i]); } statements_symbols_vec_push(&checker->statements_symbols, (StatementsSymbols) { - .table = table, + .table = statements_table, .statements = node, }); } @@ -155,16 +188,124 @@ void checker_check_statement( { switch (node->node_type) { case ASTNodeType_Block: - checker_check_statements(checker, node); + 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; +} diff --git a/compiler.h b/compiler.h index 8a75cbd..979495b 100644 --- a/compiler.h +++ b/compiler.h @@ -188,14 +188,19 @@ typedef struct { ASTNode* value; } ASTReturnNode; +typedef struct Symbol Symbol; + struct ASTNode { ASTNodeType node_type; Pos pos; union { - char* id_value; + struct { + char* id_value; + Symbol* id_symbol; + }; int int_value; ASTNode* group_value; - ASTNodeVec statements; + ASTNodeVec statements; ASTIfNode if_node; ASTLoopNode loop_node; ASTCallNode call_node; @@ -255,11 +260,14 @@ typedef enum { SymbolType_Builtin, } SymbolType; -typedef struct { +struct Symbol { SymbolType type; -} Symbol; + union { + int local_location; + }; +}; -size_t common_string_hash_djb2(const unsigned char* value, size_t length); +size_t string_hash_djb2(const char* value); typedef struct { size_t key_hash; @@ -280,44 +288,56 @@ int string_symbol_map_set(StringSymbolMap* map, size_t key_hash, Symbol value); typedef struct SymbolTable SymbolTable; struct SymbolTable { - SymbolTable* parent; - StringSymbolMap map; + SymbolTable* parent; + StringSymbolMap map; }; void symbol_table_construct(SymbolTable* table, SymbolTable* parent); void symbol_table_destroy(SymbolTable* table); +Symbol* symbol_table_resolve(SymbolTable* table, const char* id); +Symbol* symbol_table_resolve_hash(SymbolTable* table, size_t hash); +Symbol* symbol_table_resolve_local(SymbolTable* table, const char* id); +void symbol_table_define(SymbolTable* table, const char* id, Symbol symbol); typedef struct { - ASTNode* statements; - SymbolTable table; + ASTNode* statements; + SymbolTable table; } StatementsSymbols; typedef struct { - StatementsSymbols* data; - size_t length; - size_t capacity; + StatementsSymbols* data; + size_t length; + size_t capacity; } StatementsSymbolsVec; int statements_symbols_vec_construct(StatementsSymbolsVec* vec); void statements_symbols_vec_destroy(StatementsSymbolsVec* vec); -int statements_symbols_vec_push(StatementsSymbolsVec* vec, StatementsSymbols pair); +int statements_symbols_vec_push( + StatementsSymbolsVec* vec, StatementsSymbols pair); typedef struct { bool failed; - SymbolTable head_table; - StatementsSymbolsVec statements_symbols; + SymbolTable head_table; + StatementsSymbolsVec statements_symbols; } Checker; typedef struct { - SymbolTable head_table; - StatementsSymbolsVec statements_symbols; -} CheckerResult; + SymbolTable head_table; + StatementsSymbolsVec statements_symbols; +} CheckerResult; void checker_construct(Checker* checker); void checker_destroy(Checker* checker); bool checker_failed(const Checker* checker); CheckerResult checker_result(Checker* checker); -void checker_check_statements(Checker* checker, ASTNode* node); -void checker_check_statement(Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_statements( + Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_statement( + Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_assign(Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_let(Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_fn(Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_expr(Checker* checker, SymbolTable* table, ASTNode* node); +void checker_check_id(Checker* checker, SymbolTable* table, ASTNode* node); #endif diff --git a/parser.c b/parser.c index 0c84c3c..ce0d326 100644 --- a/parser.c +++ b/parser.c @@ -801,7 +801,11 @@ ASTNode* parser_parse_id(Parser* parser) strncpy(value, &parser->text[parser->current.pos.index], parser->current.length); parser_step(parser); - return ast_node_new(ASTNodeType_Id, pos, (ASTNode) { .id_value = value }); + return ast_node_new(ASTNodeType_Id, pos, + (ASTNode) { + .id_value = value, + .id_symbol = NULL, + }); } ASTNode* parser_parse_int(Parser* parser)