From 4b3a8b147ec2b0fbba0406e9f5ce68db8ca0b748 Mon Sep 17 00:00:00 2001 From: davidmaamoaix Date: Tue, 5 Mar 2024 22:40:13 -0500 Subject: [PATCH] minor typecheck adjustment --- Makefile | 3 ++- c0-utils | 2 +- src/ast.c1 | 4 ++++ src/compile.c1 | 5 ++--- src/parser.c1 | 25 ++++++++++++++----------- src/type_check.c1 | 38 +++++++++++++++++++++++++++++++++++--- 6 files changed, 58 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index b68afdd..2ad8619 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ SRC_MAIN = \ # build settings LIBS = \ + $(C0_UTIL_PATH)/shorthand.c1 \ $(C0_UTIL_PATH)/vector.c1 \ $(C0_UTIL_PATH)/ordered_map.c1 \ $(C0_UTIL_PATH)/regex.c1 @@ -47,5 +48,5 @@ clean: init: clean echo "% $(CC) $(CFLAGS) -o $(OBJ) $(LIBS) $(SRC)" > README.txt -test: init +test: $(OBJ) $(PY) tests/unit_test.py diff --git a/c0-utils b/c0-utils index a82bf90..3ce2a81 160000 --- a/c0-utils +++ b/c0-utils @@ -1 +1 @@ -Subproject commit a82bf90edc1968a71de8fd257c3237e95e9cb031 +Subproject commit 3ce2a81b53233afee821c26ffd86b0be8dce855d diff --git a/src/ast.c1 b/src/ast.c1 index cc3c703..64f73f4 100644 --- a/src/ast.c1 +++ b/src/ast.c1 @@ -16,6 +16,7 @@ struct ast_type_t { string iden; // 'A', 'P' + // `content == NULL`: then this is a null pointer (can be any pointer type) struct ast_type_t *content; // positional information @@ -79,6 +80,9 @@ struct ast_exp_t { // positional information u_pos_t *pos; + // the type of this expression (populated on typecheck) + ast_type_t *etype; + // number of C0VM instructions needed to load this expression int n_c0vm_code; }; diff --git a/src/compile.c1 b/src/compile.c1 index 8023b2c..7d49b58 100644 --- a/src/compile.c1 +++ b/src/compile.c1 @@ -64,10 +64,9 @@ c_result_t *compile(vec_t *file_reprs, cparams_t *params) { if (params->dump_ast) { println("// INCLUDED LIBS"); - void *[] libs = alloc_array(void *, om_size(gctx->libs)); - __om_collect_keys(gctx->libs->root, libs, 0); + vec_t *libs = om_get_keys(gctx->libs); for (int l = 0; l < om_size(gctx->libs); l++) { - printf("#use <%s>\n", * (string *) libs[l]); + printf("#use <%s>\n", * (string *) v_get(libs, l)); } if (!om_empty(gctx->libs)) println(""); diff --git a/src/parser.c1 b/src/parser.c1 index bf98ab8..c1e6549 100644 --- a/src/parser.c1 +++ b/src/parser.c1 @@ -1025,8 +1025,11 @@ ast_func_t *__p_parse_func(p_ctx_t *ctx) func->param_types = v_create_vector(); func->param_names = v_create_vector(); - func->ret_type = __p_expect_type(ctx); - if (func->ret_type == NULL) return NULL; + ast_type_t *rtype = __p_expect_type(ctx); + if (rtype == NULL) return NULL; + func->ret_type = rtype; + if (!t_assert_valid_type(ctx->glob_ctx, rtype, false)) return NULL; + if (!t_assert_small_type(ctx->glob_ctx, rtype)) return NULL; l_token_t *iden_tok = __p_expect_id_tok(ctx, true); if (iden_tok == NULL) return NULL; @@ -1243,14 +1246,14 @@ ast_program_t *__p_parse_program(p_ctx_t *ctx) Parsing each file updates the declared types that the parse has accumulated so far. */ -e_error_t *p_parse_file(fr_file_t *file, s_glob_ctx_t *glob_ctx) -//@requires file != NULL; -//@requires v_is_vector(file->tokens); -{ - p_ctx_t *ctx = p_create_ctx(file->tokens, glob_ctx); - file->ast = __p_parse_program(ctx); - - return ctx->glob_ctx->err; -} +// e_error_t *p_parse_file(fr_file_t *file, s_glob_ctx_t *glob_ctx) +// //@requires file != NULL; +// //@requires v_is_vector(file->tokens); +// { +// p_ctx_t *ctx = p_create_ctx(file->tokens, glob_ctx); +// file->ast = __p_parse_program(ctx); + +// return ctx->glob_ctx->err; +// } // END parsing stage diff --git a/src/type_check.c1 b/src/type_check.c1 index bd21a85..7496dfc 100644 --- a/src/type_check.c1 +++ b/src/type_check.c1 @@ -61,6 +61,9 @@ e_error_t *t_is_valid_type( } if (type->type == 'A' || type->type == 'P') { + // type of a `NULL` literal + if (type->type == 'P' && type->content == NULL) return NULL; + return t_is_valid_type(gctx, type->content, false); } @@ -96,7 +99,12 @@ bool t_match_type(s_glob_ctx_t *gctx, ast_type_t *expect, ast_type_t *real) if (expect->type == 'X') { return string_equal(expect->iden, real->iden); - } else if (expect->type == 'A' || expect->type == 'P') { + } else if (expect->type == 'A') { + return t_match_type(gctx, expect->content, real->content); + } else if (expect->type == 'P') { + // a `NULL` literal matches any pointer type + if (real->content == NULL) return true; + return t_match_type(gctx, expect->content, real->content); } else { return true; @@ -107,6 +115,7 @@ bool t_match_type(s_glob_ctx_t *gctx, ast_type_t *expect, ast_type_t *real) // BEGIN type assertions +// only used for AST type bool t_assert_valid_type(s_glob_ctx_t *gctx, ast_type_t *type, bool allow_void) //@requires __s_is_glob_ctx(gctx); //@requires type != NULL; @@ -115,6 +124,7 @@ bool t_assert_valid_type(s_glob_ctx_t *gctx, ast_type_t *type, bool allow_void) return !s_has_err(gctx); } +// only used for AST type bool t_assert_small_type(s_glob_ctx_t *gctx, ast_type_t *type) //@requires __s_is_glob_ctx(gctx); //@requires t_is_valid_type(gctx, type, true) == NULL; @@ -128,7 +138,7 @@ bool t_assert_small_type(s_glob_ctx_t *gctx, ast_type_t *type) } bool t_assert_match_type( - s_glob_ctx_t *gctx, ast_type_t *expect, ast_type_t *real + s_glob_ctx_t *gctx, ast_type_t *expect, ast_type_t *real, u_pos_t *pos ) //@requires __s_is_glob_ctx(gctx); //@requires t_is_valid_type(gctx, expect, true) == NULL; @@ -136,7 +146,7 @@ bool t_assert_match_type( { if (!t_match_type(gctx, expect, real)) { // TODO: get a AST_TO_STRING function for better error message - s_set_err_at(gctx, 31, "type msimatch", real->pos); + s_set_err_at(gctx, 31, "type msimatch", pos); return false; } @@ -144,3 +154,25 @@ bool t_assert_match_type( } // END type assertions + +// BEGIN exp type check + +// populates the `type` +bool t_check_term(s_glob_ctx_t *gctx, ast_exp_t *term) +//@requires __s_is_glob_ctx(gctx); +//@ensures xor(\result, e_has_err(gctx->err)); +{ + ast_type_t *type = alloc(ast_type_t); + if (term->type == 'I') type->type = 'I'; + else if (term->type == 'C') type->type = 'C'; + else if (term->type == 'S') type->type = 'S'; + else if (term->type == 'B') type->type = 'S'; + else if (term->type == 'N') type->type = 'S'; + else if (term->type == 'D') type->type = 'S'; + else { error("unimplemented type"); } + + term->etype = type; + return true; +} + +// END exp type check