fix list-spill, also make pipe a bit more elegant
authorcassowarii <cassowary@cassowary.me>
Sat, 11 Jul 2026 00:19:53 +0000 (17:19 -0700)
committercassowarii <cassowary@cassowary.me>
Sat, 11 Jul 2026 00:19:53 +0000 (17:19 -0700)
sample/project_euler/pe06.sa
src/compile/ir.c
src/parse/parser.c
src/vm/exec.c

index d003cb5..3587fe3 100644 (file)
@@ -10,12 +10,16 @@ def square num {
   num * num
 }
 
+def map f {
+  => l { l.map(f) }
+}
+
 def sum_squares list {
-  list.map(square) | sum
+  list | (square | map) | sum
 }
 
 def square_sum list {
-  sum list | square
+  list | sum | square
 }
 
-list::iota 1, 101 | (square_sum _) - (sum_squares _) | println
+...[1, 101] | list::iota | (square_sum _) - (sum_squares _) | println
index ec21e3b..6ee0b51 100644 (file)
@@ -1032,15 +1032,25 @@ static sbIrExpr *compile_ast_expr(hIrChunk ck, sbAst node, flag list_context) {
     } else if (node->op.type == AST_OP_PIPE) {
       /* assign LHS to our temporary secret pipe variable,
        * then use RHS as our value */
-      sbIrExpr *left = compile_ast_expr(ck, node->op.left, FALSE);
-      put_assign(ck, pipe_var(ck), left);
-      sbIrExpr *right = compile_ast_expr(ck, node->op.right, FALSE);
-      if (!node->op.right->has_us) {
+      if (node->op.right->has_us) {
+        /* TODO: I realized this doesn't really make sense if we nest | within ().
+         * like, a | (b | c _) _ won't work properly. so really we need a whole
+         * stack of these temporary variables potentially... maybe we need to save
+         * the current pipe var here and restore it again after? also, whither
+         * something like a(b | c, d | e)? oh god... */
+        sbIrExpr *left = compile_ast_expr(ck, node->op.left, FALSE);
+        put_assign(ck, pipe_var(ck), left);
+        return compile_ast_expr(ck, node->op.right, FALSE);
+      } else {
         /* if there is no _ to the right of the "|", assume it is a function
-         * call that we are passing the left side to as a singular argument */
-        right = expr_call(ck, right, expr_list(ck, expr_var(ck, pipe_var(ck))));
+         * call that we are passing the left side to as a singular argument. this
+         * means we don't actually need a temporary variable*/
+        return expr_call(ck,
+            /* thing to call */
+            compile_ast_expr(ck, node->op.right, FALSE),
+            /* parameter list (weirdly i guess the left thing could be a splat) */
+            expr_list(ck, compile_ast_expr(ck, node->op.left, TRUE)));
       }
-      return right;
     } else {
       sbIrExpr *left = NULL, *right = NULL;
       if (node->op.left != NO_NODE) {
index 3ee2ed6..bc47632 100644 (file)
@@ -178,6 +178,7 @@ static unop unops[] = {
   { T_MINUS, 85, AST_OP_UNMINUS },
   { T_AMPERSAND, 85, AST_OP_REF },
   { T_ASTERISK, 85, AST_OP_DEREF },
+  { T_ELLIPSIS, 85, AST_OP_SPLAT },
 };
 
 static const usize NUM_BINOPS = sizeof(binops) / sizeof(binops[0]);
index fd8d407..bc2a549 100644 (file)
@@ -694,8 +694,9 @@ void execute_instruction(hVm vm) {
         CHECK("internal violation: LIST_SPILL should receive an integer on top of stack");
       }
       x = sbList_get_value(v->list, &count);
-      for (usize i = 0; i < count; i++) {
+      for (usize i = count - 1; ; i--) {
         push_stack(vm, &x[i]);
+        if (i == 0) break;
       }
       res.integer += count;
       push_stack_immediate(vm, &res);