This commit is contained in:
SimonFJ20 2024-04-07 04:50:29 +02:00
parent 76bce4efef
commit c5a9c83c73
3 changed files with 195 additions and 30 deletions

159
checker.c
View File

@ -1,11 +1,11 @@
#include "compiler.h" #include "compiler.h"
#include <stdlib.h> #include <stdlib.h>
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; size_t hash = 5381;
for (size_t i = 0; i < length && value[i] != '\0'; ++i) for (size_t i = 0; value[i] != '\0'; ++i)
hash = ((hash << 5) + hash) + value[i]; hash = ((hash << 5) + hash) + (unsigned char)value[i];
return hash; return hash;
} }
@ -115,12 +115,43 @@ void symbol_table_destroy(SymbolTable* table)
string_symbol_map_destroy(&table->map); 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) void checker_construct(Checker* checker)
{ {
*checker = (Checker) { *checker = (Checker) {
.failed = false, .failed = false,
.head_table = { 0 },
.statements_symbols = { 0 }, .statements_symbols = { 0 },
}; };
symbol_table_construct(&checker->head_table, NULL);
statements_symbols_vec_construct(&checker->statements_symbols); 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; SymbolTable statements_table;
symbol_table_construct(&table, &checker->head_table); symbol_table_construct(&statements_table, table);
for (size_t i = 0; i < node->statements.length; ++i) { 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, statements_symbols_vec_push(&checker->statements_symbols,
(StatementsSymbols) { (StatementsSymbols) {
.table = table, .table = statements_table,
.statements = node, .statements = node,
}); });
} }
@ -155,16 +188,124 @@ void checker_check_statement(
{ {
switch (node->node_type) { switch (node->node_type) {
case ASTNodeType_Block: case ASTNodeType_Block:
checker_check_statements(checker, node); checker_check_statements(checker, table, node);
break;
case ASTNodeType_If: 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: case ASTNodeType_Loop:
checker_check_statements(checker, table, node->loop_node.body);
break;
case ASTNodeType_Assign: case ASTNodeType_Assign:
checker_check_assign(checker, table, node);
break;
case ASTNodeType_Let: case ASTNodeType_Let:
checker_check_let(checker, table, node);
break;
case ASTNodeType_Break: case ASTNodeType_Break:
break;
case ASTNodeType_Fn: case ASTNodeType_Fn:
checker_check_fn(checker, table, node);
break;
case ASTNodeType_Return: case ASTNodeType_Return:
if (node->return_node.value != NULL) {
checker_check_expr(checker, table, node->return_node.value);
}
break; break;
default: default:
break; 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;
}

View File

@ -188,14 +188,19 @@ typedef struct {
ASTNode* value; ASTNode* value;
} ASTReturnNode; } ASTReturnNode;
typedef struct Symbol Symbol;
struct ASTNode { struct ASTNode {
ASTNodeType node_type; ASTNodeType node_type;
Pos pos; Pos pos;
union { union {
char* id_value; struct {
char* id_value;
Symbol* id_symbol;
};
int int_value; int int_value;
ASTNode* group_value; ASTNode* group_value;
ASTNodeVec statements; ASTNodeVec statements;
ASTIfNode if_node; ASTIfNode if_node;
ASTLoopNode loop_node; ASTLoopNode loop_node;
ASTCallNode call_node; ASTCallNode call_node;
@ -255,11 +260,14 @@ typedef enum {
SymbolType_Builtin, SymbolType_Builtin,
} SymbolType; } SymbolType;
typedef struct { struct Symbol {
SymbolType type; 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 { typedef struct {
size_t key_hash; 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; typedef struct SymbolTable SymbolTable;
struct SymbolTable { struct SymbolTable {
SymbolTable* parent; SymbolTable* parent;
StringSymbolMap map; StringSymbolMap map;
}; };
void symbol_table_construct(SymbolTable* table, SymbolTable* parent); void symbol_table_construct(SymbolTable* table, SymbolTable* parent);
void symbol_table_destroy(SymbolTable* table); 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 { typedef struct {
ASTNode* statements; ASTNode* statements;
SymbolTable table; SymbolTable table;
} StatementsSymbols; } StatementsSymbols;
typedef struct { typedef struct {
StatementsSymbols* data; StatementsSymbols* data;
size_t length; size_t length;
size_t capacity; size_t capacity;
} StatementsSymbolsVec; } StatementsSymbolsVec;
int statements_symbols_vec_construct(StatementsSymbolsVec* vec); int statements_symbols_vec_construct(StatementsSymbolsVec* vec);
void statements_symbols_vec_destroy(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 { typedef struct {
bool failed; bool failed;
SymbolTable head_table; SymbolTable head_table;
StatementsSymbolsVec statements_symbols; StatementsSymbolsVec statements_symbols;
} Checker; } Checker;
typedef struct { typedef struct {
SymbolTable head_table; SymbolTable head_table;
StatementsSymbolsVec statements_symbols; StatementsSymbolsVec statements_symbols;
} CheckerResult; } CheckerResult;
void checker_construct(Checker* checker); void checker_construct(Checker* checker);
void checker_destroy(Checker* checker); void checker_destroy(Checker* checker);
bool checker_failed(const Checker* checker); bool checker_failed(const Checker* checker);
CheckerResult checker_result(Checker* checker); CheckerResult checker_result(Checker* checker);
void checker_check_statements(Checker* checker, ASTNode* node); void checker_check_statements(
void checker_check_statement(Checker* checker, SymbolTable* table, ASTNode* node); 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 #endif

View File

@ -801,7 +801,11 @@ ASTNode* parser_parse_id(Parser* parser)
strncpy(value, &parser->text[parser->current.pos.index], strncpy(value, &parser->text[parser->current.pos.index],
parser->current.length); parser->current.length);
parser_step(parser); 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) ASTNode* parser_parse_int(Parser* parser)