From c2065e6e5e9eca78719c58dbe21f2fadfb44f961 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sun, 31 Oct 2021 14:46:02 +0100 Subject: Unify semantic analysis actions under a single function --- src/parser.c | 160 ++++++++++++++++++----------------------------------------- 1 file changed, 49 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/parser.c b/src/parser.c index d4deb74..31eb172 100644 --- a/src/parser.c +++ b/src/parser.c @@ -419,12 +419,14 @@ symbol_in_env(Environment *env, Object *symbol) { } void -check_object_scope(Environment *env, Object *obj, Errors *errors) { - if (obj == NULL) { +semantic_analysis(Environment *env, Object *obj, Errors *errors) { + if (obj == NULL || obj->visited) { return; } + obj->visited = true; switch (obj->type) { case OBJ_TYPE_SYMBOL: { + Object *found = symbol_in_env(env, obj); if (symbol_in_env(env, obj) == NULL) { error_push(errors, (Error){ .type = ERR_TYPE_PARSER, @@ -432,57 +434,56 @@ check_object_scope(Environment *env, Object *obj, Errors *errors) { .line = obj->line, .col = obj->col, }); + return; } - } break; - case OBJ_TYPE_PAIR: { - check_object_scope(env, obj->head, errors); - check_object_scope(env, obj->tail, errors); + semantic_analysis(env, found, errors); } break; case OBJ_TYPE_DEF: { ht_insert(env->table, obj->var_name, obj->var_expr); - check_object_scope(env, obj->var_expr, errors); + semantic_analysis(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); + semantic_analysis(env, obj->var_name, errors); + semantic_analysis(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); - obj->env = new_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; - } -} - -void -remove_unused_expr(Object *obj) { - if (obj == NULL) { - return; - } - switch (obj->type) { - case OBJ_TYPE_DEF: - case OBJ_TYPE_SET: { - remove_unused_expr(obj->var_expr); - } break; - case OBJ_TYPE_IF: { - remove_unused_expr(obj->condition); - remove_unused_expr(obj->expr_true); - remove_unused_expr(obj->expr_false); + semantic_analysis(env, obj->condition, errors); + semantic_analysis(env, obj->expr_true, errors); + semantic_analysis(env, obj->expr_false, errors); } break; case OBJ_TYPE_PAIR: { - remove_unused_expr(obj->head); - remove_unused_expr(obj->tail); + Object *head = obj->head; + if (IS_SYMBOL(head)) { + head = symbol_in_env(env, head); + if (head == NULL) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_SYMBOL_NOT_FOUND, + .line = obj->head->line, + .col = obj->head->col, + }); + return; + } + } + if (IS_LAMBDA(head)) { + if (obj->n_elems != array_size(head->params)) { + error_push(errors, (Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_NOT_ENOUGH_ARGS, + .line = obj->line, + .col = obj->col + }); + return; + } + } + semantic_analysis(env, obj->head, errors); + semantic_analysis(env, obj->tail, errors); } break; case OBJ_TYPE_LAMBDA: { + // Initialize scope for this lambda. + Environment *new_env = env_alloc(env); + obj->env = new_env; + // Used for removing unnecessary statements. Object **new_body = NULL; array_init(new_body, 0); for (size_t i = 0; i < array_size(obj->body); i++) { @@ -497,7 +498,7 @@ remove_unused_expr(Object *obj) { continue; } } - remove_unused_expr(expr); + semantic_analysis(obj->env, expr, errors); array_push(new_body, expr); } array_free(obj->body); @@ -507,54 +508,6 @@ remove_unused_expr(Object *obj) { } } -void -check_function_args(Environment *env, Object *obj, Errors *errors) { - if (obj == NULL || obj->visited) { - return; - } - obj->visited = true; - switch (obj->type) { - case OBJ_TYPE_SYMBOL: { - Object *found = symbol_in_env(env, obj); - check_function_args(env, found, errors); - } break; - case OBJ_TYPE_DEF: - case OBJ_TYPE_SET: { - check_function_args(env, obj->var_expr, errors); - } break; - case OBJ_TYPE_IF: { - check_function_args(env, obj->condition, errors); - check_function_args(env, obj->expr_true, errors); - check_function_args(env, obj->expr_false, errors); - } break; - case OBJ_TYPE_PAIR: { - Object *head = obj->head; - if (IS_SYMBOL(head)) { - head = symbol_in_env(env, head); - } - if (IS_LAMBDA(head)) { - if (obj->n_elems != array_size(head->params)) { - error_push(errors, (Error){ - .type = ERR_TYPE_PARSER, - .value = ERR_NOT_ENOUGH_ARGS, - .line = obj->line, - .col = obj->col - }); - } - } - check_function_args(env, head, errors); - check_function_args(env, obj->tail, errors); - } break; - case OBJ_TYPE_LAMBDA: { - for (size_t i = 0; i < array_size(obj->body); i++) { - Object *expr = obj->body[i]; - check_function_args(obj->env, expr, errors); - } - } break; - default: break; - } -} - Root * parse(Token *tokens, Errors *errors) { array_init(roots, 0); @@ -589,16 +542,10 @@ parse(Token *tokens, Errors *errors) { ht_insert(global_env->table, symbol, symbol); } - // 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); - if (errors->n != 0) { - return NULL; - } - } - - // Remove unnecessary statements. + // Perform semantic analysis: + // 1. Populate symbol tables and ensure symbols are in scope when used. + // 2. Removing unnecessary expressions. + // 3. Verify number of arguments is correct in function calls. Root *final_roots = NULL; array_init(final_roots, 0); for (size_t i = 0; i < array_size(roots); i++) { @@ -614,24 +561,15 @@ parse(Token *tokens, Errors *errors) { } } array_push(final_roots, root); - remove_unused_expr(root); + semantic_analysis(global_env, root, errors); if (errors->n != 0) { + array_free(final_roots); return NULL; } } array_free(roots); roots = final_roots; - // Check that the number of arguments in function calls match the number of - // formal parameters. - for (size_t i = 0; i < array_size(roots); i++) { - Object *root = roots[i]; - check_function_args(global_env, root, errors); - if (errors->n != 0) { - return NULL; - } - } - // TODO: Type check basic expressions (e.g. arithmetic/numeric comparisons). // We can't be sure when we have functions unless the return type is known. -- cgit v1.2.1