diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-03-17 02:12:02 +0200 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-03-17 02:12:02 +0200 |
commit | 78bf3e039d77e3eb0d5e394273adb69b2b70a76d (patch) | |
tree | 0ed6f2058e348dbd18b0baa9c4ee442206191096 /src/analyze.c | |
parent | 2367a8b63c3bcfe62d1aaf7d82c0ab3622f3b16c (diff) | |
download | fwd-78bf3e039d77e3eb0d5e394273adb69b2b70a76d.tar.gz fwd-78bf3e039d77e3eb0d5e394273adb69b2b70a76d.zip |
detect leaks
Diffstat (limited to 'src/analyze.c')
-rw-r--r-- | src/analyze.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/src/analyze.c b/src/analyze.c index 8e76892..7eee49a 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -30,6 +30,7 @@ static int analyze_proc(struct state *state, struct scope *scope, return -1; } + proc_scope->flags |= SCOPE_PROC; scope_add_scope(scope, proc_scope); struct state proc_state = {}; @@ -150,6 +151,28 @@ static int analyze_block(struct state *state, struct scope *scope, else node->t = tgen_void(node->loc); + if (!block_error(node)) + return 0; + + struct ast *err = block_error(node); + if (error_str(err)) + return 0; + + struct ast *id = error_id(err); + assert(id); + + struct ast *def = file_scope_find_symbol(scope, id_str(id)); + if (!def) { + semantic_error(scope, id, "no such symbol"); + return -1; + } + + struct type *t = def->t; + if (t->k != TYPE_ERR) { + semantic_error(scope, id, "invalid error variable type"); + return -1; + } + return 0; } @@ -248,7 +271,7 @@ static int analyze_call(struct state *state, struct scope *scope, return -1; } - return 0; + return analyze(state, scope, call_err(node)); } static int analyze_ref(struct state *state, struct scope *scope, @@ -332,6 +355,8 @@ static int analyze_closure(struct state *state, struct scope *scope, return -1; } + node->scope = closure_scope; + closure_scope->flags |= SCOPE_PROC; scope_add_scope(scope, closure_scope); if (analyze_list(state, closure_scope, closure_bindings(node))) @@ -427,6 +452,40 @@ static int analyze_if(struct state *state, struct scope *scope, return 0; } +static int analyze_err_branch(struct state *state, struct scope *scope, struct ast *node) +{ + struct scope *branch_scope = create_scope(); + if (!branch_scope) { + internal_error("failed allocating err branch scope"); + return -1; + } + + node->t = tgen_void(node->loc); + + scope_add_scope(scope, branch_scope); + struct ast *var = gen_var(strdup(err_branch_id(node)), NULL, node->loc); + struct type *err_type = tgen_err(node->loc); + var->t = err_type; + scope_add_var(branch_scope, var); + return analyze(state, branch_scope, err_branch_body(node)); +} + +static int analyze_own(struct state *state, struct scope *scope, struct ast *node) +{ + struct ast *found = file_scope_find_symbol(scope, own_id(node)); + if (!found) { + semantic_error(scope, node, "no symbol named \"%s\"", + own_id(node)); + return -1; + } + + if (is_trivially_copyable(found->t)) + semantic_warn(scope, node, "trivially copyable type is never owned"); + + node->t = tgen_void(node->loc); + return analyze(state, scope, own_body(node)); +} + static int analyze(struct state *state, struct scope *scope, struct ast *node) { if (!node) @@ -464,6 +523,7 @@ static int analyze(struct state *state, struct scope *scope, struct ast *node) } switch (node->k) { + case AST_ERR_BRANCH: ret = analyze_err_branch(state, scope, node); break; case AST_CLOSURE: ret = analyze_closure(state, scope, node); break; case AST_PROC_DEF: ret = analyze_proc(state, scope, node); break; case AST_VAR_DEF: ret = analyze_var(state, scope, node); break; @@ -473,6 +533,7 @@ static int analyze(struct state *state, struct scope *scope, struct ast *node) case AST_CALL: ret = analyze_call(state, scope, node); break; case AST_REF: ret = analyze_ref(state, scope, node); break; case AST_LET: ret = analyze_let(state, scope, node); break; + case AST_OWN: ret = analyze_own(state, scope, node); break; case AST_ID: ret = analyze_id(state, scope, node); break; case AST_IF: ret = analyze_if(state, scope, node); break; |