--- /dev/null
+#include "compile/analyze.h"
+
+#include "parse/ast.h"
+#include "data/symbol.h"
+
+i32 sbAst_count_pipe_underscores(sbAst node) {
+ if (node == NULL) return 0;
+
+ switch (node->type) {
+ case AST_NULL:
+ /* like the end of a list or whatever */
+ return 0;
+ case AST_NODE_NAME:
+ if (sbstrncmp(sbSymbol_name(node->symb), "_", 1) == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ case AST_NODE_SEQ:
+ case AST_NODE_NEXT:
+ case AST_NODE_MULTIVAL:
+ case AST_NODE_FUNCCALL:
+ case AST_VAL_FUNC:
+ case AST_VAL_IMFUNC:
+ case AST_VAL_OBJ:
+ case AST_NODE_HASHENTRY:
+ return sbAst_count_pipe_underscores(node->seq.left)
+ + sbAst_count_pipe_underscores(node->seq.right);
+ case AST_NODE_OP:
+ if (node->op.type == AST_OP_PIPE) {
+ /* for a pipe, underscores on the right side don't count
+ * towards this, because they refer to the result of whatever
+ * is on the left side. but underscores on the left side do
+ * refer to what we're binding, so they do count */
+ return sbAst_count_pipe_underscores(node->op.left);
+ } else {
+ return sbAst_count_pipe_underscores(node->op.left);
+ + sbAst_count_pipe_underscores(node->op.right);
+ }
+ case AST_NODE_ASSIGN:
+ case AST_NODE_LET:
+ /* for declarations and assignments, we only count the expressions
+ * on the right, not the things on the left (this might happen if we
+ * have a pipe into a function literal that contains statements etc) */
+ return sbAst_count_pipe_underscores(node->op.right);
+ case AST_VAL_LIST:
+ case AST_VAL_HASH:
+ /* check the things inside the whatever */
+ return sbAst_count_pipe_underscores(node->op.left);
+ case AST_VAL_NIL:
+ case AST_VAL_INT:
+ case AST_VAL_STRING:
+ case AST_VAL_FLOAT:
+ case AST_VAL_SYMBOL:
+ case AST_VAL_BOOLEAN:
+ /* these are not the name "_" */
+ return 0;
+ default:
+ PANIC("aah! (%lld)", (long long)node->type);
+ }
+}
#include "compile/ir.h"
+#include "compile/analyze.h"
#include "parse/ast.h"
#include "data/symbol.h"
#include "data/integer.h"
} else if (node->op.type == AST_OP_PIPE) {
/* assign LHS to our temporary secret pipe variable,
* then use RHS as our value */
- if (node->op.right->has_us) {
+ i32 num_bindings = sbAst_count_pipe_underscores(node->op.right);
+ if (num_bindings > 0) {
/* 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... */
+ if (ck->pipe_var_in_use || list_context) {
+ PANIC("Pipe cannot currently be used in this context. I will fix it");
+ }
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);
+ ck->pipe_var_in_use = TRUE;
+ sbIrExpr *right = compile_ast_expr(ck, node->op.right, FALSE);
+ ck->pipe_var_in_use = FALSE;
+ return right;
} 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. this
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)));
+ /* parameter list (true = the left thing can be a splat, because it does work,
+ * but you can't have commas. but you can do ...[x, y, z] | stuff) */
+ //expr_list(ck, compile_ast_expr(ck, node->op.left, TRUE)));
+ // ok currently you can't. but we will
+ expr_list(ck, compile_ast_expr(ck, node->op.left, FALSE)));
}
} else {
sbIrExpr *left = NULL, *right = NULL;