From 67e63bf4b02b6145bb2842f9002dc808fb885acf Mon Sep 17 00:00:00 2001 From: cassowarii Date: Fri, 10 Jul 2026 16:15:42 -0700 Subject: [PATCH] add | operator between expressions; project euler #6 --- src/compile/ir.c | 51 +++++++++++++++++++++++++++++++++++++++++++++----- src/compile/ir.h | 3 ++- src/compile/print_ir.c | 22 ++++++++++++++++------ 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/compile/ir.c b/src/compile/ir.c index 3e214be..5ab9b6c 100644 --- a/src/compile/ir.c +++ b/src/compile/ir.c @@ -17,6 +17,7 @@ typedef struct varmapentry { static sbIrChunk *compile_ast_function(hIrProgram ir, sbAst params, sbAst seqast); static sbIrChunk *new_chunk(hIrProgram ir); static void chunk_deinitialize(hIrChunk ck); +static sbIrVariable *create_var(hIrChunk ck, const char *name, usize name_len); void sbIrProgram_initialize(hIrProgram ir, usize initial_arena_size) { *ir = (sbIrProgram) {0}; @@ -107,6 +108,14 @@ static void chunk_deinitialize(hIrChunk ck) { sbBuffer_deinitialize(&ck->closed_vars); } +static sbIrVariable *var_at_index(hIrChunk ck, usize index) { + if (ck->program->varmapping.size / sizeof(varmapentry) > index) { + return BUFFER_INDEX(ck->program->varmapping, varmapentry, index).var; + } else { + return NO_VAR; + } +} + /* find variables that already exist */ static sbIrVariable *existing_var(hIrChunk ck, const char *name, usize name_len, usize *index_out) { usize index = 0; @@ -187,8 +196,26 @@ static sbIrVariable *bind_upvalue(hIrChunk ck, usize variable_index) { } } +/* ensure a pipe variable slot is available */ +static sbIrVariable *pipe_var(hIrChunk ck) { + if (ck->pipe_var_id == -1) { + sbIrVariable *new_pipe_var = create_var(ck, "", 0); + ck->pipe_var_id = new_pipe_var->slot_id; + new_pipe_var->introduced = BY_IMPLICIT; + return new_pipe_var; + } else { + return var_at_index(ck, ck->pipe_var_id + ck->lowest_var_id); + } +} + /* to look up a variable name in source code */ static sbIrVariable *var_name(hIrChunk ck, const char *name, usize name_len) { + if (name_len == 1 && name[0] == '_') { + /* _ variable is resolved specially depending on context... currently, this is + * just for the pipe variable */ + return pipe_var(ck); + } + usize index; sbIrVariable *v = existing_var(ck, name, name_len, &index); @@ -206,11 +233,16 @@ static sbIrVariable *var_name(hIrChunk ck, const char *name, usize name_len) { /* we can introduce new variables into a scope using LET */ static sbIrVariable *create_var(hIrChunk ck, const char *name, usize name_len) { - sbIrVariable *already_existing = existing_var(ck, name, name_len, NULL); - if (already_existing != NO_VAR) { - // TODO this should probably just be a warning - chunk_error(ck, "redeclaration of variable '%s'!\n", name); - return NO_VAR; + /* we can pass an empty name to create extra 'internal' variables that don't + * have real names, as part of a sort of desugar thing. but you have to remember + * their ID numbers */ + if (name_len > 0) { + sbIrVariable *already_existing = existing_var(ck, name, name_len, NULL); + if (already_existing != NO_VAR) { + // TODO this should probably just be a warning + chunk_error(ck, "redeclaration of variable '%s'!\n", name); + return NO_VAR; + } } sbIrVariable *new_var = sbArena_alloc(&ck->program->arena, sizeof(sbIrVariable)); @@ -527,6 +559,9 @@ static sbIrChunk *compile_ast_function(hIrProgram ir, sbAst paramsAst, sbAst seq /* create new scope to hold function parameters */ usize parameter_scope_level = ck->program->varmapping.size / sizeof(varmapentry); + /* we have no pipe var right now */ + ck->pipe_var_id = -1; + /* compile parameters */ sbIrBindList *arg_binding = compile_ast_bind_list(ck, paramsAst, TRUE, BY_PARAM); if (arg_binding) { @@ -994,6 +1029,12 @@ static sbIrExpr *compile_ast_expr(hIrChunk ck, sbAst node, flag list_context) { } else { return expr_op(ck, AST_OP_SPLAT, compile_ast_expr(ck, node->op.left, FALSE), NULL); } + } 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); + return compile_ast_expr(ck, node->op.right, FALSE); } else { sbIrExpr *left = NULL, *right = NULL; if (node->op.left != NO_NODE) { diff --git a/src/compile/ir.h b/src/compile/ir.h index a27b2a1..d1a378c 100644 --- a/src/compile/ir.h +++ b/src/compile/ir.h @@ -58,6 +58,7 @@ typedef enum sbIrNameIntroduceType { BY_LET, BY_PARAM, BY_CONTEXT, + BY_IMPLICIT, } sbIrNameIntroduceType; typedef struct sbIrLabel { @@ -144,10 +145,10 @@ typedef struct sbIrChunk { i32 id; i16 num_args; i16 num_upvalues; - flag variadic; i32 label_count; i32 variable_count; i32 lowest_var_id; + i32 pipe_var_id; sbBuffer closed_vars; sbBuffer stmts; } sbIrChunk; diff --git a/src/compile/print_ir.c b/src/compile/print_ir.c index a6102fa..096cbd9 100644 --- a/src/compile/print_ir.c +++ b/src/compile/print_ir.c @@ -1,5 +1,7 @@ #include "compile/ir.h" +#include "data/symbol.h" + static void print_stmt(sbIrStmt *s); void sbIrProgram_print(hIrProgram ir) { @@ -50,14 +52,17 @@ static void print_expr(sbIrExpr *e) { print_var(*var); debug(", "); } + debug("\b\b"); } - debug("}"); + debug(" }"); break; case IR_E_VALUE: if (e->value.type == IT_NIL) { debug("nil"); } else if (e->value.type == IT_INTEGER) { debug("%lld", (long long)e->value.integer); + } else if (e->value.type == IT_SYMBOL) { + debug(":%s", sbSymbol_name(e->value.symbol)); } else { debug("some value"); } @@ -88,13 +93,18 @@ static void print_expr(sbIrExpr *e) { debug(" )"); break; case IR_E_LIST: - if (e->list.this) { - print_expr(e->list.this); - } if (e->list.next) { - debug(", "); print_expr(e->list.next); + if (e->list.next->list.next) { + debug(", "); + } } + if (e->list.this) { + print_expr(e->list.this); + } + break; + case IR_E_CONTEXT: + debug("(context var %s)", sbSymbol_name(e->symbol)); break; default: debug("something %d", e->type); @@ -143,7 +153,7 @@ static void print_stmt(sbIrStmt *s) { if (s->expr) { print_expr(s->expr); } else { - debug("NOTHING"); + debug("NOTHING!! (PROBABLY A BUG)"); } debug("\n"); break; -- 1.8.3.1