]> Nishi Git Mirror - gwion.git/commitdiff
:art: remove unnecessary
authorfennecdjay <fennecdjay@gmail.com>
Tue, 5 Mar 2024 12:52:16 +0000 (13:52 +0100)
committerfennecdjay <fennecdjay@gmail.com>
Tue, 5 Mar 2024 12:52:16 +0000 (13:52 +0100)
14 files changed:
include/sema.h [new file with mode: 0644]
include/sema_private.h [new file with mode: 0644]
src/parse/check.c
src/parse/func_resolve_tmpl.c
src/parse/scan1.c
src/parse/scan2.c
src/parse/spread.c
src/pass.c
src/sema/sema.c [new file with mode: 0644]
tests/error/func_arg_array_empty.gw
tests/error/func_ret_array_empty.gw
tests/error/new_empty_array.gw
tests/error/ptr_arg_array.gw
tests/error/union_array_empty.gw

diff --git a/include/sema.h b/include/sema.h
new file mode 100644 (file)
index 0000000..8b8a376
--- /dev/null
@@ -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 (file)
index 0000000..bff82ab
--- /dev/null
@@ -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);
index 3c9e9d0b408bf90531f85add01a2290b3b9a52a3..56b176cd9b8ba56a45e1350c8a4d503894fa6762 100644 (file)
@@ -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);
index ce8bacdcd2eae1a03ca40afe4db6554b25b16698..1d46d318b5f394f11d653004c1d9496430220109 100644 (file)
@@ -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);
index a6843143b2f75cb2a5d4893e8432406bfcd2fe85..93cf66a1ab83408ca2ad3e2289be85e61e6933f4 100644 (file)
@@ -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)
index b0a2cbf74565dc6c15972eccfa02effcfe126bd3..5cf63d2e94c2365094a737ff952bfe0c8e30c401 100644 (file)
@@ -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);
index f8640d97dfa95da1d26b12f9f93c5cb90e734a92..4a569e034b84742c028f263f59431550ba6a1e0a 100644 (file)
@@ -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"
index 2cd453b11f0e625234f07d77f0e72c0230a1dc28..25ffb45f1f0ded9f9c59b9f8d34be301457c9975 100644 (file)
@@ -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 (file)
index 0000000..8deb9e0
--- /dev/null
@@ -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 <ctype.h>
+#include <stdlib.h>
+
+#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;
+}
index 968368f1ff68db3efd671a6d3d32ff3fc8d7666a..15c982f98b032b40e434e0300b4555c528e1c326 100644 (file)
@@ -1,2 +1,2 @@
-#! [contains] must be defined with empty
+#! [contains] array must be empty
 fun int[] my_func(int[2] i){}
index 76c9a488024c9eeca52e46535ad7ca87e204bb52..b7df34497863f656597b84be65eaf3934a0fa0b2 100644 (file)
@@ -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){}
index 80000dba5d2806deff3f5d77e6d443a215a94c54..502203d32c827cd84399f328175fb0f212420eb8 100644 (file)
@@ -1,2 +1,2 @@
-#! [contains] instantiate with empty
+#! [contains] must provide values/expressions for array 
 new Object[];
index 083ac6d5c914cbfa2926f6771c0b58ca9b3b381e..95d7ff69bba1a8c61a4c21c0921b85722be1e38f 100644 (file)
@@ -1,2 +1,2 @@
-#! [contains] must be defined with empty
+#! [contains] array must be empty
 funptr void my_func (int[4] i);
index c9f63041d11d1a76fa58d9a7758da247d16d3347..cd65235bd63d4aa4a33fe35e922c38d5d8ed84ca 100644 (file)
@@ -1,4 +1,4 @@
-#! [contains] must be defined with empty
+#! [contains] array must be empty
 union U {
   int i;
   int[4] j;