From 7633987d40fa0972b868ab92e580367d49c87d1b Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Tue, 5 Mar 2024 13:52:16 +0100 Subject: [PATCH] :art: remove unnecessary --- include/sema.h | 1 + include/sema_private.h | 72 ++++ src/parse/check.c | 4 +- src/parse/func_resolve_tmpl.c | 13 +- src/parse/scan1.c | 2 +- src/parse/scan2.c | 2 +- src/parse/spread.c | 1 - src/pass.c | 7 +- src/sema/sema.c | 591 ++++++++++++++++++++++++++++ tests/error/func_arg_array_empty.gw | 2 +- tests/error/func_ret_array_empty.gw | 4 +- tests/error/new_empty_array.gw | 2 +- tests/error/ptr_arg_array.gw | 2 +- tests/error/union_array_empty.gw | 2 +- 14 files changed, 683 insertions(+), 22 deletions(-) create mode 100644 include/sema.h create mode 100644 include/sema_private.h create mode 100644 src/sema/sema.c diff --git a/include/sema.h b/include/sema.h new file mode 100644 index 00000000..8b8a3763 --- /dev/null +++ b/include/sema.h @@ -0,0 +1 @@ +ANN bool sema_pass(Env a, Ast *b); diff --git a/include/sema_private.h b/include/sema_private.h new file mode 100644 index 00000000..bff82abd --- /dev/null +++ b/include/sema_private.h @@ -0,0 +1,72 @@ +typedef struct { + char *filename; + MemPool mp; + //Context context; + bool error; + bool func; + bool handling; +} Sema; + +ANN static bool sema_array_sub(Sema *a, Array_Sub b); +ANN static bool sema_tmpl(Sema *a, Tmpl *b); +ANN static bool sema_range(Sema *a, Range *b); +ANN static bool sema_type_decl(Sema *a, Type_Decl *b); +ANN static bool sema_prim_id(Sema *a, Symbol *b); +ANN static bool sema_prim_num(Sema *a, m_uint *b); +ANN static bool sema_prim_float(Sema *a, m_float *b); +ANN static bool sema_prim_str(Sema *a, m_str *b); +ANN static bool sema_prim_array(Sema *a, Array_Sub *b); +ANN static bool sema_prim_range(Sema *a, Range* *b); +ANN static bool sema_prim_dict(Sema *a, Exp* *b); +ANN static bool sema_prim_hack(Sema *a, Exp* *b); +ANN static bool sema_prim_interp(Sema *a, Exp* *b); +ANN static bool sema_prim_char(Sema *a, m_str *b); +ANN static bool sema_prim_nil(Sema *a, bool *b); +ANN static bool sema_prim_perform(Sema *a, Symbol *b); +ANN static bool sema_prim(Sema *a, Exp_Primary *b); +ANN static bool sema_variable(Sema *a, Variable *b); +ANN static bool sema_exp_decl(Sema *a, Exp_Decl *b); +ANN static bool sema_exp_binary(Sema *a, Exp_Binary *b); +ANN static bool sema_exp_unary(Sema *a, Exp_Unary *b); +ANN static bool sema_exp_cast(Sema *a, Exp_Cast *b); +ANN static bool sema_exp_post(Sema *a, Exp_Postfix *b); +ANN static bool sema_exp_call(Sema *a, Exp_Call *b); +ANN static bool sema_exp_array(Sema *a, Exp_Array *b); +ANN static bool sema_exp_slice(Sema *a, Exp_Slice *b); +ANN static bool sema_exp_if(Sema *a, Exp_If *b); +ANN static bool sema_exp_dot(Sema *a, Exp_Dot *b); +ANN static bool sema_exp_lambda(Sema *a, Exp_Lambda *b); +ANN static bool sema_exp_td(Sema *a, Type_Decl *b); +ANN static bool sema_exp(Sema *a, Exp* b); +ANN static bool sema_stmt_exp(Sema *a, Stmt_Exp b); +ANN static bool sema_stmt_while(Sema *a, Stmt_Flow b); +ANN static bool sema_stmt_until(Sema *a, Stmt_Flow b); +ANN static bool sema_stmt_for(Sema *a, Stmt_For b); +ANN static bool sema_stmt_each(Sema *a, Stmt_Each b); +ANN static bool sema_stmt_loop(Sema *a, Stmt_Loop b); +ANN static bool sema_stmt_if(Sema *a, Stmt_If b); +ANN static bool sema_stmt_code(Sema *a, Stmt_Code b); +ANN static bool sema_stmt_break(Sema *a, Stmt_Index b); +ANN static bool sema_stmt_continue(Sema *a, Stmt_Index b); +ANN static bool sema_stmt_return(Sema *a, Stmt_Exp b); +ANN static bool sema_case_list(Sema *a, Stmt_List b); +ANN static bool sema_stmt_match(Sema *a, Stmt_Match b); +ANN static bool sema_stmt_case(Sema *a, Stmt_Match b); +ANN static bool sema_stmt_index(Sema *a, Stmt_Index b); +ANN static bool sema_stmt_pp(Sema *a, Stmt_PP b); +ANN static bool sema_stmt_retry(Sema *a, Stmt_Exp b); +ANN static bool sema_stmt_try(Sema *a, Stmt_Try b); +ANN static bool sema_stmt_defer(Sema *a, Stmt_Defer b); +ANN static bool sema_stmt(Sema *a, Stmt* b); +ANN static bool sema_stmt_list(Sema *a, Stmt_List b); +ANN static bool sema_func_base(Sema *a, Func_Base *b); +ANN static bool sema_func_def(Sema *a, Func_Def b); +ANN static bool sema_class_def(Sema *a, Class_Def b); +ANN static bool sema_trait_def(Sema *a, Trait_Def b); +ANN static bool sema_enum_def(Sema *a, Enum_Def b); +ANN static bool sema_union_def(Sema *a, Union_Def b); +ANN static bool sema_fptr_def(Sema *a, Fptr_Def b); +ANN static bool sema_type_def(Sema *a, Type_Def b); +ANN static bool sema_extend_def(Sema *a, Extend_Def b); +ANN static bool sema_section(Sema *a, Section *b); +ANN static bool sema_ast(Sema *a, Ast b); diff --git a/src/parse/check.c b/src/parse/check.c index 3c9e9d0b..56b176cd 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -226,8 +226,8 @@ ANN static inline Type prim_array_match(const Env env, Exp* e) { ANN static Type check_prim_array(const Env env, const Array_Sub *data) { const Array_Sub array = *data; Exp* e = array->exp; - if (!e) - ERR_O(prim_pos(data), _("must provide values/expressions for array [...]")); +// if (!e) +// ERR_O(prim_pos(data), _("must provide values/expressions for array [...]")); CHECK_O(check_exp(env, e)); env_weight(env, 1); return array->type = prim_array_match(env, e); diff --git a/src/parse/func_resolve_tmpl.c b/src/parse/func_resolve_tmpl.c index ce8bacdc..1d46d318 100644 --- a/src/parse/func_resolve_tmpl.c +++ b/src/parse/func_resolve_tmpl.c @@ -30,19 +30,16 @@ ANN static inline Value template_get_ready(const Env env, const Value v, } ANN static inline bool -tmpl_valid(const Env env, const Func_Def fdef, const m_str filename) { +tmpl_valid(const Env env, const Func_Def fdef) { if (safe_fflag(fdef->base->func, fflag_valid)) return true; -// const m_str old_file = env->name; -// env->name = filename; const bool ret = check_traverse_fdef(env, fdef); -// env->name = old_file; if(!fdef->base->func) free_func_def(env->gwion->mp, fdef); return ret; } ANN static Func ensure_tmpl(const Env env, const Func_Def fdef, - Exp_Call *const exp, const m_str filename) { - if (!tmpl_valid(env, fdef, filename)) return NULL; + Exp_Call *const exp) { + if (!tmpl_valid(env, fdef)) return NULL; if (exp->args && !exp->args->type) return NULL; const Func f = fdef->base->func; const Tmpl tmpl = {.list = fdef->base->tmpl->list, .call = exp->tmpl->call}; @@ -92,7 +89,7 @@ ANN static Func tmpl_exists(const Env env, struct ResolverArgs *ra, const Value exists) { if (env->func == exists->d.func_ref) return find_func_match(env, env->func, ra->e) ? env->func : NULL; - return ensure_tmpl(env, exists->d.func_ref->def, ra->e, ra->v->from->filename); + return ensure_tmpl(env, exists->d.func_ref->def, ra->e); } ANN static Func create_tmpl(const Env env, struct ResolverArgs *ra, @@ -122,7 +119,7 @@ ANN static Func create_tmpl(const Env env, struct ResolverArgs *ra, } fdef->base->args = args; } - const Func func = ensure_tmpl(env, fdef, ra->e, ra->v->from->filename); + const Func func = ensure_tmpl(env, fdef, ra->e); if (func && func->def->builtin) { builtin_func(env->gwion, func, (void*)ra->v->d.func_ref->code->native_func); set_vflag(func->value_ref, vflag_builtin); diff --git a/src/parse/scan1.c b/src/parse/scan1.c index a6843143..93cf66a1 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -189,7 +189,7 @@ ANN static inline bool scan1_prim(const Env env, const Exp_Primary *prim) { // we should use effects when typechecking for that return scan1_exp(env, prim->d.exp); } - if (prim->prim_type == ae_prim_array && prim->d.array->exp) + if (prim->prim_type == ae_prim_array) return scan1_exp(env, prim->d.array->exp); if (prim->prim_type == ae_prim_range) return scan1_range(env, prim->d.range); if (env->func && prim->prim_type == ae_prim_perform && env->scope->depth <= 2) diff --git a/src/parse/scan2.c b/src/parse/scan2.c index b0a2cbf7..5cf63d2e 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -103,7 +103,7 @@ ANN static bool scan2_range(const Env env, Range *range) { ANN static inline bool scan2_prim(const Env env, const Exp_Primary *prim) { if (prim->prim_type == ae_prim_hack || prim->prim_type == ae_prim_dict || prim->prim_type == ae_prim_interp) CHECK_B(scan2_exp(env, prim->d.exp)); - else if (prim->prim_type == ae_prim_array && prim->d.array->exp) + else if (prim->prim_type == ae_prim_array) return scan2_exp(env, prim->d.array->exp); else if (prim->prim_type == ae_prim_range) return scan2_range(env, prim->d.range); diff --git a/src/parse/spread.c b/src/parse/spread.c index f8640d97..4a569e03 100644 --- a/src/parse/spread.c +++ b/src/parse/spread.c @@ -5,7 +5,6 @@ #include "traverse.h" #include "template.h" #include "parse.h" -#include "gwion.h" #include "object.h" #include "instr.h" #include "operator.h" diff --git a/src/pass.c b/src/pass.c index 2cd453b1..25ffb45f 100644 --- a/src/pass.c +++ b/src/pass.c @@ -7,8 +7,9 @@ #include "gwion.h" #include "pass.h" #include "traverse.h" +#include "sema.h" -#define N_PASS 2 +#define N_PASS 3 #define N_SCANPASS 4 static bool typecheck_ast(const Env env, Ast *ast) { @@ -19,8 +20,8 @@ static bool typecheck_ast(const Env env, Ast *ast) { return !env->context->error; } -static const m_str default_passes_name[2] = {"check", "emit"}; -static const compilation_pass default_passes[2] = {typecheck_ast, emit_ast}; +static const m_str default_passes_name[3] = {"sema", "check", "emit"}; +static const compilation_pass default_passes[3] = {sema_pass, typecheck_ast, emit_ast}; ANN void pass_register(const Gwion gwion, const m_str name, const compilation_pass pass) { diff --git a/src/sema/sema.c b/src/sema/sema.c new file mode 100644 index 00000000..8deb9e04 --- /dev/null +++ b/src/sema/sema.c @@ -0,0 +1,591 @@ +#include "gwion_util.h" +#include "gwion_ast.h" +#include "gwion_env.h" +#include "loc.h" +#include "vm.h" +#include "gwion.h" +#include "sema.h" +#include "sema_private.h" +#include +#include + +#define POISON(a, b) \ + do { \ + a->error = true; \ + b->poison = true; \ + } while (0) + +#define POISON_OK(a, b, ok) \ + do { \ + POISON(a, b); \ + ok = false; \ + } while (0) + + +ANN static bool unique_expression(Sema *a, Exp *b, const char *ctx) { + const bool ok = sema_exp(a, b); + if(!b->next) return true && ok; + gwerr_basic("can't use multiple expressions", ctx, + NULL, a->filename, b->next->loc, 0); + return false; +} + +__attribute__((warn_unused_result)) +ANN static bool array_not_empty(Sema *a, Array_Sub b, + const char *ctx, const loc_t loc) { + if(b->exp) + return true; + gwerr_basic(_("must provide values/expressions for array [...]"), + ctx, NULL, a->filename, loc, 0); + return false; +} + +__attribute__((warn_unused_result)) +ANN static bool array_empty(Sema *a, Array_Sub b, + const char *ctx, const loc_t loc) { + if(!b->exp) + return true; + gwerr_basic(_("array must be empty []"), + ctx, NULL, a->filename, loc, 0); + return false; +} + +__attribute__((warn_unused_result)) +ANN static bool type_decl_array_not_empty(Sema *a, Type_Decl *b, const char *ctx) { + const bool ok = sema_type_decl(a, b); + if(b->array) return array_not_empty(a, b->array, ctx, b->tag.loc) && ok; + return ok; +} + +__attribute__((warn_unused_result)) +ANN static bool type_decl_array_empty(Sema *a, Type_Decl *b, const char *ctx) { + const bool ok = sema_type_decl(a, b); + if(b->array) return array_empty(a, b->array, ctx, b->tag.loc) && ok; + return ok; +} + +ANN static bool sema_array_sub(Sema *a, Array_Sub b) { + if(b->exp) return sema_exp(a, b->exp); + return true; +} + +ANN static bool sema_tmplarg(Sema *a, TmplArg *b) { + if (b->type == tmplarg_td) + return type_decl_array_empty(a, b->d.td, "in template argument"); + return sema_exp(a, b->d.exp); +} + +ANN static bool sema_tmplarg_list(Sema *a, TmplArg_List b) { + bool ok = true; + for(uint32_t i = 0; i < b->len; i++) { + TmplArg * c = mp_vector_at(b, TmplArg, i); + if(!sema_tmplarg(a, c)) + ok = false; + } + return ok; +} + +ANN static bool sema_tmpl(Sema *a, Tmpl *b) { + if(b->call) return sema_tmplarg_list(a, b->call); + return true; +} + +ANN static bool sema_range(Sema *a, Range *b) { + bool ok = true; + if(b->start && !unique_expression(a, b->start, "in range start")) + ok = false; + if(b->end && !unique_expression(a, b->end, "in range end")) + ok = false; + return ok; +} + +ANN static bool sema_type_decl(Sema *a, Type_Decl *b) { + bool ok = true; + if(b->array && !sema_array_sub(a, b->array)) + ok = false; + if(b->types && !sema_tmplarg_list(a, b->types)) + ok = false; + return ok; +} + +ANN static bool sema_prim_id(Sema *a NUSED, Symbol *b NUSED) { + return true; +} + +ANN static bool sema_prim_num(Sema *a NUSED, m_uint *b NUSED) { + return true; +} + +ANN static bool sema_prim_float(Sema *a NUSED, m_float *b NUSED) { + return true; +} + +ANN static bool sema_prim_str(Sema *a NUSED, m_str *b NUSED) { + return true; +} + +ANN static bool sema_prim_array(Sema *a, Array_Sub *b) { + bool ok = sema_array_sub(a, *b); + if(!array_not_empty(a, *b, + "in array litteral", prim_exp(b)->loc)) + POISON_OK(a, prim_exp(b), ok); + return ok; +} + +ANN static bool sema_prim_range(Sema *a, Range* *b) { + return sema_range(a, *b); +} + +ANN static bool sema_prim_dict(Sema *a, Exp* *b) { + return sema_exp(a, *b); +} + +ANN static bool sema_prim_hack(Sema *a, Exp* *b) { + return sema_exp(a, *b); +} + +ANN static bool sema_prim_interp(Sema *a, Exp* *b) { + return sema_exp(a, *b); +} + +ANN static bool sema_prim_char(Sema *a NUSED, m_str *b NUSED) { + return true; +} + +ANN static bool sema_prim_nil(Sema *a NUSED, bool *b NUSED) { + return true; +} + +ANN static bool sema_prim_perform(Sema *a NUSED, Symbol *b NUSED) { + return true; +} + +ANN static bool sema_prim_locale(Sema *a NUSED, Symbol *b NUSED) { + return true; +} + +DECL_PRIM_FUNC(sema, bool, Sema *) +ANN static bool sema_prim(Sema *a, Exp_Primary *b) { + return sema_prim_func[b->prim_type](a, &b->d); +} + + +ANN static bool sema_variable(Sema *a, Variable *b) { + if(b->td) return sema_type_decl(a, b->td); + return true; +} + +ANN static bool sema_exp_decl(Sema *a, Exp_Decl *b) { +// TODO: arguments? + bool ok = sema_variable(a, &b->var); + if(b->args && !sema_exp(a, b->args)) + ok = false; + return ok; +} + +ANN static bool sema_exp_binary(Sema *a, Exp_Binary *b) { + const bool ok = sema_exp(a, b->lhs); + return sema_exp(a, b->rhs) && ok; +} + +ANN static bool sema_exp_unary(Sema *a, Exp_Unary *b) { + const enum unary_type type = b->unary_type; + if(type == unary_exp) return sema_exp(a, b->exp); + if(type == unary_td) { + if(!type_decl_array_not_empty(a, b->ctor.td, "in `new` expression")) + POISON(a, exp_self(b)); + if(b->ctor.exp) return sema_exp(a, b->ctor.exp); + } else + return sema_stmt_list(a, b->code); + return !exp_self(b)->poison; +} + +ANN static bool sema_exp_cast(Sema *a, Exp_Cast *b) { + const bool ok = type_decl_array_empty(a, b->td, "in `cast` expression"); + return sema_exp(a, b->exp) && ok; +} + +ANN static bool sema_exp_post(Sema *a, Exp_Postfix *b) { + return sema_exp(a, b->exp); +} + +ANN static bool sema_exp_call(Sema *a, Exp_Call *b) { + bool ok = sema_exp(a, b->func); + if(b->args && !sema_exp(a, b->args)) + ok = false; + if(b->tmpl && !sema_tmpl(a, b->tmpl)) + ok = false; + return ok; +} + +ANN static bool sema_exp_array(Sema *a, Exp_Array *b) { + const bool ok = sema_exp(a, b->base); + return sema_array_sub(a, b->array) && ok; +} + +ANN static bool sema_exp_slice(Sema *a, Exp_Slice *b) { + const bool ok = sema_exp(a, b->base); + return sema_range(a, b->range) && ok; +} + +ANN static bool sema_exp_if(Sema *a, Exp_If *b) { + bool ok = unique_expression(a, b->cond, "in `if` expression condition"); + if(b->if_exp && !unique_expression(a, b->if_exp, "in `if` expression true branch")) + ok = false; + return unique_expression(a, b->else_exp, "in `in` expression false branch") && ok; +} + +ANN static bool sema_exp_dot(Sema *a, Exp_Dot *b) { + return sema_exp(a, b->base); +} + +ANN static bool sema_exp_lambda(Sema *a, Exp_Lambda *b) { + return sema_func_def(a, b->def); +} + +ANN static bool sema_exp_td(Sema *a, Type_Decl *b) { + return type_decl_array_empty(a, b, "in `type declaration` expression"); +} + +DECL_EXP_FUNC(sema, bool, Sema*) +ANN static bool sema_exp(Sema *a, Exp* b) { + bool ok = sema_exp_func[b->exp_type](a, &b->d); + if(b->next && !sema_exp(a, b ->next)) + ok = false; + return ok; +} + +ANN static bool sema_stmt_exp(Sema *a, Stmt_Exp b) { + if(b->val) return sema_exp(a, b->val); + return true; +} + +ANN static bool sema_stmt_while(Sema *a, Stmt_Flow b) { + const bool ok = sema_exp(a, b->cond); + return sema_stmt(a, b->body) && ok; +} + +ANN static bool sema_stmt_until(Sema *a, Stmt_Flow b) { + const bool ok = sema_exp(a, b->cond); + return sema_stmt(a, b->body) && ok; +} + +ANN static bool sema_stmt_for(Sema *a, Stmt_For b) { + bool ok = sema_stmt(a, b->c1); + if(b->c2 && !sema_stmt(a, b->c2)) + ok = false; + if(b->c3 && !sema_exp(a, b->c3)) + ok = false; + return sema_stmt(a, b->body) && ok; +} + +ANN static bool sema_stmt_each(Sema *a, Stmt_Each b) { + const bool ok = unique_expression(a, b->exp, "in foreach statement"); + return sema_stmt(a, b->body) && ok; +} + +// TODO: rename loop to repeat +ANN static bool sema_stmt_loop(Sema *a, Stmt_Loop b) { + const bool ok = unique_expression(a, b->cond, "in repeat statement"); + return sema_stmt(a, b->body) && ok; +} + +ANN static bool sema_stmt_if(Sema *a, Stmt_If b) { + bool ok = sema_exp(a, b->cond); + if(!sema_stmt(a, b->if_body)) + ok = false; + if(b->else_body && !sema_stmt(a, b->else_body)) + ok = false; + return ok; +} + +ANN static bool sema_stmt_code(Sema *a, Stmt_Code b) { + if(b->stmt_list) return sema_stmt_list(a, b->stmt_list); + return true; +} + +ANN static bool sema_stmt_break(Sema *a, Stmt_Index b) { + return sema_stmt_index(a, b); +} + +ANN static bool sema_stmt_continue(Sema *a, Stmt_Index b) { + return sema_stmt_index(a, b); +} + +ANN static bool sema_stmt_return(Sema *a, Stmt_Exp b) { + bool ok = true; + if(!a->func) { + gwerr_basic("'return' statement found outside function definition", NULL, NULL, a->filename, stmt_self(b)->loc, 0); + POISON(a, stmt_self(b)); + ok = false; + } + if(b->val && !unique_expression(a, b->val, "in `return` statement")) + ok = false; + return ok; +} + +ANN static bool sema_case_list(Sema *a, Stmt_List b) { + bool ok = true; + for(uint32_t i = 0; i < b->len; i++) { + Stmt* c = mp_vector_at(b, Stmt, i); + if(!sema_stmt_case(a, &c->d.stmt_match)) { + POISON_OK(a, c, ok); + } + } + return ok; +} + +ANN static bool sema_stmt_match(Sema *a, Stmt_Match b) { + bool ok = sema_exp(a, b->cond); + if(!sema_case_list(a, b->list)) + ok = false; + if(b->where && !sema_stmt(a, b->where)) + ok = false; + return ok; +} + +ANN static bool sema_stmt_case(Sema *a, Stmt_Match b) { + bool ok = sema_exp(a, b->cond); + if(!sema_stmt_list(a, b->list)) + ok = false; + if(b->when && !sema_exp(a, b->when)) + ok = false; + return ok; +} + +ANN static bool sema_stmt_index(Sema *a NUSED, Stmt_Index b NUSED) { + return true; +} + +ANN static bool sema_stmt_pp(Sema *a, Stmt_PP b) { + if(b->pp_type == ae_pp_include) + a->filename = b->data; + return true; +} + +ANN static bool sema_stmt_retry(Sema *a NUSED, Stmt_Exp b NUSED) { + if(a->handling) return true; + gwerr_basic("`retry outside of `handle` block", NULL, NULL, a->filename, stmt_self(b)->loc, 0); + return false; +} + +ANN static bool sema_handler(Sema *a, Handler *b, ID_List *tags) { + bool ok = true; + for(uint32_t i = 0; i < (*tags)->len; i++) { + Tag *tag = mp_vector_at(*tags, Tag, i); + if(!tag->sym && b->tag.sym) { + gwerr_basic("named handler after a catch-all one", NULL, NULL, a->filename, b->tag.loc, 0); + gwerr_secondary("catch-all used here", a->filename, b->tag.loc); + ok = false; + } else if(b->tag.sym == tag->sym) { + gwerr_basic("duplicate handler tag", NULL, NULL, a->filename, b->tag.loc, 0); + gwerr_secondary("handler used here", a->filename, b->tag.loc); + ok = false; + } + } + mp_vector_add(a->mp, tags, Tag, b->tag); + return sema_stmt(a, b->stmt) && ok; +} + +ANN static bool sema_handler_list(Sema *a, Handler_List b) { + bool ok = true; + MP_Vector *tags = new_mp_vector(a->mp, Tag, 0); + for(uint32_t i = 0; i < b->len; i++) { + Handler *handler = mp_vector_at(b, Handler, i); + if(!sema_handler(a, handler, &tags)) + ok = false; + } + free_mp_vector(a->mp, Symbol, tags); + return ok; +} + +ANN static bool sema_stmt_try(Sema *a, Stmt_Try b) { + const bool handling = a->handling; + a->handling = true; + bool ok = sema_stmt(a, b->stmt); + if(!sema_handler_list(a, b->handler)) + ok = false; + a->handling = handling; + return ok; +} + +ANN static bool sema_stmt_defer(Sema *a, Stmt_Defer b) { + return sema_stmt(a, b->stmt); +} + +ANN static bool sema_stmt_spread(Sema *a NUSED, Spread_Def b NUSED) { + return true; +} + +DECL_STMT_FUNC(sema, bool, Sema*) +ANN static bool sema_stmt(Sema *a, Stmt* b) { + return sema_stmt_func[b->stmt_type](a, &b->d); +} + +ANN static bool sema_arg(Sema *a, Arg *b, const bool no_default) { + bool ok = sema_variable(a, &b->var); + // NOTE: we need to check for td in case of lambda + // maybe lambdas should have a td with 'auto'? + if(b->var.td && b->var.td->array && + !array_empty(a, b->var.td->array, + "in argument", b->var.td->tag.loc)) + ok = false; + if (b->exp) { + if(no_default) { + gwerr_basic("'default' argument not allowed", NULL, NULL, a->filename, b->var.vd.tag.loc, 0); + ok = false; + } + if(!unique_expression(a, b->exp, "in argument list")) + ok = false; + } + return ok; +} + +ANN static bool sema_arg_list(Sema *a, Arg_List b, + bool *has_default, const bool arg_needs_sym, const bool no_default) { + bool ok = true; + for(uint32_t i = 0; i < b->len; i++) { + Arg *c = mp_vector_at(b, Arg, i); + if(!c->var.vd.tag.sym && arg_needs_sym) { + gwerr_basic("argument needs name", NULL, NULL, a->filename, c->var.vd.tag.loc, 0); + ok = false; + } + if(!sema_arg(a, c, no_default)) + ok = false; + if(c->exp) *has_default = true; + else if(*has_default) { + gwerr_basic("missing default argument", NULL, NULL, a->filename, c->var.vd.tag.loc, 0); + ok = false; + } + } + return ok; +} + +ANN static bool sema_stmt_list(Sema *a, Stmt_List b) { + bool ok = true; + for(uint32_t i = 0; i < b->len; i++) { + Stmt* c = mp_vector_at(b, Stmt, i); + if(!sema_stmt(a, c)) + POISON_OK(a, c, ok); + } + return ok; +} + +ANN static bool sema_func_base(Sema *a, Func_Base *b, const bool arg_need_sym) { + bool ok = true; + if(b->td && !type_decl_array_empty(a, b->td, "in function return type")) + ok = false; + const bool no_default = GET_FLAG(b, abstract) || fbflag(b, fbflag_op); + bool has_default = false; + if(b->args && !sema_arg_list(a, b->args, &has_default, arg_need_sym, no_default)) + ok = false; + if(has_default) + set_fbflag(b, fbflag_default); + if(b->tmpl && !sema_tmpl(a, b->tmpl)) + ok = false; + return ok; +} + +ANN static bool sema_func_def(Sema *a, Func_Def b) { + bool ok = sema_func_base(a, b->base, !GET_FLAG(b->base, abstract)); + if(b->d.code) { + const bool func = a->func; + a->func = true; + (void)sema_stmt_list(a, b->d.code); // ignore code in return value + a->func = func; + } + return ok; +} + +ANN static bool sema_class_def(Sema *a, Class_Def b) { + bool ok = sema_type_def( a, &b->base); + // TODO: what about typedeffing an array type? + if(b->base.ext && b->base.ext->array && + !array_not_empty(a, b->base.ext->array, + "in class extends", b->base.ext->tag.loc)) + ok = false; + if(b->body) sema_ast(a, b->body); // ignore code in return value + return ok; +} + +ANN static bool sema_trait_def(Sema *a, Trait_Def b) { + if(b->body) return sema_ast(a, b->body); + return true; +} + +ANN static bool sema_enumvalue(Sema *a NUSED, EnumValue *b NUSED) { + return true; + // gwint, set +} + +ANN static bool sema_enum_list(Sema *a, EnumValue_List b) { + bool ok = true; + for(uint32_t i = 0; i < b->len; i++) { + EnumValue *c = mp_vector_at(b, EnumValue, i); + if(!sema_enumvalue(a, c)) + ok = false; + } + return ok; +} + +ANN static bool sema_enum_def(Sema *a, Enum_Def b) { + return sema_enum_list(a, b->list); +} + +// TODO: rename l +ANN static bool sema_union_def(Sema *a, Union_Def b) { + bool ok = true; + for(uint32_t i = 0; i < b->l->len; i++) { + Variable *c = mp_vector_at(b->l, Variable, i); + sema_variable(a, c); + if(!type_decl_array_empty(a, c->td, "in union member")) + ok = false; + } + if(b->tmpl && !sema_tmpl(a, b->tmpl)) + ok = false; + return ok; +} + +ANN static bool sema_fptr_def(Sema *a, Fptr_Def b) { + return sema_func_base(a, b->base, false); +} + +ANN static bool sema_type_def(Sema *a, Type_Def b) { + bool ok = true; + if(b->ext && !sema_type_decl(a, b->ext)) + ok = false; + if(b->tmpl && !sema_tmpl(a, b->tmpl)) + ok = false; + if(b->when && !unique_expression(a, b->when, "in type definition")) + ok = false; + return ok; +} + +ANN static bool sema_extend_def(Sema *a, Extend_Def b) { + return type_decl_array_empty(a, b->td, "in extends definition"); +} + +ANN static bool sema_prim_def(Sema *a NUSED, Prim_Def b NUSED) { + return true; +} + +DECL_SECTION_FUNC(sema, bool, Sema*) +ANN static bool sema_section(Sema *a, Section *b) { + return sema_section_func[b->section_type](a, *(void**)&b->d); +} + +ANN static bool sema_ast(Sema *a, Ast b) { + bool ok = true; + for(uint32_t i = 0; i < b->len; i++) { + Section *c = mp_vector_at(b, Section, i); + if(!sema_section(a, c)) + POISON_OK(a, c, ok); + } + return ok; +} + +ANN bool sema_pass(Env a, Ast *b) { + Sema sema = { .filename = a->name, .mp = a->gwion->mp }; + /*return*/ sema_ast(&sema, *b); + return !sema.error; +} diff --git a/tests/error/func_arg_array_empty.gw b/tests/error/func_arg_array_empty.gw index 968368f1..15c982f9 100644 --- a/tests/error/func_arg_array_empty.gw +++ b/tests/error/func_arg_array_empty.gw @@ -1,2 +1,2 @@ -#! [contains] must be defined with empty +#! [contains] array must be empty fun int[] my_func(int[2] i){} diff --git a/tests/error/func_ret_array_empty.gw b/tests/error/func_ret_array_empty.gw index 76c9a488..b7df3449 100644 --- a/tests/error/func_ret_array_empty.gw +++ b/tests/error/func_ret_array_empty.gw @@ -1,2 +1,2 @@ -#! [contains] must be defined with empty -fun int[1] my_func(int i[]){} +#! [contains] array must be empty +fun int[1] my_func(int[] i){} diff --git a/tests/error/new_empty_array.gw b/tests/error/new_empty_array.gw index 80000dba..502203d3 100644 --- a/tests/error/new_empty_array.gw +++ b/tests/error/new_empty_array.gw @@ -1,2 +1,2 @@ -#! [contains] instantiate with empty +#! [contains] must provide values/expressions for array new Object[]; diff --git a/tests/error/ptr_arg_array.gw b/tests/error/ptr_arg_array.gw index 083ac6d5..95d7ff69 100644 --- a/tests/error/ptr_arg_array.gw +++ b/tests/error/ptr_arg_array.gw @@ -1,2 +1,2 @@ -#! [contains] must be defined with empty +#! [contains] array must be empty funptr void my_func (int[4] i); diff --git a/tests/error/union_array_empty.gw b/tests/error/union_array_empty.gw index c9f63041..cd65235b 100644 --- a/tests/error/union_array_empty.gw +++ b/tests/error/union_array_empty.gw @@ -1,4 +1,4 @@ -#! [contains] must be defined with empty +#! [contains] array must be empty union U { int i; int[4] j; -- 2.43.0