:art: update
authorfennecdjay <fennecdjay@gmail.com>
Thu, 14 Mar 2024 07:21:09 +0000 (08:21 +0100)
committerfennecdjay <fennecdjay@gmail.com>
Thu, 14 Mar 2024 07:21:09 +0000 (08:21 +0100)
include/sema_private.h
src/sema/sema.c
tests/try-handle/duplicate_handler.gw [new file with mode: 0644]
tests/try-handle/retry_outside_handle.gw [new file with mode: 0644]

index d6eee9f5aaa436ff1b2d9282b64a2bc609eec13c..a98a6ea448ba53e6aaf1d810ba6ec5fd678e233d 100644 (file)
@@ -10,6 +10,7 @@ typedef struct {
   bool scope;
   bool handling;
   bool in_variadic;
+  bool in_defer;
 } Sema;
 
 #ifdef __SEMA_IMPLEMENTATION__
index 811e8844c21df83421236c75ab7417e59a683d60..bef5c35eb8fe2433bc03149be1a70e7bdb5252e7 100644 (file)
@@ -331,6 +331,11 @@ ANN static bool sema_stmt_return(Sema *a, Stmt_Exp b) {
     POISON(a, stmt_self(b));
     ok = false;
   }
+  if(a->in_defer) {
+    gwerr_basic("'return' statement in defered action", 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;
@@ -377,7 +382,7 @@ ANN static bool sema_stmt_pp(Sema *a, Stmt_PP b) {
 
 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);
+  gwerr_basic("`retry` outside of `handle` block", NULL, NULL, a->filename, stmt_self(b)->loc, 0);
   return false;
 }
 
@@ -422,7 +427,10 @@ ANN static bool sema_stmt_try(Sema *a, Stmt_Try b) {
 }
 
 ANN static bool sema_stmt_defer(Sema *a, Stmt_Defer b) {
+  const bool in_defer = a ->in_defer;
+  a->in_defer = true;
   return sema_stmt(a, b->stmt, false);
+  a ->in_defer = in_defer;
 }
 
 ANN2(1, 2) static bool sema_spread(Sema *a, const Spread_Def spread, MP_Vector **acc) {
@@ -662,20 +670,23 @@ ANN static bool sema_func_def(Sema *a, Func_Def b) {
   const Tmpl *tmpl = b->base->tmpl;
   const bool is_base = tmpl && tmpl_base(tmpl);
   const bool is_spread = tmpl && is_spread_tmpl(tmpl);
-  const bool in_variadic = a->in_variadic;
   const bool is_fill = !is_base && is_spread;
+  const bool in_variadic = a->in_variadic;
+  const bool in_defer = a->in_defer;
   a->in_variadic = in_variadic || is_spread;
+  a->in_defer = in_defer;
   if(is_fill && !fill(a, tmpl)) 
     return false;
   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;
+    a->func = true; // we can move this out
     (void)sema_stmt_list(a, &b->d.code); // ignore code in return value
     a->func = func;
   }
   if(is_fill) unfill(a, tmpl);
   a->in_variadic = in_variadic;
+  a->in_defer = in_defer;
   return ok;
 }
 
diff --git a/tests/try-handle/duplicate_handler.gw b/tests/try-handle/duplicate_handler.gw
new file mode 100644 (file)
index 0000000..ee3ab2e
--- /dev/null
@@ -0,0 +1,6 @@
+#! [contains] duplicate handler tag
+try {
+
+} handle Foo {
+} handle Foo {}
+
diff --git a/tests/try-handle/retry_outside_handle.gw b/tests/try-handle/retry_outside_handle.gw
new file mode 100644 (file)
index 0000000..d23fc07
--- /dev/null
@@ -0,0 +1,3 @@
+
+#! [contains] `retry` outside of `handle` block
+retry;