From 90b0d817fedfa5715b195e16da67fa6bdd67638e Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 29 Dec 2025 00:07:16 +0200 Subject: work towards a simple integer vector implementation + Hopefully shows that useful programs can be implemented with the rules present + Still missing at least external functions with non-void returns --- src/analyze.c | 240 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 135 insertions(+), 105 deletions(-) (limited to 'src/analyze.c') diff --git a/src/analyze.c b/src/analyze.c index 4f98ac6..2dc039a 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -106,6 +106,19 @@ static int analyze_binop(struct state *state, struct scope *scope, if (analyze(state, scope, rhs)) return -1; + /* allow pointer arithmetic, follows C conventions */ + if (node->k == AST_ADD || node->k == AST_SUB) { + if (is_ptr_type(lhs->t->k) && is_int_type(rhs->t->k)) { + node->t = lhs->t; + return 0; + } + + if (is_ptr_type(rhs->t->k) && is_int_type(lhs->t->k)) { + node->t = rhs->t; + return 0; + } + } + if (!types_match(lhs->t, rhs->t)) { type_mismatch(scope, node, lhs->t, rhs->t); @@ -135,17 +148,9 @@ static int analyze_comparison(struct state *state, struct scope *scope, return -1; } - /** @todo check type is some primitive */ - char *tf = strdup("bool"); - if (!tf) { - internal_error("failed allocating comparison bool str"); - return -1; - } - - node->t = tgen_id(tf, node->loc); + node->t = tgen_type(TYPE_BOOL, NULL, NULL, node->loc); if (!node->t) { internal_error("failed allocating comparison bool type"); - free(tf); return -1; } @@ -190,10 +195,14 @@ static int analyze_var(struct state *state, struct scope *scope, static int analyze_let(struct state *state, struct scope *scope, struct ast *node) { - if (analyze(state, scope, let_var(node))) + if (analyze(state, scope, let_expr(node))) return -1; - if (analyze(state, scope, let_expr(node))) + struct ast *var = let_var(node); + if (!(var_type(var))) + var_type(var) = (let_expr(node))->t; + + if (analyze(state, scope, var)) return -1; struct type *l = (let_var(node))->t; @@ -232,7 +241,11 @@ static int deduce_closure_types(struct scope *scope, struct ast *node, struct ty } struct ast *param = closure_bindings(node); - struct type *t = tclosure_args(type); + struct type *t = (type->k == TYPE_CLOSURE) + ? tclosure_args(type) + : tpure_closure_args(type) + ; + if (ast_list_len(param) != type_list_len(t)) { semantic_error(scope, node, "expected %zu closure parameters, got %zu", type_list_len(t), ast_list_len(param)); @@ -535,7 +548,7 @@ static int analyze_construct(struct state *state, struct scope *scope, struct as { struct ast *def = file_scope_find_type(scope, construct_id(node)); if (!def) { - semantic_error(scope, node, "no such type"); + semantic_error(scope, node, "no such type: %s", construct_id(node)); return -1; } @@ -578,6 +591,69 @@ static int analyze_construct(struct state *state, struct scope *scope, struct as return 0; } +static int analyze_explode(struct state *state, struct scope *scope, struct ast *node) +{ + if (analyze(state, scope, explode_expr(node))) + return -1; + + struct type *type = (explode_expr(node))->t; + if (type->k != TYPE_ID) { + char *str = type_str(type); + semantic_error(scope, explode_expr(node), + "expected struct type, got %s\n", + str); + free(str); + return -1; + } + + struct ast *def = file_scope_find_type(scope, type->id); + if (!def || def->k != AST_STRUCT_DEF) { + semantic_error(scope, explode_expr(node), + "no such struct type: %s\n", + type->id); + return -1; + } + + struct ast *params = struct_body(def); + struct ast *args = explode_deconstruct(node); + + if (ast_list_len(params) != ast_list_len(args)) { + semantic_error(scope, node, "expected %zu args, got %zu\n", + ast_list_len(params), ast_list_len(args)); + return -1; + } + + foreach_node(arg, args) { + struct ast *var = deconstruction_var(arg); + struct ast *exists = scope_find_symbol(def->scope, deconstruction_id(arg)); + if (!exists) { + semantic_error(scope, arg, "no member %s in %s\n", + deconstruction_id(arg), type->id); + return -1; + } + + if (!var_type(var)) + (var_type(var)) = exists->t; + + if (analyze(state, scope, var)) + return -1; + + if (!types_match(exists->t, var->t)) { + type_mismatch(scope, arg, exists->t, var->t); + return -1; + } + + if (scope_add_symbol(scope, var)) + return -1; + + /** @todo check for duplicates, preferably not in O(n^2) or with + * a memory allocation? */ + } + + node->t = tgen_void(node->loc); + return 0; +} + static int analyze_if(struct state *state, struct scope *scope, struct ast *node) { @@ -661,66 +737,6 @@ static int analyze_as(struct state *state, struct scope *scope, struct ast *node return 0; } -static int analyze_assign(struct state *state, struct scope *scope, struct ast *node) -{ - struct ast *expr = assign_expr(node); - if (analyze(state, scope, expr)) - return -1; - - struct ast *target = assign_target(node); - if (analyze(state, scope, target)) - return -1; - - - if (!types_match(expr->t, target->t)) { - type_mismatch(scope, node, target->t, expr->t); - return -1; - } - - if (!is_lvalue(target)) { - semantic_error(scope, target, "not an lvalue"); - return -1; - } - - node->t = target->t; - return 0; -} - -static int analyze_dot(struct state *state, struct scope *scope, struct ast *node) -{ - struct ast *expr = dot_expr(node); - if (analyze(state, scope, expr)) - return -1; - - struct type *type = expr->t; - if (type->k != TYPE_ID) { - char *s = type_str(type); - semantic_error(scope, node, "type %s does not have any members", s); - free(s); - return -1; - } - - struct ast *def = file_scope_find_type(scope, tid_str(type)); - if (!def) { - semantic_error(scope, node, "no such type: %s", tid_str(type)); - return -1; - } - - if (def->k != AST_STRUCT_DEF) { - semantic_error(scope, node, "not a struct type: %s", tid_str(type)); - return -1; - } - - struct ast *member = scope_find_symbol(def->scope, dot_id(node)); - if (!member) { - semantic_error(scope, node, "no such member: %s", dot_id(node)); - return -1; - } - - node->t = member->t; - return 0; -} - static int analyze_sizeof(struct state *state, struct scope *scope, struct ast *node) { if (analyze_type(state, scope, sizeof_type(node))) @@ -731,34 +747,6 @@ static int analyze_sizeof(struct state *state, struct scope *scope, struct ast * return 0; } -static int analyze_arr(struct state *state, struct scope *scope, struct ast *node) -{ - struct ast *base = arr_base(node); - if (analyze(state, scope, base)) - return -1; - - if (base->t->k != TYPE_ARR) { - char *s = type_str(base->t); - semantic_error(scope, base, "expected array type, got %s", s); - free(s); - return -1; - } - - struct ast *idx = arr_idx(node); - if (analyze(state, scope, idx)) - return -1; - - if (!is_int_type(idx->t->k)) { - char *s = type_str(idx->t); - semantic_error(scope, idx, "expected int type, got %s", s); - free(s); - return -1; - } - - node->t = tarr_base(base->t); - return 0; -} - static int analyze_nil_check(struct state *state, struct scope *scope, struct ast *node) { struct ast *expr = nil_check_expr(node); @@ -805,6 +793,43 @@ static int analyze_forget(struct state *state, struct scope *scope, struct ast * return 0; } +static int analyze_put(struct state *state, struct scope *scope, struct ast *put) +{ + struct ast *dst = put_dst(put); + if (analyze(state, scope, dst)) + return -1; + + struct type *type = dst->t; + if (type->k != TYPE_REF) { + char *str = type_str(type); + semantic_error(scope, put, "trying to write to non-ref type %s\n", str); + free(str); + return -1; + } + + put->t = tref_base(type); + return 0; +} + +static int analyze_write(struct state *state, struct scope *scope, struct ast *write) +{ + struct ast *src = write_src(write); + if (analyze(state, scope, src)) + return -1; + + struct ast *dst = write_dst(write); + if (analyze(state, scope, dst)) + return -1; + + if (!types_match(src->t, dst->t)) { + type_mismatch(scope, write, src->t, dst->t); + return -1; + } + + write->t = tgen_void(write->loc); + return 0; +} + static int analyze(struct state *state, struct scope *scope, struct ast *node) { if (!node) @@ -864,14 +889,14 @@ static int analyze(struct state *state, struct scope *scope, struct ast *node) case AST_STRUCT_DEF: ret = analyze_struct(state, scope, node); break; case AST_CONSTRUCT: ret = analyze_construct(state, scope, node); break; + case AST_EXPLODE: ret = analyze_explode(state, scope, node); break; case AST_SIZEOF: ret = analyze_sizeof(state, scope, node); break; case AST_NIL: ret = analyze_nil(state, scope, node); break; case AST_AS: ret = analyze_as(state, scope, node); break; - case AST_ASSIGN: ret = analyze_assign(state, scope, node); break; - case AST_ARR: ret = analyze_arr(state, scope, node); break; - case AST_DOT: ret = analyze_dot(state, scope, node); break; + case AST_WRITE: ret = analyze_write(state, scope, node); break; + case AST_PUT: ret = analyze_put(state, scope, node); break; case AST_FORGET: ret = analyze_forget(state, scope, node); break; @@ -919,7 +944,7 @@ static int analyze_list(struct state *state, struct scope *scope, static int analyze_type(struct state *state, struct scope *scope, struct type *type) { - if (type->t0 && analyze_type(state, scope, type->t0)) + if (type->t0 && analyze_type_list(state, scope, type->t0)) return -1; /* temporary */ @@ -969,6 +994,11 @@ static int analyze_type(struct state *state, struct scope *scope, return 0; } + if (strcmp(id, "bool") == 0) { + type->k = TYPE_BOOL; + return 0; + } + /* check for user-defined types */ struct ast *def = file_scope_find_type(scope, id); if (!def) { -- cgit v1.2.3