flip calling convention: evaluate right to left
authorcassowarii <2374677+cassowarii@users.noreply.github.com>
Fri, 10 Jul 2026 15:59:36 +0000 (08:59 -0700)
committercassowarii <2374677+cassowarii@users.noreply.github.com>
Fri, 10 Jul 2026 15:59:36 +0000 (08:59 -0700)
src/compile/ir.c
src/lib/lib.c
src/lib/method/float.c
src/lib/method/integer.c
src/lib/method/list.c
src/lib/method/string.c
src/parse/parser.c
src/vm/exec.c

index 4503cd3..3e214be 100644 (file)
@@ -686,7 +686,7 @@ static void compile_ast_stmt(hIrChunk ck, sbAst node, flag implicit_return) {
         E1 = NIL_EXPR;
       } else {
         /* TODO handle multival here */
-        E1 = compile_ast_expr(ck, node->seq.left->seq.left, FALSE);
+        E1 = compile_ast_expr(ck, node->seq.left->seq.right, FALSE);
       }
       put_return(ck, E1);
       break;
@@ -732,11 +732,11 @@ static void compile_ast_stmt(hIrChunk ck, sbAst node, flag implicit_return) {
       N1 = node->seq.left;  /* things to bind to */
       N2 = node->seq.right; /* values to assign */
       while (N1 != NO_NODE && N2 != NO_NODE) {
-        V1 = compile_ast_var(ck, N1->seq.left);
-        E1 = compile_ast_expr(ck, N2->seq.left, TRUE);
+        V1 = compile_ast_var(ck, N1->seq.right);
+        E1 = compile_ast_expr(ck, N2->seq.right, TRUE);
         put_assign(ck, V1, E1);
-        N1 = N1->seq.right;
-        N2 = N2->seq.right;
+        N1 = N1->seq.left;
+        N2 = N2->seq.left;
       }
 
       if (N1 != NO_NODE) {
@@ -872,9 +872,11 @@ static sbIrExpr *compile_ast_list(hIrChunk ck, sbAst node) {
   sbIrExpr *list = IR_EMPTY_LIST;
   sbIrExpr **place_here = &list;
   while (considering != NO_NODE) {
-    *place_here = expr_list(ck, compile_ast_expr(ck, considering->seq.left, TRUE));
+    /* we compile the list right-to-left so that it ends up being on the stack with
+     * the earliest elements closest to the top */
+    *place_here = expr_list(ck, compile_ast_expr(ck, considering->seq.right, TRUE));
     place_here = &(*place_here)->list.next;
-    considering = considering->seq.right;
+    considering = considering->seq.left;
   }
   return list;
 }
@@ -937,9 +939,9 @@ static sbIrBindList *compile_ast_bind_list(hIrChunk ck, sbAst node, flag create_
   usize pre_splat_count = 0;
   while (considering != NO_NODE) {
     /* bind list needs to be reversed, because we're going to bind to some stack
-     * that was built bottom-to-top. so we build it in the reverse order from a
+     * that was built top-to-bottom. so we build it in the reverse order from a
      * value list. */
-    sbAst elem = considering->seq.left;
+    sbAst elem = considering->seq.right;
     if (elem->type == AST_NODE_OP && elem->op.type == AST_OP_SPLAT) {
       if (!was_splat) {
         was_splat = TRUE;
@@ -954,11 +956,11 @@ static sbIrBindList *compile_ast_bind_list(hIrChunk ck, sbAst node, flag create_
       pre_splat_count ++;
     }
     sbIrBindList *new_list = new_bind_list(
-        ck, compile_ast_binding(ck, considering->seq.left, create_vars, type), pre_splat_count
+        ck, compile_ast_binding(ck, elem, create_vars, type), pre_splat_count
     );
     new_list->next = list;
     list = new_list;
-    considering = considering->seq.right;
+    considering = considering->seq.left;
   }
 
   return list;
index edd339f..9c919ec 100644 (file)
@@ -30,14 +30,14 @@ void sbLib_resolve_method(hVm vm) {
   if (argc->type != IT_INTEGER) {
     CHECK("argc of send should be integer!");
   }
-  /* subtract 1 because the method name is itself a param */
-  usize num_params = argc->integer - 1;
-  hV *method_name_val = sbVm_peek(vm, num_params);
+  hV *method_name_val = sbVm_pop(vm);
   if (method_name_val->type != IT_SYMBOL) {
     /* TODO this may become not true */
     PANIC("method name must be symbol!");
   }
 
+  /* subtract 1 because the method name is itself a param */
+  usize num_params = argc->integer - 1;
   hLibTable table_to_use = NULL;
   switch(target->type) {
     case IT_LIST:
index 5372808..9accacb 100644 (file)
@@ -8,7 +8,6 @@
 sbLibTable g_float_methods;
 
 static void to_string(hVm vm, hV *target, usize num_params) {
-  sbVm_pop(vm); /* remove method name */
   char stackbuf[1024];
   char *buf = stackbuf;
   usize length = snprintf(buf, 1024, "%g", target->float_val);
index f9598e8..bb9d9e1 100644 (file)
@@ -9,7 +9,6 @@
 sbLibTable g_integer_methods;
 
 static void to_string(hVm vm, hV *target, usize num_params) {
-  sbVm_pop(vm); /* remove method name */
   char stackbuf[1024];
   char *buf = stackbuf;
   usize length = sbInteger_snprint(buf, 1024, target->integer);
index 0fbc761..839a87a 100644 (file)
@@ -17,7 +17,6 @@ static void length(hVm vm, hV *list, usize num_params) {
   if (num_params != 0) {
     PANIC("list#length takes no arguments!");
   }
-  sbVm_pop(vm); /* remove method name */
   usize length;
   sbList_get_value(list->list, &length);
   sbVm_push_immediate(vm, &HVINT(length));
@@ -28,7 +27,6 @@ static void push(hVm vm, hV *list, usize num_params) {
     PANIC("list#push expects 1 argument!");
   }
   hV *to_append = sbVm_pop(vm);
-  sbVm_pop(vm); /* remove method name */
   sbList_append(list->list, to_append);
   sbVm_push_immediate(vm, &HVNIL);
 }
@@ -38,7 +36,6 @@ static void reverse(hVm vm, hV *list, usize num_params) {
     PANIC("list#reverse takes no arguments!");
   }
   /* TODO maybe mutate in place if no other refs */
-  sbVm_pop(vm); /* remove method name */
   usize length;
   hV *elems = sbList_get_value(list->list, &length);
   hList new_list = sbList_new(length);
@@ -64,7 +61,6 @@ static void join(hVm vm, hV *list, usize num_params) {
     join_with = TRUE;
     delimiter = delimiter_v->string;
   }
-  sbVm_pop(vm); /* remove method name */
   usize length;
   hV *elems = sbList_get_value(list->list, &length);
   hString joined = sbString_new("", 0);
@@ -141,7 +137,6 @@ sbCFuncStatus list_each_cfunc(hVm vm, flag init) {
     sbVm_request_var_space(vm, 3);
     hV *iterating_list = sbVm_pop(vm);
     hV *loop_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
     hV index = HVINT(0);
     vm->fp->locals[0] = *iterating_list;
     vm->fp->locals[1] = index;
@@ -172,7 +167,6 @@ sbCFuncStatus list_map_cfunc(hVm vm, flag init) {
     sbVm_request_var_space(vm, 4);
     hV *iterating_list = sbVm_pop(vm);
     hV *map_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
     usize length;
     sbList_get_value(iterating_list->list, &length);
     hV index = HVINT(0);
@@ -209,7 +203,6 @@ sbCFuncStatus list_filter_cfunc(hVm vm, flag init) {
     sbVm_request_var_space(vm, 4);
     hV *iterating_list = sbVm_pop(vm);
     hV *filter_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
     usize length;
     sbList_get_value(iterating_list->list, &length);
     hV index = HVINT(0);
@@ -251,7 +244,6 @@ sbCFuncStatus list_any_cfunc(hVm vm, flag init) {
     sbVm_request_var_space(vm, 3);
     hV *iterating_list = sbVm_pop(vm);
     hV *pred_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
     hV index = HVINT(0);
 
     vm->fp->locals[0] = *iterating_list;
@@ -290,7 +282,6 @@ sbCFuncStatus list_all_cfunc(hVm vm, flag init) {
     sbVm_request_var_space(vm, 3);
     hV *iterating_list = sbVm_pop(vm);
     hV *pred_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
     hV index = HVINT(0);
 
     vm->fp->locals[0] = *iterating_list;
index 5fc1125..1e9e966 100644 (file)
@@ -14,7 +14,6 @@ void list_all_cfunc(hVm vm, flag init);
 sbLibTable g_string_methods;
 
 static void split(hVm vm, hV *target, usize num_params) {
-  sbVm_pop(vm); /* remove method name */
   usize length;
   char scratch[8];
   const char *buf = sbString_get_value(target->string, scratch, &length);
@@ -29,7 +28,6 @@ static void to_string(hVm vm, hV *target, usize num_params) {
   if (num_params != 0) {
     PANIC("to_string takes no parameters");
   }
-  sbVm_pop(vm); /* remove method name */
 
   /* to_string for a string just returns itself */
   sbVm_push_immediate(vm, target);
index 082bdac..b255e5a 100644 (file)
@@ -383,12 +383,10 @@ static sbAst id_sym_node(hParser pr, sbLexToken token) {
 static sbAst parse_expr(hParser pr, u8 min_precedence);
 static sbAst parse_comma_exprs(hParser pr, sbAst after) {
   sbAst result = NO_NODE;
-  sbAst *put_here = &result;
   sbAst expr;
 
   if (after) {
-    *put_here = seq_node(pr, AST_NODE_MULTIVAL, after, NO_NODE);
-    put_here = &(*put_here)->seq.right;
+    result = after;
   }
 
   do {
@@ -408,8 +406,11 @@ static sbAst parse_comma_exprs(hParser pr, sbAst after) {
       if (expr == NO_NODE) break;
     }
 
-    *put_here = seq_node(pr, AST_NODE_MULTIVAL, expr, NO_NODE);
-    put_here = &(*put_here)->seq.right;
+    /* we build up our linked list in 'reverse' order, with later elements
+     * closer to the root of the tree, because lists are passed on the stack
+     * with the first elements at the top, which means we want to evaluate
+     * the last ones first */
+    result = seq_node(pr, AST_NODE_MULTIVAL, result, expr);
   } while (expect(pr, T_COMMA));
 
   return result;
@@ -611,9 +612,9 @@ static sbAst parse_expr(hParser pr, u8 min_precedence) {
         method_name = parse_name_as_sym(pr);
       }
       if (method_name == NO_NODE) return syntax_error(pr);
-      sbAst params = NO_NODE;
+      rhs = seq_node(pr, AST_NODE_MULTIVAL, NO_NODE, method_name);
       if (expect(pr, T_LPAREN)) {
-        params = parse_comma_exprs(pr, NULL);
+        rhs = parse_comma_exprs(pr, rhs);
         if (!expect(pr, T_RPAREN)) return syntax_error(pr);
       }
       ast_type = AST_NODE_METHODCALL;
@@ -621,7 +622,6 @@ static sbAst parse_expr(hParser pr, u8 min_precedence) {
         /* (whatever)->x is rewritten as (*whatever).x */
         lhs = unop_node(pr, AST_OP_DEREF, lhs);
       }
-      rhs = seq_node(pr, AST_NODE_MULTIVAL, method_name, params);
     } else if (op.type == T_BACKSQUIGARROW) {
       /* a <~ b, c, d can have multiple comma things on the right side */
       if (!expect(pr, T_LPAREN)) return syntax_error(pr);
@@ -823,7 +823,7 @@ static sbAst parse_stmt(hParser pr) {
         if (expr->type != AST_NODE_MULTIVAL) {
           /* if we have an = with one thing on the left side,
            * wrap it in a multival anyway for consistency */
-          expr = seq_node(pr, AST_NODE_MULTIVAL, expr, NO_NODE);
+          expr = seq_node(pr, AST_NODE_MULTIVAL, NO_NODE, expr);
         }
         expr = seq_node(pr, AST_NODE_ASSIGN, expr, assigned_values);
       }
index f6ec602..1e8ecb2 100644 (file)
@@ -644,16 +644,14 @@ void execute_instruction(hVm vm) {
         CHECK("internal violation: LIST_GATHER should receive an integer on top of stack");
       }
       param = v->integer;
-      count = param;
+      count = 0;
       res = sbV_empty_list(param);
-      while (count > 0) {
-        /* list gets built from bottom up, because first thing pushed is lower
-         * on the stack */
-        w = peek_stack(vm, count - 1);
+      while (count < param) {
+        /* list gets built from top of stack down */
+        w = pop_stack(vm);
         sbV_append(&res, w);
-        count --;
+        count ++;
       }
-      npop_stack(vm, param);
       push_stack_immediate(vm, &res);
       break;
     case BC_HASH_GATHER: