about summary refs log tree commit diff
path: root/executor.c
diff options
context:
space:
mode:
authorNakidai <nakidai@disroot.org>2025-03-25 14:35:06 +0300
committerNakidai <nakidai@disroot.org>2025-03-25 14:35:06 +0300
commit2d5f634d0d28a0762835afa01dd1e9eb212e4803 (patch)
treee3e141464181f88dff69c32e1cb48b6f9e258f37 /executor.c
parent98a243bf9ab1a3e8bd2de56d7b16302f303f323a (diff)
download3cl-2d5f634d0d28a0762835afa01dd1e9eb212e4803.tar.gz
3cl-2d5f634d0d28a0762835afa01dd1e9eb212e4803.zip
Implement all instructions
Something doesn't work, though
Diffstat (limited to 'executor.c')
-rw-r--r--executor.c96
1 files changed, 62 insertions, 34 deletions
diff --git a/executor.c b/executor.c
index 0458f1c..e39df2c 100644
--- a/executor.c
+++ b/executor.c
@@ -41,19 +41,25 @@ static short *get_variable(char name, struct cccl_Variables *scope)
     return NULL;
 }
 
-enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope)
+enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope, size_t depth)
 {
+    if (verbose)
+        if (code->value)
+            fprintf(stderr, "Executing %s with %d [%c], %lu nodes, depth %lu\n", strnode(code->type), code->value, code->value, code->in_length, depth);
+        else
+            fprintf(stderr, "Executing %s, %lu nodes, depth %lu\n", strnode(code->type), code->in_length, depth);
     switch (code->type)
     {
     case cccl_Node_CODE:
     {
-        int res;
+        enum cccl_ExecutorStatus res;
         for (size_t i = 0; i < code->in_length; ++i)
-            if ((res = cccl_execute(code->in[i], scope)) != 0)
-                goto code_end;
-code_end:
-        if (res == cccl_Executor_ERROR)
-            return res;
+            switch ((res = cccl_execute(code->in[i], scope, depth + 1)))
+            {
+            case cccl_Executor_ERROR: return res;
+            case cccl_Executor_CONTINUE: return cccl_Executor_ERROR;
+            case cccl_Executor_END: goto end;
+            }
     } break;
     case cccl_Node_PUSHZERO:
     {
@@ -197,56 +203,78 @@ code_end:
 
         size_t i = geti(code->value);
         struct cccl_Variables localscope = {0};
-        int res;
+        enum cccl_ExecutorStatus res;
         for (size_t j = 0; j < functions[i].length; ++j)
-            if ((res = cccl_execute(functions[i].body[j], &localscope)) != 0)
-                goto call_end;
-call_end:
-        if (res == cccl_Executor_ERROR)
-            return res;
+            switch ((res = cccl_execute(functions[i].body[j], &localscope, depth + 1)))
+            {
+            case cccl_Executor_ERROR: return res;
+            case cccl_Executor_CONTINUE: return cccl_Executor_ERROR;
+            case cccl_Executor_END: goto end;
+            }
     } break;
     case cccl_Node_INFINITE:
     {
-        int res;
+        short *p;
         if (code->value == '_')
-            for (;;)
-                for (size_t i = 0; i < code->in_length; ++i)
-                    if ((res = cccl_execute(code->in[i], scope)) != 0)
-                        goto infinite_end;
-
-        short *p = get_variable(code->value, scope);
-        if (!p)
-            errx(1, "Cannot loop using non-existent variable %c", code->value);
+        {
+            short n = 1;
+            p = &n;
+        } else
+        {
+            short *p = get_variable(code->value, scope);
+            if (!p)
+                errx(1, "Cannot loop over non-existent variable %c", code->value);
+        }
 
+        enum cccl_ExecutorStatus res;
         while (*p > 0)
             for (size_t i = 0; i < code->in_length; ++i)
-                if ((res = cccl_execute(code->in[i], scope)) != 0)
-                    goto infinite_end;
-infinite_end:
-        if (res == cccl_Executor_ERROR)
-            return res;
+                switch ((res = cccl_execute(code->in[i], scope, depth + 1)))
+                {
+                case cccl_Executor_ERROR: return res;
+                case cccl_Executor_CONTINUE: break;
+                case cccl_Executor_END: goto end;
+                }
     } break;
     case cccl_Node_REPEAT:
     {
         short *p = get_variable(code->value, scope);
         if (!p)
-            errx(1, "Cannot loop using non-existent variable %c", code->value);
+            errx(1, "Cannot loop over non-existent variable %c", code->value);
         else if (*p < 0)
             errx(1, "Cannot iterate %c=%d times", code->value, *p);
 
-        int res;
+        enum cccl_ExecutorStatus res;
         for (size_t i = 0; i < *p; ++i)
             for (size_t j = 0; j < code->in_length; ++j)
-                if ((res = cccl_execute(code->in[j], scope)) != 0)
-                    goto repeat_end;
-repeat_end:
-        if (res == cccl_Executor_ERROR)
-            return res;
+                switch ((res = cccl_execute(code->in[j], scope, depth + 1)))
+                {
+                case cccl_Executor_ERROR: return res;
+                case cccl_Executor_CONTINUE: break;
+                case cccl_Executor_END: goto end;
+                }
     };
     case cccl_Node_CONDITIONAL:
     {
+        assert(stack.length >= 1);
+        short *p = get_variable(code->value, scope);
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '?');
+        if (!p)
+            errx(1, "Cannot check non-existent variable %c", code->value);
+
+        enum cccl_ExecutorStatus res;
+        if (stack.buffer[stack.length - 1] == *p)
+            for (size_t i = 0; i < code->in_length; ++i)
+                switch ((res = cccl_execute(code->in[i], scope, depth + 1)))
+                {
+                case cccl_Executor_ERROR: return res;
+                case cccl_Executor_CONTINUE: return res;
+                case cccl_Executor_END: goto end;
+                }
     } break;
     }
 
+end:
     return 0;
 }