diff options
Diffstat (limited to 'src/analyze.c')
-rw-r--r-- | src/analyze.c | 276 |
1 files changed, 202 insertions, 74 deletions
diff --git a/src/analyze.c b/src/analyze.c index 0c06096..be52bfb 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1,12 +1,21 @@ /* SPDX-License-Identifier: copyleft-next-0.3.1 */ /* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ +#include <fwd/compiler.h> #include <fwd/analyze.h> +#include <fwd/mod.h> #include <stdlib.h> +#include <stdarg.h> #include <string.h> #include <assert.h> +#include <dlfcn.h> + +enum state_flags { + STATE_PROC_REQ_FRAME = (1 << 0) +}; struct state { + enum state_flags flags; }; static int analyze(struct state *state, struct scope *scope, struct ast *node); @@ -62,7 +71,13 @@ static int analyze_proc(struct state *state, struct scope *scope, if (!proc_body(node)) return 0; - return analyze_known_block(&proc_state, proc_scope, proc_body(node)); + if (analyze_known_block(&proc_state, proc_scope, proc_body(node))) + return -1; + + if (proc_state.flags & STATE_PROC_REQ_FRAME) + ast_set_flags(node, AST_REQ_FRAME); + + return 0; } static int analyze_unop(struct state *state, struct scope *scope, @@ -144,28 +159,6 @@ static int analyze_known_block(struct state *state, struct scope *scope, struct if (analyze_list(state, scope, block_body(node))) return -1; - struct ast *err = block_error(node); - if (!err) - return 0; - - 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; } @@ -261,6 +254,9 @@ static int analyze_call(struct state *state, struct scope *scope, struct type *type = types; foreach_node(arg, args) { + if (arg->k == AST_CLOSURE) + state->flags |= STATE_PROC_REQ_FRAME; + if (!types_match(type, arg->t)) { type_mismatch(scope, node, type, arg->t); return -1; @@ -277,7 +273,7 @@ static int analyze_call(struct state *state, struct scope *scope, return -1; } - return analyze(state, scope, call_err(node)); + return 0; } static int analyze_ref(struct state *state, struct scope *scope, @@ -396,17 +392,10 @@ static int analyze_int(struct state *state, struct scope *scope, (void)state; (void)scope; - /** @todo do this properly, very hacky, bad bad bad */ - char *i = strdup("int"); - if (!i) { - internal_error("failed allocating constant int type string"); - return -1; - } - - node->t = tgen_id(i, node->loc); + /* start with largest possible and work down */ + node->t = tgen_type(TYPE_I64, NULL, NULL, node->loc); if (!node->t) { internal_error("failed allocating constant int type"); - free(i); return -1; } @@ -464,40 +453,6 @@ 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_symbol(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) @@ -535,7 +490,6 @@ 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; @@ -545,7 +499,6 @@ 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; @@ -556,6 +509,12 @@ static int analyze(struct state *state, struct scope *scope, struct ast *node) node->t = tgen_void(node->loc); ret = 0; break; + + case AST_IMPORT: + node->t = tgen_void(node->loc); + ret = 0; + break; + default: internal_error("missing ast analysis for %s", ast_str(node->k)); return -1; @@ -585,11 +544,43 @@ static int analyze_list(struct state *state, struct scope *scope, static int analyze_type(struct state *state, struct scope *scope, struct type *type) { - /* for now, let's just say all types are fine as they are, specified by - * the user. */ - (void)state; - (void)scope; - (void)type; + if (type->t0 && analyze_type(state, scope, type->t0)) + return -1; + + /* temporary */ + if (type->k != TYPE_ID) + return 0; + + char *id = type->id; + + if (strcmp(id, "i8") == 0) + type->k = TYPE_I8; + + else if (strcmp(id, "u8") == 0) + type->k = TYPE_U8; + + else if (strcmp(id, "i16") == 0) + type->k = TYPE_I16; + + else if (strcmp(id, "u16") == 0) + type->k = TYPE_U16; + + else if (strcmp(id, "i32") == 0) + type->k = TYPE_I32; + + else if (strcmp(id, "u32") == 0) + type->k = TYPE_U32; + + else if (strcmp(id, "i64") == 0) + type->k = TYPE_I64; + + else if (strcmp(id, "u64") == 0) + type->k = TYPE_U64; + else { + internal_error("unhandled type id: %s", id); + abort(); + } + return 0; } @@ -604,6 +595,133 @@ static int analyze_type_list(struct state *state, struct scope *scope, return 0; } +static int copy_scope(bool reexport, struct scope *to, struct scope *from) +{ + foreach(visible, symbol, &from->symbols) { + struct ast *def = symbol->data; + if (!reexport && def->scope != from) + continue; + + if (!ast_flags(def, AST_FLAG_PUBLIC)) + continue; + + if (scope_add_symbol(to, def)) + return -1; + } + + foreach(visible, symbol, &from->types) { + struct ast *def = symbol->data; + if (!reexport && def->scope != from) + continue; + + if (!ast_flags(def, AST_FLAG_PUBLIC)) + continue; + + if (scope_add_symbol(to, def)) + return -1; + } + + foreach(visible, symbol, &from->traits) { + struct ast *def = symbol->data; + if (!reexport && def->scope != from) + continue; + + if (!ast_flags(def, AST_FLAG_PUBLIC)) + continue; + + if (scope_add_symbol(to, def)) + return -1; + } + + return 0; +} + +/* allowed to be noisy */ +static int try_import_file(struct scope *scope, struct ast *node) +{ + const char *file = import_file(node); + struct scope *child = compile_file(file); + if (!child) { + semantic_info(scope, node, "imported here"); + return -1; + } + + if (copy_scope(ast_flags(node, AST_FLAG_PUBLIC), scope, child)) { + semantic_info(scope, node, "imported here"); + return -1; + } + + return 0; +} + +/* should be quiet upon failure */ +static int try_import_mod(struct scope *scope, struct ast *node) +{ + /** @todo cleanup */ + void *mod = dlopen(import_file(node), RTLD_LAZY); + if (!mod) + return -1; + + fwd_open_t fwdopen = dlsym(mod, "fwdopen"); + if (!fwdopen) { + dlclose(mod); + return -1; + } + + mod_vec_append(&scope->mods, mod); + return fwdopen((void *)scope); +} + +static struct type *fwd_type_kind(fwd_type_t type) +{ + switch (type) { + case FWD_VOID: return tgen_void(NULL_LOC()); + case FWD_I64: return tgen_type(TYPE_I64, NULL, NULL, NULL_LOC()); + case FWD_PTR: { + struct type *base = tgen_void(NULL_LOC()); + return tgen_ptr(base, NULL_LOC()); + } + + default: + break; + } + + abort(); + return NULL; +} + +int fwd_register(struct fwd_state *state, const char *name, fwd_extern_t func, fwd_type_t rtype, ...) +{ + struct scope *scope = (void *)state; + struct ast *vars = NULL; + + va_list args; + va_start(args, rtype); + while (1) { + fwd_type_t type = va_arg(args, enum fwd_type); + if (type == FWD_END) + break; + + struct ast *new = gen_var(strdup("arg"), fwd_type_kind(type), NULL_LOC()); + + if (vars) + vars->n = new; + else + vars = new; + } + va_end(args); + + vars = reverse_ast_list(vars); + + struct ast *def = gen_proc(strdup(name), vars, + fwd_type_kind(rtype), NULL, NULL_LOC()); + + if (scope_add_symbol(scope, def)) + return -1; + + return 0; +} + int analyze_root(struct scope *scope, struct ast *root) { foreach_node(node, root) { @@ -628,6 +746,16 @@ int analyze_root(struct scope *scope, struct ast *root) return -1; break; + case AST_IMPORT: { + if (!try_import_mod(scope, node)) + break; + + if (!try_import_file(scope, node)) + break; + + return -1; + } + default: abort(); } |