From a921acd83750a66bcb73179ce1581f3280197289 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sat, 30 Oct 2021 14:59:44 +0200 Subject: Add symbol declaration error checking --- src/parser.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/src/parser.c b/src/parser.c index 2429f68..3e6abc2 100644 --- a/src/parser.c +++ b/src/parser.c @@ -313,13 +313,28 @@ parse_list(Parser *parser, Errors *errors) { root->head = NULL; root->tail = NULL; Object *current = root; + bool first = true; while (has_next_token(parser)) { + Token tok = peek_token(parser); current->head = parse_tree(parser, errors); if (errors->n != 0 || current->head == NULL) { return NULL; } - Token tok = peek_token(parser); + if (first) { + if (!IS_SYMBOL(current->head) && !IS_LAMBDA(current->head)) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_NOT_CALLABLE, + .line = tok.line, + .col = tok.col, + }); + return NULL; + } + first = false; + } + + tok = peek_token(parser); if (tok.type == TOKEN_RPAREN) { next_token(parser); return root; @@ -388,9 +403,60 @@ parse_tree(Parser *parser, Errors *errors) { return NULL; } +bool +symbol_in_env(Environment *env, Object *symbol) { + while (env != NULL) { + Object *found = ht_lookup(env->table, symbol); + if (found != NULL) { + return true; + } + env = env->parent; + } + return false; +} + void -scope_check(Environment *env) { - // STUB +check_object_scope(Environment *env, Object *obj, Errors *errors) { + if (obj == NULL) { + return; + } + switch (obj->type) { + case OBJ_TYPE_SYMBOL: { + if (!symbol_in_env(env, obj)) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_SYMBOL_NOT_FOUND, + .line = obj->line, + .col = obj->col, + }); + } + } break; + case OBJ_TYPE_PAIR: { + check_object_scope(env, obj->head, errors); + check_object_scope(env, obj->tail, errors); + } break; + case OBJ_TYPE_DEF: { + ht_insert(env->table, obj->var_name, obj->var_expr); + check_object_scope(env, obj->var_expr, errors); + } break; + case OBJ_TYPE_SET: { + check_object_scope(env, obj->var_name, errors); + check_object_scope(env, obj->var_expr, errors); + } break; + case OBJ_TYPE_IF: { + check_object_scope(env, obj->condition, errors); + check_object_scope(env, obj->expr_true, errors); + check_object_scope(env, obj->expr_false, errors); + } break; + case OBJ_TYPE_LAMBDA: { + Environment *new_env = env_alloc(env); + for (size_t i = 0; i < array_size(obj->body); i++) { + Object *expr = obj->body[i]; + check_object_scope(new_env, expr, errors); + } + } break; + default: break; + } } Root * @@ -428,9 +494,12 @@ parse(Token *tokens, Errors *errors) { ht_insert(global_env->table, symbol, symbol); } - // Perform semantic analysis. - scope_check(global_env); - // TODO: Check that symbols are defined before usage. + // Check that symbols are defined before usage. + for (size_t i = 0; i < array_size(roots); i++) { + Object *root = roots[i]; + check_object_scope(global_env, root, errors); + } + // TODO: Remove unnecessary statements. return roots; } -- cgit v1.2.1