#include "parser.h" #include "darray.h" typedef enum DefaultType { TYPE_VOID, TYPE_BOOL, TYPE_STR, TYPE_U8, TYPE_U16, TYPE_U32, TYPE_U64, TYPE_S8, TYPE_S16, TYPE_S32, TYPE_S64, TYPE_F32, TYPE_F64, } DefaultType; static Type default_types[] = { [TYPE_VOID] = {STRING("void"), 0}, [TYPE_BOOL] = {STRING("bool"), 1}, [TYPE_STR] = {STRING("str"), 16}, // size (8) + pointer to data (8). [TYPE_U8] = {STRING("u8"), 1}, [TYPE_U16] = {STRING("u16"), 2}, [TYPE_U32] = {STRING("u32"), 4}, [TYPE_U64] = {STRING("u64"), 8}, [TYPE_S8] = {STRING("s8"), 1}, [TYPE_S16] = {STRING("s16"), 2}, [TYPE_S32] = {STRING("s32"), 4}, [TYPE_S64] = {STRING("s64"), 8}, [TYPE_F32] = {STRING("f32"), 4}, [TYPE_F64] = {STRING("f64"), 8}, }; Token next_token(Parser *parser) { return parser->tokens[parser->current_token++]; } Token peek_token(Parser *parser) { return parser->tokens[parser->current_token]; } bool has_next(Parser *parser) { return parser->current_token < array_size(parser->tokens); } bool consume_rparen(Parser *parser) { Token tok = next_token(parser); if (tok.type != TOKEN_RPAREN) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_RPAREN, tok.line, tok.col); return false; } return true; } bool consume_lparen(Parser *parser) { Token tok = next_token(parser); if (tok.type != TOKEN_LPAREN) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_LPAREN, tok.line, tok.col); return false; } return true; } Node * parse_number(Parser *parser) { Token tok = next_token(parser); if (tok.type != TOKEN_NUMBER) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_NUMBER, tok.line, tok.col); return NULL; } bool negative = false; int base = 10; char c = sv_next(&tok.value); if (c == '-') { negative = true; c = sv_next(&tok.value); } if (c == '+') { c = sv_next(&tok.value); } if (c == '0' && sv_peek(&tok.value) != '\0') { c = sv_next(&tok.value); if (c == 'x') { base = 16; c = sv_next(&tok.value); } else if (c == 'b') { base = 2; c = sv_next(&tok.value); } else if (!(c >= '0' && c <= '9')){ push_error(ERR_TYPE_PARSER, ERR_MALFORMED_NUMBER, tok.line, tok.col); return NULL; } } // Integral part. u64 integral = 0; while (c != '\0') { ssize_t current = 0; if (c >= 'a' && c <= 'z' && base == 16) { current = (c - 'a') + 10; } else if (c >= 'A' && c <= 'Z' && base == 16) { current = (c - 'A') + 10; } else if (c >= '0' && c <= '9') { current = (c - '0'); } else if (c == '.') { c = sv_next(&tok.value); break; } else { push_error(ERR_TYPE_PARSER, ERR_MALFORMED_NUMBER, tok.line, tok.col); return NULL; } integral = integral * base + current; c = sv_next(&tok.value); } // Fractional part. u64 fractional = 0; while (c != '\0') { ssize_t current = 0; if (c >= 'a' && c <= 'z' && base == 16) { current = (c - 'a') + 10; } else if (c >= 'A' && c <= 'Z' && base == 16) { current = (c - 'A') + 10; } else if (c >= '0' && c <= '9') { current = (c - '0'); } else { push_error(ERR_TYPE_PARSER, ERR_MALFORMED_NUMBER, tok.line, tok.col); return NULL; } fractional = fractional * base + current; c = sv_next(&tok.value); } Node * node = alloc_node(NODE_NUMBER); node->number.negative = negative; node->number.integral = integral; node->number.fractional = fractional; node->line = tok.line; node->col = tok.col; return node; } Node * parse_string(Parser *parser) { Token tok = next_token(parser); if (tok.type != TOKEN_STRING) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_STRING, tok.line, tok.col); return NULL; } Node *node = alloc_node(NODE_STRING); node->string = tok.value; node->line = tok.line; node->col = tok.col; return node; } Node * parse_symbol(Parser *parser) { Token tok = next_token(parser); if (tok.type != TOKEN_SYMBOL) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_SYMBOL, tok.line, tok.col); return NULL; } Node *node = alloc_node(NODE_SYMBOL); node->string = tok.value; node->line = tok.line; node->col = tok.col; return node; } Node * parse_type(Parser *parser) { Token tok = next_token(parser); if (tok.type != TOKEN_COLON) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_TYPE, tok.line, tok.col); return NULL; } Node *node = alloc_node(NODE_TYPE); node->line = tok.line; node->col = tok.col; tok = next_token(parser); if (tok.type != TOKEN_SYMBOL) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_TYPE, tok.line, tok.col); return NULL; } node->string = tok.value; return node; } Node * parse_bool(Parser *parser) { Token tok = next_token(parser); if (!(tok.type == TOKEN_TRUE || tok.type == TOKEN_FALSE)) { push_error(ERR_TYPE_PARSER, ERR_NOT_A_BOOL, tok.line, tok.col); return NULL; } Node *node = alloc_node(NODE_BOOL); node->boolean = tok.type == TOKEN_TRUE; node->line = tok.line; node->col = tok.col; return node; } Node * parse_builtin(Parser *parser) { Token tok = next_token(parser); Node *node = alloc_node(NODE_BUILTIN); node->builtin.type = tok.type; node->line = tok.line; node->col = tok.col; array_init(node->builtin.args, 0); while (has_next(parser)) { Token next = peek_token(parser); if (next.type == TOKEN_RPAREN) { next_token(parser); return node; } Node *arg = parse_next(parser); if (arg == NULL) { break; } array_push(node->builtin.args, arg); } push_error(ERR_TYPE_PARSER, ERR_UNMATCHED_PAREN, tok.line, tok.col); return NULL; } Node * parse_funcall(Parser *parser) { Token tok = peek_token(parser); Node *name = parse_symbol(parser); if (name == NULL) { return NULL; } Node *node = alloc_node(NODE_FUNCALL); node->funcall.name = name; node->line = tok.line; node->col = tok.col; array_init(node->funcall.args, 0); while (has_next(parser)) { Token next = peek_token(parser); if (next.type == TOKEN_RPAREN) { next_token(parser); return node; } Node *arg = parse_next(parser); if (arg == NULL) { break; } array_push(node->funcall.args, arg); } push_error(ERR_TYPE_PARSER, ERR_UNMATCHED_PAREN, tok.line, tok.col); return NULL; } Node * parse_def(Parser *parser) { Token tok = next_token(parser); Node *symbol = parse_symbol(parser); if (symbol == NULL) { return NULL; } // TODO: Making type definitions mandatory for now until we introduce type // inference. Node *type = parse_type(parser); if (type == NULL) { return NULL; } Node *value = parse_next(parser); if (value == NULL) { return NULL; } if (!consume_rparen(parser)) { return NULL; } Node *node = alloc_node(NODE_DEF); node->def.symbol = symbol; node->def.value = value; node->def.type = type; node->line = tok.line; node->col = tok.col; return node; } Node * parse_set(Parser *parser) { Token tok = next_token(parser); Node *symbol = parse_symbol(parser); if (symbol == NULL) { return NULL; } Node *value = parse_next(parser); if (value == NULL) { return NULL; } if (!consume_rparen(parser)) { return NULL; } Node *node = alloc_node(NODE_SET); node->set.symbol = symbol; node->set.value = value; node->line = tok.line; node->col = tok.col; return node; } Node * parse_fun(Parser *parser) { Token tok = next_token(parser); Node *name = parse_symbol(parser); if (name == NULL) { return NULL; } Node *node = alloc_node(NODE_FUN); node->fun.name = name; array_init(node->fun.param_names, 0); array_init(node->fun.param_types, 0); node->line = tok.line; node->col = tok.col; // Parse parameter list and return type. if (!consume_lparen(parser)) { return NULL; } while (true) { Token next = peek_token(parser); if (next.type == TOKEN_RPAREN) { next_token(parser); break; } Node *name = parse_symbol(parser); if (name == NULL) { return NULL; } Node *type = parse_type(parser); if (type == NULL) { return NULL; } array_push(node->fun.param_names, name); array_push(node->fun.param_types, type); } Node *ret_type = parse_type(parser); if (ret_type == NULL) { return NULL; } node->fun.return_type = ret_type; Node *body = parse_next(parser); if (body == NULL) { return NULL; } node->fun.body = body; if (!consume_rparen(parser)) { return NULL; } return node; } Node * parse_if(Parser *parser) { Token tok = next_token(parser); Node *node = alloc_node(NODE_IF); node->ifexpr.cond = NULL; node->ifexpr.expr_true = NULL; node->ifexpr.expr_false = NULL; node->line = tok.line; node->col = tok.col; Node *cond = parse_next(parser); if (cond == NULL) { return NULL; } Node *expr_true = parse_next(parser); if (expr_true == NULL) { return NULL; } node->ifexpr.cond = cond; node->ifexpr.expr_true = expr_true; tok = peek_token(parser); // Optional else statement. if (tok.type != TOKEN_RPAREN) { Node *expr_false = parse_next(parser); if (expr_false == NULL) { return NULL; } node->ifexpr.expr_false = expr_false; } if (!consume_rparen(parser)) { return NULL; } return node; } Node * parse_paren(Parser *parser) { next_token(parser); // Skip paren. Token tok = peek_token(parser); switch (tok.type) { // Builtin functions. case TOKEN_ADD: case TOKEN_SUB: case TOKEN_MUL: case TOKEN_DIV: case TOKEN_MOD: case TOKEN_NOT: case TOKEN_AND: case TOKEN_OR: case TOKEN_EQ: case TOKEN_LT: case TOKEN_GT: case TOKEN_LE: case TOKEN_GE: { return parse_builtin(parser); } break; // Special functions. case TOKEN_DEF: { return parse_def(parser); } break; case TOKEN_SET: { return parse_set(parser); } break; case TOKEN_FUN: { return parse_fun(parser); } break; case TOKEN_IF: { return parse_if(parser); } break; default: break; } return parse_funcall(parser); } Node * parse_block(Parser *parser) { Token tok = next_token(parser); Node *node = alloc_node(NODE_BLOCK); array_init(node->block.expr, 0); node->line = tok.line; node->col = tok.col; while (true) { Token next = peek_token(parser); if (next.type == TOKEN_RCURLY) { next_token(parser); break; } Node *expr = parse_next(parser); if (expr == NULL) { return NULL; } array_push(node->block.expr, expr); } return node; } Node * parse_next(Parser *parser) { Token tok = peek_token(parser); switch (tok.type) { case TOKEN_NUMBER: { return parse_number(parser); } break; case TOKEN_STRING: { return parse_string(parser); } break; case TOKEN_SYMBOL: { return parse_symbol(parser); } break; case TOKEN_TRUE: case TOKEN_FALSE: { return parse_bool(parser); } break; case TOKEN_LPAREN: { return parse_paren(parser); } break; case TOKEN_EOF: { return NULL; } break; case TOKEN_LCURLY: { return parse_block(parser); } break; default: { push_error(ERR_TYPE_PARSER, ERR_UNKNOWN_TOK_TYPE, tok.line, tok.col); return NULL; } break; } } u64 sym_hash(const struct HashTable *table, void *bytes) { Node *symbol = bytes; u64 hash = _xor_shift_hash(symbol->string.start, symbol->string.n); hash = _fibonacci_hash(hash, table->shift_amount); return hash; } bool sym_eq(void *a, void *b) { Node *a_node = a; Node *b_node = b; assert(a_node->type == NODE_SYMBOL); assert(b_node->type == NODE_SYMBOL); return sv_equal(&a_node->string, &b_node->string); } u64 type_hash(const struct HashTable *table, void *bytes) { StringView *type = bytes; u64 hash = _xor_shift_hash(type->start, type->n); hash = _fibonacci_hash(hash, table->shift_amount); return hash; } bool type_eq(void *a, void *b) { StringView *a_type = a; StringView *b_type = b; return sv_equal(a_type, b_type); } Scope * alloc_scope(Scope *parent) { Scope *scope = malloc(sizeof(Scope)); scope->parent = parent; scope->symbols = ht_init(sym_hash, sym_eq); scope->types = ht_init(type_hash, type_eq); return scope; } ParseTree * alloc_parsetree(void) { ParseTree *parse_tree = malloc(sizeof(ParseTree)); array_init(parse_tree->roots, 0); parse_tree->global_scope = alloc_scope(NULL); parse_tree->current_scope = parse_tree->global_scope; // Fill global scope with default types. HashTable *types = parse_tree->global_scope->types; for (size_t i = 0; i < sizeof(default_types)/sizeof(Type); ++i) { Type *type = &default_types[i]; ht_insert(types, &type->name, type); } return parse_tree; } bool parse_roots(Parser *parser) { while (has_next(parser)) { Token tok = peek_token(parser); if (tok.type == TOKEN_EOF) { break; } Node *node = parse_next(parser); if (node == NULL) { return false; } array_push(parser->parse_tree->roots, node); } return true; } Type * find_type(Parser *parser, Node *type) { // Normally default types will be used more often. Since we don't // allow type shadowing, we search first on the global scope. Scope *scope = parser->parse_tree->global_scope; Type *ret = ht_lookup(scope->types, &type->string); if (ret != NULL) { return ret; } scope = parser->parse_tree->current_scope; while (scope->parent != NULL) { Type *ret = ht_lookup(scope->types, &type->string); if (ret != NULL) { return ret; } scope = scope->parent; } push_error(ERR_TYPE_PARSER, ERR_UNKNOWN_TYPE, type->line, type->col); return NULL; } // TODO: Review this function when needed // bool // insert_type(Parser *parser, Node *type, size_t size) { // HashTable *types = parser->parse_tree->current_scope->types; // if (ht_lookup(types, type) != NULL) { // push_error(ERR_TYPE_PARSER, ERR_TYPE_REDEF, type->line, type->col); // return false; // } // // TODO: alloc_type. // ht_insert(types, &type->string, type); // return true; // } Type * find_symbol(Parser *parser, Node *node) { Scope *scope = parser->parse_tree->current_scope; while (scope != NULL) { Type *type = ht_lookup(scope->symbols, node); if (type != NULL) { return type; } scope = scope->parent; } push_error(ERR_TYPE_PARSER, ERR_UNKNOWN_SYMBOL, node->line, node->col); return NULL; } bool insert_symbol(Parser *parser, Node *symbol, Node *type) { HashTable *symbols = parser->parse_tree->current_scope->symbols; if (ht_lookup(symbols, symbol) != NULL) { push_error(ERR_TYPE_PARSER, ERR_SYMBOL_REDEF, symbol->line, symbol->col); return false; } Type *t = find_type(parser, type); if (t == NULL) { return NULL; } ht_insert(symbols, symbol, t); return true; } bool symbol_check(Parser *parser, Node *node) { switch (node->type) { case NODE_BUILTIN: { for (size_t i = 0; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; if (!symbol_check(parser, arg)) { return false; } } } break; case NODE_SYMBOL: { if (find_symbol(parser, node) == NULL) { return false; } } break; case NODE_SET: { Node *symbol = node->set.symbol; if (find_symbol(parser, symbol) == NULL) { return false; } if (!symbol_check(parser, node->set.value)) { return false; } } break; case NODE_FUN: { Scope *prev_scope = parser->parse_tree->current_scope; parser->parse_tree->current_scope = alloc_scope(prev_scope); node->scope = parser->parse_tree->current_scope; // Parameters. for (size_t i = 0; i < array_size(node->fun.param_names); ++i) { Node *param = node->fun.param_names[i]; Node *type = node->fun.param_types[i]; if (!insert_symbol(parser, param, type)) { return false; } } // Body. Node *body = node->fun.body; if (body->type == NODE_BLOCK) { body->scope = parser->parse_tree->current_scope; for (size_t i = 0; i < array_size(body->block.expr); ++i) { Node *expr = body->block.expr[i]; if (!symbol_check(parser, expr)) { return false; } } } else { if (!symbol_check(parser, body)) { return false; } } parser->parse_tree->current_scope = prev_scope; } break; case NODE_BLOCK: { Scope *prev_scope = parser->parse_tree->current_scope; parser->parse_tree->current_scope = alloc_scope(prev_scope); node->scope = parser->parse_tree->current_scope; for (size_t i = 0; i < array_size(node->block.expr); ++i) { Node *expr = node->block.expr[i]; if (!symbol_check(parser, expr)) { return false; } } parser->parse_tree->current_scope = prev_scope; } break; case NODE_IF: { if (!symbol_check(parser, node->ifexpr.cond)) { return false; } if (!symbol_check(parser, node->ifexpr.expr_true)) { return false; } if (node->ifexpr.expr_false != NULL) { if (!symbol_check(parser, node->ifexpr.expr_false)) { return false; } } } break; case NODE_DEF: { if (!symbol_check(parser, node->def.value)) { return false; } if (!insert_symbol(parser, node->def.symbol, node->def.type)) { return false; } } break; case NODE_FUNCALL: { if (!symbol_check(parser, node->funcall.name)) { return false; } } break; default: break; } return true; } Type * coerce_numeric_types(Type *a, Type *b) { if (a == &default_types[TYPE_U8]) { if (b == &default_types[TYPE_U16] || b == &default_types[TYPE_U32] || b == &default_types[TYPE_U64] || b == &default_types[TYPE_S8] || b == &default_types[TYPE_S16] || b == &default_types[TYPE_S32] || b == &default_types[TYPE_S64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } } else if (a == &default_types[TYPE_U16]) { if (b == &default_types[TYPE_U32] || b == &default_types[TYPE_S16] || b == &default_types[TYPE_S32] || b == &default_types[TYPE_S64] || b == &default_types[TYPE_U64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } if (b == &default_types[TYPE_S8]) { return &default_types[TYPE_S16]; } } else if (a == &default_types[TYPE_U32]) { if (b == &default_types[TYPE_U64] || b == &default_types[TYPE_S32] || b == &default_types[TYPE_S64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } if (b == &default_types[TYPE_S8] || b == &default_types[TYPE_S16]) { return &default_types[TYPE_S32]; } } else if (a == &default_types[TYPE_U64]) { if (b == &default_types[TYPE_S64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } if (b == &default_types[TYPE_S8] || b == &default_types[TYPE_S16] || b == &default_types[TYPE_S32]) { return &default_types[TYPE_S64]; } } else if (a == &default_types[TYPE_S8]) { if (b == &default_types[TYPE_S16] || b == &default_types[TYPE_S32] || b == &default_types[TYPE_S64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } } else if (a == &default_types[TYPE_S16]) { if (b == &default_types[TYPE_S32] || b == &default_types[TYPE_S64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } } else if (a == &default_types[TYPE_S32]) { if (b == &default_types[TYPE_S64] || b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } } else if (a == &default_types[TYPE_S64]) { if (b == &default_types[TYPE_F32] || b == &default_types[TYPE_F64]) { return b; } } else if (a == &default_types[TYPE_F32]) { if (b == &default_types[TYPE_F64]) { return b; } } return a; } bool type_is_numeric(Type *t) { if (t == &default_types[TYPE_U8] || t == &default_types[TYPE_U16] || t == &default_types[TYPE_U32] || t == &default_types[TYPE_U64] || t == &default_types[TYPE_S8] || t == &default_types[TYPE_S16] || t == &default_types[TYPE_S32] || t == &default_types[TYPE_S64] || t == &default_types[TYPE_F32] || t == &default_types[TYPE_F64]) { return true; } return false; } bool resolve_type(Parser *parser, Node *node) { if (node->expr_type != NULL) { return true; } Scope *prev_scope = NULL; if (node->scope != NULL) { prev_scope = parser->parse_tree->current_scope; parser->parse_tree->current_scope = node->scope; } switch (node->type) { case NODE_BUILTIN: { for (size_t i = 0; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; if (!resolve_type(parser, arg)) { return false; } } switch (node->builtin.type) { // Numbers. case TOKEN_ADD: case TOKEN_SUB: case TOKEN_MUL: case TOKEN_DIV: case TOKEN_MOD: { Type *type = NULL; for (size_t i = 0; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; // Check that all arguments are nums. if (!type_is_numeric(arg->expr_type)) { push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_NUM, arg->line, arg->col); return false; } if (type == NULL) { type = arg->expr_type; } else if (type != arg->expr_type) { type = coerce_numeric_types(type, arg->expr_type); } } node->expr_type = type; } break; // Bools. case TOKEN_NOT: case TOKEN_AND: case TOKEN_OR: { // Check that all arguments are boolean. for (size_t i = 0; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; if (arg->expr_type != &default_types[TYPE_BOOL]) { push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_BOOL, arg->line, arg->col); return false; } } node->expr_type = &default_types[TYPE_BOOL]; } break; case TOKEN_EQ: case TOKEN_LT: case TOKEN_GT: case TOKEN_LE: case TOKEN_GE: { // Check that all arguments are nums. for (size_t i = 0; i < array_size(node->builtin.args); ++i) { Node *arg = node->builtin.args[i]; if (!type_is_numeric(arg->expr_type)) { push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_NUM, arg->line, arg->col); return false; } } node->expr_type = &default_types[TYPE_BOOL]; } break; default: break; } } break; case NODE_SYMBOL: { node->expr_type = find_symbol(parser, node); } break; case NODE_FUN: { if (!resolve_type(parser, node->fun.body)) { return false; } // Check that the type of body matches the return type. StringView *type_body = &node->fun.body->expr_type->name; StringView *return_type = &node->fun.return_type->string; if (!sv_equal(type_body, return_type)) { push_error(ERR_TYPE_PARSER, ERR_WRONG_RET_TYPE, node->line, node->col); return false; } } break; case NODE_BLOCK: { for (size_t i = 0; i < array_size(node->block.expr); ++i) { Node *expr = node->block.expr[i]; if (!resolve_type(parser, expr)) { return false; } } Node *last_expr = node->block.expr[array_size(node->block.expr) - 1]; node->expr_type = last_expr->expr_type; } break; case NODE_IF: { if (!resolve_type(parser, node->ifexpr.cond)) { return false; } if (!resolve_type(parser, node->ifexpr.expr_true)) { return false; } Type *type_true = node->ifexpr.expr_true->expr_type; node->expr_type = type_true; if (node->ifexpr.expr_false != NULL) { if (!resolve_type(parser, node->ifexpr.expr_false)) { return false; } } // Check ifexpr.cond is a bool. Type *type_cond = node->ifexpr.cond->expr_type; if (!sv_equal(&type_cond->name, &default_types[TYPE_BOOL].name)) { push_error(ERR_TYPE_PARSER, ERR_WRONG_COND_TYPE, node->line, node->col); return false; } // Check if types of expr_true and expr_false match if (node->ifexpr.expr_false != NULL) { Type *type_false = node->ifexpr.expr_false->expr_type; if (type_is_numeric(type_true) && type_is_numeric(type_false)) { node->expr_type = coerce_numeric_types(type_true, type_false); } else if (!sv_equal(&type_true->name, &type_false->name)) { push_error(ERR_TYPE_PARSER, ERR_WRONG_TYPE_T_F, node->line, node->col); return false; } } } break; case NODE_SET: { node->expr_type = &default_types[TYPE_VOID]; if (!resolve_type(parser, node->set.value)) { return false; } } break; case NODE_DEF: { node->expr_type = &default_types[TYPE_VOID]; if (!resolve_type(parser, node->def.value)) { return false; } } break; case NODE_NUMBER: { if (node->number.fractional != 0) { node->expr_type = &default_types[TYPE_F64]; } else if (node->number.negative) { node->expr_type = &default_types[TYPE_S64]; } else { node->expr_type = &default_types[TYPE_U64]; } } break; case NODE_BOOL: { node->expr_type = &default_types[TYPE_BOOL]; } break; case NODE_STRING: { node->expr_type = &default_types[TYPE_STR]; } break; case NODE_FUNCALL: { if (!resolve_type(parser, node->funcall.name)) { return false; } node->expr_type = node->funcall.name->expr_type; for (size_t i = 0; i < array_size(node->funcall.args); ++i) { Node *arg = node->funcall.args[i]; if (!resolve_type(parser, arg)) { return false; } } } break; default: break; } if (node->scope != NULL) { parser->parse_tree->current_scope = prev_scope; } return true; } bool semantic_analysis(Parser *parser) { // Fill up global function symbols. for (size_t i = 0; i < array_size(parser->parse_tree->roots); ++i) { Node *root = parser->parse_tree->roots[i]; if (root->type == NODE_FUN) { Node *name = root->fun.name; // TODO: make sure we store information in the symbol table that // this is actually a function, not just a variable with // return_type. if (!insert_symbol(parser, name, root->fun.return_type)) { return false; } } } for (size_t i = 0; i < array_size(parser->parse_tree->roots); ++i) { // Fill up symbol tables in proper scope and check existance. if (!symbol_check(parser, parser->parse_tree->roots[i])) { return false; } // Resolve type of expression for all elements. if (!resolve_type(parser, parser->parse_tree->roots[i])) { return false; } } return true; } ParseTree * parse(Token *tokens) { Parser parser = { .tokens = tokens, .current_token = 0, }; parser.parse_tree = alloc_parsetree(); if (!parse_roots(&parser)) { return NULL; } if (!semantic_analysis(&parser)) { return NULL; } return parser.parse_tree; }