SLUDGE
This commit is contained in:
parent
76bce4efef
commit
c5a9c83c73
159
checker.c
159
checker.c
@ -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;
|
||||||
|
}
|
||||||
|
60
compiler.h
60
compiler.h
@ -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
|
||||||
|
6
parser.c
6
parser.c
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user