From: cassowarii Date: Fri, 3 Jul 2026 23:22:16 +0000 (-0700) Subject: initial stab at method calls; *almost* works, but not quite X-Git-Url: https://git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=eca49ae83dec4f03f7af35c4cdde4455775578b9;p=sarabande.git initial stab at method calls; *almost* works, but not quite --- diff --git a/src/compile/emit.c b/src/compile/emit.c index 2c91afc..acab122 100644 --- a/src/compile/emit.c +++ b/src/compile/emit.c @@ -323,6 +323,11 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) { compile_expr(cm, expr->call.func); EMIT(BC_CALL); break; + case IR_E_SEND: + compile_list(cm, expr->send.message); + compile_expr(cm, expr->send.target); + EMIT(BC_SEND); + break; case IR_E_VAR: if (expr->var->is_upvalue) { EMIT(BC_LD_UPVAL); diff --git a/src/compile/ir.c b/src/compile/ir.c index 70ba765..6bd6545 100644 --- a/src/compile/ir.c +++ b/src/compile/ir.c @@ -340,6 +340,14 @@ static sbIrExpr *expr_call(hIrChunk ck, sbIrExpr *to_call, sbIrExpr *param) { }); } +static sbIrExpr *expr_send(hIrChunk ck, sbIrExpr *target, sbIrExpr *message) { + return new_expr(ck, &(sbIrExpr) { + .type = IR_E_SEND, + .send.target = target, + .send.message = message, + }); +} + static sbIrExpr *expr_list(hIrChunk ck, sbIrExpr *value) { return new_expr(ck, &(sbIrExpr) { .type = IR_E_LIST, @@ -929,6 +937,10 @@ static sbIrExpr *compile_ast_expr(hIrChunk ck, sbAst node, flag list_context) { sbIrExpr *called = compile_ast_expr(ck, node->seq.left, FALSE); sbIrExpr *params = compile_ast_list(ck, node->seq.right); return expr_call(ck, called, params); + } else if (node->type == AST_NODE_METHODCALL) { + sbIrExpr *target = compile_ast_expr(ck, node->seq.left, FALSE); + sbIrExpr *message = compile_ast_list(ck, node->seq.right); + return expr_send(ck, target, message); } else if (node->type == AST_VAL_FUNC) { sbIrChunk *func = compile_ast_function(ck->program, node->seq.left, node->seq.right); return expr_func(ck, func); diff --git a/src/compile/ir.h b/src/compile/ir.h index 3ddb128..a1044fc 100644 --- a/src/compile/ir.h +++ b/src/compile/ir.h @@ -46,6 +46,7 @@ typedef enum sbIrExprType { IR_E_VAR, IR_E_FUNC, IR_E_CALL, + IR_E_SEND, IR_E_LIST, IR_E_HASH, } sbIrExprType; @@ -100,6 +101,10 @@ typedef struct sbIrExpr { struct sbIrExpr *this; struct sbIrExpr *next; } list; + struct { + struct sbIrExpr *target; + struct sbIrExpr *message; + } send; }; } sbIrExpr; diff --git a/src/compile/print_ir.c b/src/compile/print_ir.c index 374eda4..ab71f23 100644 --- a/src/compile/print_ir.c +++ b/src/compile/print_ir.c @@ -74,13 +74,16 @@ static void print_expr(sbIrExpr *e) { case IR_E_CALL: debug("CALL: "); print_expr(e->call.func); - debug(" with params "); - sbIrExpr *param = e->call.param; - while (param) { - print_expr(param->list.this); - debug(","); - param = param->list.next; - } + debug(" with params ("); + print_expr(e->call.param); + debug(")"); + break; + case IR_E_SEND: + debug("SEND: "); + print_expr(e->send.target); + debug(" <~( "); + print_expr(e->send.message); + debug(" )"); break; case IR_E_LIST: print_expr(e->list.this); diff --git a/src/data/methods.c b/src/data/methods.c new file mode 100644 index 0000000..dc8bd0a --- /dev/null +++ b/src/data/methods.c @@ -0,0 +1,49 @@ +#include "data/methods.h" + +#include "vm/exec.h" +#include "data/symbol.h" +#include "data/list.h" + +#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name))) + +void sbList_method(hV list, hVm vm) { + if (list.type != IT_LIST) { + CHECK("can't call sbList_method on something that isn't a list"); + } + hV argc = sbVm_pop(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); + if (method_name_val->type == IT_SYMBOL) { + const char *method_name = sbSymbol_name(method_name_val->symbol); + printf("method name: %s\n", method_name); + if (METHOD_IS("each")) { + if (num_params != 1) { + PANIC("wrong number of arguments passed to list#each!"); + } + hV loop_func = sbVm_pop(vm); + sbVm_pop(vm); /* remove method name */ + usize length; + hV *iter_values = sbList_get_value(list.list, &length); + for (usize i = 0; i < length; i++) { + /* TODO : This doesn't work! It almost works, but when we call the + * callback func, we need to, like, pause this function and run more + * VM instructions, then come back to this one. How do? :thinking emoji: */ + printf("index %zu\n", i); + sbVm_push(vm, iter_values[i]); + sbVm_push(vm, HVINT(1)); + printf("call loop-func\n"); + sbVm_call_func(vm, loop_func); + /* remove result of loop_func */ + printf("loop-func done\n"); + sbVm_pop(vm); + } + } + } else { + PANIC("method name to list is not symbol! (%lld)", method_name_val->type); + } +} + diff --git a/src/data/methods.h b/src/data/methods.h new file mode 100644 index 0000000..c93dc5a --- /dev/null +++ b/src/data/methods.h @@ -0,0 +1,3 @@ +#include "common.h" + +void sbList_method(hV list, hVm vm); diff --git a/src/data/value.h b/src/data/value.h index 61c1956..46bfc03 100644 --- a/src/data/value.h +++ b/src/data/value.h @@ -3,6 +3,8 @@ #include "common.h" +#define FLAG_SQUIGGLY (1ULL << 62) + #define HVINT(n) ((hV) { .type = IT_INTEGER, .integer = n }) #define HVSTR(s) ((hV) { .type = IT_STRING, .string = s }) #define HVSYM(s) ((hV) { .type = IT_SYMBOL, .symbol = s }) @@ -12,6 +14,7 @@ #define HVNIL ((hV) { .type = IT_NIL }) #define HVNOTHING ((hV) {0}) #define HVFUNC(i, c) ((hV) { .type = i, .closure = c }) +#define HVFUNC2(i, c) ((hV) { .type = i | FLAG_SQUIGGLY, .closure = c }) typedef u64 hHash; typedef u64 hString; diff --git a/src/parse/parser.c b/src/parse/parser.c index b34fe1d..09076ad 100644 --- a/src/parse/parser.c +++ b/src/parse/parser.c @@ -605,15 +605,17 @@ 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); - if (!expect(pr, T_LPAREN)) return syntax_error(pr); - sbAst params = parse_comma_exprs(pr, NULL); - if (!expect(pr, T_RPAREN)) return syntax_error(pr); + sbAst params = NO_NODE; + if (expect(pr, T_LPAREN)) { + params = parse_comma_exprs(pr, NULL); + if (!expect(pr, T_RPAREN)) return syntax_error(pr); + } ast_type = AST_NODE_METHODCALL; if (op.type == T_ARROW) { /* (whatever)->x is rewritten as (*whatever).x */ lhs = unop_node(pr, AST_OP_DEREF, lhs); } - rhs = seq_node(pr, AST_NODE_NEXT, method_name, params); + 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); diff --git a/src/vm/exec.c b/src/vm/exec.c index 1c4934a..42ff4f9 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -7,6 +7,10 @@ void call_block(hVm vm, usize block_id, hClosure closure); void execute_instruction(hVm vm); +void push_stack(hVm vm, const hV *value); +hV pop_stack(hVm vm); +hV *npop_stack(hVm vm, usize count); +hV *peek_stack(hVm vm, usize offset); void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode) { *vm = (sbVm) {0}; @@ -50,6 +54,22 @@ sbVmStatus sbVm_execute(hVm vm, sbVmProgram *pm) { return VM_STAT_SUCCESS; } +void sbVm_push(hVm vm, hV value) { + push_stack(vm, &value); +} + +hV sbVm_pop(hVm vm) { + return pop_stack(vm); +} + +hV *sbVm_peek(hVm vm, usize where) { + return peek_stack(vm, where); +} + +void sbVm_call_func(hVm vm, hV func) { + call_block(vm, func.type, func.closure); +} + /* --- */ void call_block(hVm vm, usize block_id, hClosure closure) { @@ -327,6 +347,9 @@ void execute_instruction(hVm vm) { } call_block(vm, vv.type, vv.closure); break; + case BC_SEND: + sbV_message_handler(vm); + break; case BC_NUMARG: param = get_param(vm); vv = pop_stack(vm); @@ -364,8 +387,6 @@ void execute_instruction(hVm vm) { case BC_RET: return_from_block(vm); break; - case BC_SEND: - PANIC("todo"); case BC_OP_EQ: v = peek_stack(vm, 1); w = peek_stack(vm, 0); diff --git a/src/vm/exec.h b/src/vm/exec.h index 0b8b219..ebcb8bf 100644 --- a/src/vm/exec.h +++ b/src/vm/exec.h @@ -69,10 +69,16 @@ typedef struct sbVm { flag debugmode; } sbVm; -typedef sbVm *hVm; - void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode); void sbVm_deinitialize(hVm vm); sbVmStatus sbVm_execute(hVm vm, sbVmProgram *pm); + +void sbVm_push(hVm vm, hV value); + +hV sbVm_pop(hVm vm); + +hV *sbVm_peek(hVm vm, usize where); + +void sbVm_call_func(hVm vm, hV func); diff --git a/src/vm/operations.c b/src/vm/operations.c index 3504db4..15e9f47 100644 --- a/src/vm/operations.c +++ b/src/vm/operations.c @@ -1,8 +1,31 @@ #include "vm/operations.h" +#include "vm/exec.h" #include "data/integer.h" #include "data/list.h" #include "data/hashtable.h" +#include "data/methods.h" + +void sbV_message_handler(hVm vm) { + hV target = sbVm_pop(vm); + switch(target.type) { + case IT_LIST: + sbList_method(target, vm); + break; + default: + if (target.type < 0) { + PANIC("haven't implemented method calling for this intrinsic type!"); + } + if (target.type & FLAG_SQUIGGLY) { + /* squiggle function */ + sbVm_call_func(vm, target); + } else { + /* normal function */ + PANIC("haven't implemented method calling for functions yet!"); + //sbFunction_method(target, vm); + } + } +} hV sbV_add(const hV *a, const hV *b) { if (a->type == IT_INTEGER && b->type == IT_INTEGER) { diff --git a/src/vm/operations.h b/src/vm/operations.h index 672fa8b..f14c8b8 100644 --- a/src/vm/operations.h +++ b/src/vm/operations.h @@ -1,5 +1,7 @@ #include "common.h" +void sbV_message_handler(hVm vm); + hV sbV_add(const hV *a, const hV *b); hV sbV_sub(const hV *a, const hV *b); diff --git a/src/vm/vm.h b/src/vm/vm.h index 24e3b76..a952ec6 100644 --- a/src/vm/vm.h +++ b/src/vm/vm.h @@ -2,5 +2,9 @@ #define __SARABANDE_VM_H__ #include "vm/bytecode.h" +#include "data/value.h" + +struct sbVm; +typedef struct sbVm *hVm; #endif