From: cassowarii <2374677+cassowarii@users.noreply.github.com> Date: Thu, 23 Jul 2026 02:28:14 +0000 (-0700) Subject: list assignment (and such) works! X-Git-Url: https://git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=540baea12c12ea95cf97fe852c1480c1628e2781;p=sarabande.git list assignment (and such) works! the only thing i think not currently working is something mysterious in generator, and list.length right now because it doesn't return a reference. i'll fix this later, i'm tired and it's too WARM, i need to remove some of my horrible comments too --- diff --git a/sample/generator.sbd b/sample/generator.sbd index f06aa0b..7ef6f0d 100644 --- a/sample/generator.sbd +++ b/sample/generator.sbd @@ -153,12 +153,16 @@ let generator = (=> { } } + def get_classmethod m { + &class_methods[m] + } + => f { if f == op::index { - class_methods(op::index) + get_classmethod } else { => method { - instance_methods[method](f) + &(instance_methods[method](f)) } } } diff --git a/src/compile/emit.c b/src/compile/emit.c index bfe0728..d2eef01 100644 --- a/src/compile/emit.c +++ b/src/compile/emit.c @@ -136,6 +136,12 @@ void record_labelpos(sbVmCompiler *cm, sbIrLabel *label, u32 offset) { sbBuffer_append(&cm->label_positions, &lp, sizeof(struct labelpos)); } +/* things that implicitly dereference when used in a value context but + * can be assigned to on the left side of an = */ +flag is_implicit_ref(sbIrExpr *expr) { + return expr->type == IR_E_VAR || expr->type == IR_E_DOT || (expr->type == IR_E_OP && expr->op.type == AST_OP_INDEX); +} + void compile_list(sbVmCompiler *cm, sbIrExpr *expr); void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list); void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) { @@ -214,18 +220,32 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) { * The reason for this has to do with assigning through nested data structures. * Doing it this way just makes the whole semantics feel more natural. It's similar * to returning a reference from indexing in C++, I guess. */ - compile_ref(cm, stmt->assign.where->op.left, TRUE); /* thing we are indexing into */ + if (is_implicit_ref(stmt->assign.where->op.left)) { + compile_ref(cm, stmt->assign.where->op.left, TRUE); + } else { + compile_expr(cm, stmt->assign.where->op.left); + } compile_expr(cm, stmt->assign.where->op.right); /* index we are using */ - EMIT(BC_OP_INDEXLREF); + if (is_implicit_ref(stmt->assign.where->op.left)) { + EMIT(BC_OP_INDEXLREF_IND); + } else { + /* THE PROLIFERATION OF THESE!!!!!!!!!! I DO NOT LIKE!!!! */ + EMIT(BC_OP_INDEXLREF); + } EMIT(BC_REF_PUT); } else if (stmt->assign.where->type == IR_E_DOT) { /* same as op::index, essentially. the dot returns a reference to the inside of the * thing, then we can assign to that reference */ - compile_expr(cm, stmt->assign.where->op.right); + compile_expr(cm, stmt->assign.where->dot.param); EMIT(BC_LD_IMM); EARG(1); - compile_ref(cm, stmt->assign.where->op.left, TRUE); - EMIT(BC_CALL_IND); + if (is_implicit_ref(stmt->assign.where->dot.target)) { + compile_ref(cm, stmt->assign.where->dot.target, TRUE); + EMIT(BC_DOT_IND); + } else { + compile_expr(cm, stmt->assign.where->dot.target); + EMIT(BC_DOT); + } EMIT(BC_REF_PUT); } else { PANIC("This type of assignment operation is not supported!"); @@ -369,6 +389,11 @@ void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list) { } void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) { + if (cm->debugmode) { + sbIr_print_expr(expr); + debug("\n"); + } + switch(expr->type) { case IR_E_OP: if (expr->op.type == AST_OP_REF) { @@ -386,8 +411,7 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) { case IR_E_CALL: /* calling convention: store argument count on stack */ compile_list(cm, expr->call.param); - if (expr->call.func->type == IR_E_DOT - || (expr->call.func->type == IR_E_OP && expr->call.func->op.type == AST_OP_INDEX)) { + if (is_implicit_ref(expr->call.func)) { /* for expressions with reference type, call 'through' the reference */ compile_ref(cm, expr->call.func, TRUE); EMIT(BC_CALL_IND); @@ -497,23 +521,43 @@ void compile_ref(sbVmCompiler *cm, sbIrExpr *expr, flag is_lref) { } EARG(expr->var->slot_id); } else if (expr->type == IR_E_OP && expr->op.type == AST_OP_INDEX) { - compile_ref(cm, expr->op.left, is_lref); /* thing we are indexing into */ + /* TODO: Oh my god, it's 90F with no air conditioning, but can we PLEASE figure out + * a better way to structure this??!!?!?!?! */ + if (is_implicit_ref(expr->op.left)) { + compile_ref(cm, expr->op.left, is_lref); /* thing we are indexing into */ + } else { + compile_expr(cm, expr->op.left); /* thing we are indexing into */ + } compile_expr(cm, expr->op.right); /* index we are using */ if (is_lref) { /* a[0] = ? / a::b = ? */ - EMIT(BC_OP_INDEXLREF); + if (is_implicit_ref(expr->op.left)) { + /* THIS SUCKS!!! */ + EMIT(BC_OP_INDEXLREF_IND); + } else { + EMIT(BC_OP_INDEXLREF); + } } else { /* &a[0] / &a::b */ - EMIT(BC_OP_INDEXRREF); + if (is_implicit_ref(expr->op.left)) { + EMIT(BC_OP_INDEXRREF_IND); + } else { + EMIT(BC_OP_INDEXRREF); + } } } else if (expr->type == IR_E_DOT) { compile_expr(cm, expr->dot.param); EMIT(BC_LD_IMM); EARG(1); - compile_ref(cm, expr->dot.target, is_lref); - EMIT(BC_DOT); + if (is_implicit_ref(expr->dot.target)) { + compile_ref(cm, expr->dot.target, is_lref); + EMIT(BC_DOT_IND); + } else { + compile_expr(cm, expr->dot.target); + EMIT(BC_DOT); + } } else { - PANIC("cannot & non-variable-name! (todo)"); + PANIC("This type of reference operation is not supported!"); } } diff --git a/src/compile/print_ir.c b/src/compile/print_ir.c index 070b0c1..21a3d0a 100644 --- a/src/compile/print_ir.c +++ b/src/compile/print_ir.c @@ -82,9 +82,9 @@ static void print_expr(sbIrExpr *e) { debug(")"); break; case IR_E_CALL: - debug("CALL: "); + debug("(CALL: "); print_expr(e->call.func); - debug(" with params ("); + debug(" with params "); if (e->call.param) { print_expr(e->call.param); } diff --git a/src/lib/lib.c b/src/lib/lib.c index 64c6b4e..002945d 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -183,19 +183,22 @@ static sbLibTable *find_method_table(hVal *target) { /* resolve_method should have set us up so we can just call in twice */ static sbCFuncStatus please_call_again(hVm vm, flag init) { hVal *target = sbVm_pop(vm); - if (target->type <= 0) { + if (init && target->type <= 0) { PANIC("i have not implemented partial methods for builtin types yet! i'll get to it"); + } else if (!init && target->type != IT_REF) { + PANIC("object illegally did not return a reference!"); } if (init) { /* first time around: call to dispatch method */ sbVm_call_func(vm, target); - /* please call us again if you have any questions*/ + /* please call us again if you have any questions */ return CFUNC_NEXT; } else { /* second time around: call method on its parameters */ - sbVm_transfer_to_func(vm, target); + hVal *bound_method_ptr = sbVar_get_value_ptr(sbVar_deref(target)); + sbVm_transfer_to_func(vm, bound_method_ptr); /* please forget we ever existed */ return CFUNC_TAILCALL; diff --git a/src/lib/table.c b/src/lib/table.c index 85cd49b..9c60df9 100644 --- a/src/lib/table.c +++ b/src/lib/table.c @@ -12,13 +12,13 @@ typedef sbLibTable { hSymbol *keys; union { sbLibMethod *methods; - hVal *values; + sbVar *values; }; } sbLibTable; */ static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod *method); -static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol key, hVal *value); +static void insert_value(hSymbol *keys, sbVar *values, usize capacity, hSymbol key, hVal *value); static void check_grow_table(hLibTable t); void sbLibTable_initialize(hLibTable t, usize capacity, flag method_table) { @@ -74,12 +74,30 @@ hVal *sbLibTable_find_value(hLibTable t, hSymbol key) { } if (t->keys[index]) { - return &t->values[index]; + return sbVar_get_value_ptr(&t->values[index]); } else { return NULL; } } +hVal sbLibTable_find_ref(hLibTable t, hSymbol key) { + if (t->method_table) CHECK("cannot find value in method table"); + + sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol)); + usize index = hash % t->capacity; + while (t->keys[index] && t->keys[index] != key) { + index ++; + index %= t->capacity; + } + + if (t->keys[index]) { + /* lvalue ref always safe because these never get deallocated */ + return sbVar_get_lvalue_ref(&t->values[index]); + } else { + return HVNIL; + } +} + void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method) { if (!t->method_table) CHECK("cannot put method in non-method table"); @@ -123,7 +141,7 @@ static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, h methods[index] = *method; } -static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol key, hVal *value) { +static void insert_value(hSymbol *keys, sbVar *values, usize capacity, hSymbol key, hVal *value) { sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol)); usize index = hash % capacity; @@ -133,7 +151,7 @@ static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol ke } keys[index] = key; - values[index] = *value; + sbVar_set_value(&values[index], value); } static void check_grow_table(hLibTable t) { @@ -154,11 +172,11 @@ static void check_grow_table(hLibTable t) { free(t->methods); t->methods = new_methods; } else { - hVal *new_values = calloc(new_capacity, sizeof(hVal)); + sbVar *new_values = calloc(new_capacity, sizeof(hVal)); for (usize i = 0; i < t->capacity; i++) { if (t->keys[i] != 0) { - insert_value(new_keys, new_values, new_capacity, t->keys[i], &t->values[i]); + insert_value(new_keys, new_values, new_capacity, t->keys[i], sbVar_get_value_ptr(&t->values[i])); } } diff --git a/src/lib/table.h b/src/lib/table.h index bcf2add..72649bb 100644 --- a/src/lib/table.h +++ b/src/lib/table.h @@ -13,7 +13,7 @@ typedef struct sbLibTable { flag method_table; union { sbLibMethod *methods; - hVal *values; + sbVar *values; }; } sbLibTable; @@ -27,6 +27,8 @@ sbLibMethod *sbLibTable_find_method(hLibTable t, hSymbol key); hVal *sbLibTable_find_value(hLibTable t, hSymbol key); +hVal sbLibTable_find_ref(hLibTable t, hSymbol key); + void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod *method); void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method); diff --git a/src/vm/bytecode.h b/src/vm/bytecode.h index c246edd..e96e17e 100644 --- a/src/vm/bytecode.h +++ b/src/vm/bytecode.h @@ -25,7 +25,8 @@ typedef enum sbOpcode { BC_SWAP, // swap top two values on stack BC_CALL, // push return address and jump to new block BC_CALL_IND, // 'a->(...)' indirect call that can return a value - BC_DOT, // 'a.b' indirect call that should return a reference + BC_DOT, // 'a.b' call that should return a reference + BC_DOT_IND, // 'a.b' indirect call that should return a reference BC_RET, // return to calling block BC_NUMARG, // check number of function arguments = this BC_MINARG, // check number of function arguments > this @@ -53,7 +54,9 @@ typedef enum sbOpcode { BC_OP_OR, // logical or BC_OP_INDEXVAL, // a[...] BC_OP_INDEXLREF, // a[...] = ... + BC_OP_INDEXLREF_IND, // a[...] = ... BC_OP_INDEXRREF, // &a[...] + BC_OP_INDEXRREF_IND, // &a[...] BC_OP_RANGEINDEX, // index [a..b] BC_ALLOC_VARS, // create space in rstack for local variables BC_CLOSURE, // create closure from top elements of stack diff --git a/src/vm/exec.c b/src/vm/exec.c index f68f119..24d93d0 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -458,17 +458,22 @@ void execute_instruction(hVm vm) { swap_stack_top(vm); break; case BC_CALL: + case BC_DOT: v = pop_stack(vm); sbVm_call_func(vm, v); break; - case BC_DOT: + case BC_DOT_IND: case BC_CALL_IND: v = pop_stack(vm); - if (v->type != IT_REF) { + if (v->type == IT_REF) { + vars = sbVar_deref(v); + w = sbVar_get_value_ptr(vars); + sbVm_call_func(vm, w); + } else if (v->type & IT_FLAG_BOUND_METHOD) { + sbVm_call_func(vm, v); + } else { PANIC("object illegally returned non-reference value"); } - vars = sbVar_deref(v); - sbVm_call_func(vm, sbVar_get_value_ptr(vars)); break; case BC_SEND: sbLib_resolve_method(vm); @@ -608,10 +613,16 @@ void execute_instruction(hVm vm) { sbV_index_value(vm); break; case BC_OP_INDEXLREF: - sbV_index_lref(vm); + sbV_index_ref(vm, TRUE, FALSE); + break; + case BC_OP_INDEXLREF_IND: + sbV_index_ref(vm, TRUE, TRUE); break; case BC_OP_INDEXRREF: - sbV_index_rref(vm); + sbV_index_ref(vm, FALSE, FALSE); + break; + case BC_OP_INDEXRREF_IND: + sbV_index_ref(vm, FALSE, TRUE); break; case BC_OP_RANGEINDEX: v = peek_stack(vm, 2); diff --git a/src/vm/operations.c b/src/vm/operations.c index fcd4e33..d1ad06f 100644 --- a/src/vm/operations.c +++ b/src/vm/operations.c @@ -148,52 +148,39 @@ void sbV_index_value(hVm vm) { } } -void sbV_index_lref(hVm vm) { +void sbV_index_ref(hVm vm, flag is_lref, flag is_indirect) { hVal *a = sbVm_peek(vm, 1); hVal *b = sbVm_peek(vm, 0); - if (a->type != IT_REF) { - PANIC("Object illegally returned non-reference!"); + + if (is_indirect) { + if (a->type != IT_REF) { + PANIC("Object illegally returned non-reference!"); + } + a = sbVar_get_value_ptr(sbVar_deref(a)); } - a = sbVar_get_value_ptr(sbVar_deref(a)); if (a->type == IT_LIST && b->type == IT_INTEGER) { sbVm_npop(vm, 2); - hVal result = sbList_index_lvalue_ref(a->list, b->integer); + hVal result; + if (is_lref) { + result = sbList_index_lvalue_ref(a->list, b->integer); + } else { + result = sbList_index_rvalue_ref(a->list, b->integer); + } sbVm_push(vm, &result); } else if (a->type == IT_HASH) { sbVm_npop(vm, 2); - hVal result = sbHash_find_lvalue_ref(a->hash, b); + hVal result; + if (is_lref) { + result = sbHash_find_lvalue_ref(a->hash, b); + } else { + result = sbHash_find_rvalue_ref(a->hash, b); + } sbVm_push(vm, &result); } else if (a->type == IT_MODULE && b->type == IT_SYMBOL) { - PANIC("TODO"); - } else { - sbVm_swap(vm); /* b a */ - sbVm_push_immediate(vm, &HVSYM(S_OP_INDEX)); /* b a op::index */ - sbVm_swap(vm); /* b op::index a */ - sbVm_push_immediate(vm, &HVINT(2)); /* b op::index a 2 */ - sbVm_swap(vm); /* b op::index 2 a */ - sbLib_resolve_method(vm); - } -} - -void sbV_index_rref(hVm vm) { - hVal *a = sbVm_peek(vm, 1); - hVal *b = sbVm_peek(vm, 0); - if (a->type != IT_REF) { - PANIC("Object illegally returned non-reference!"); - } - a = sbVar_get_value_ptr(sbVar_deref(a)); - - if (a->type == IT_LIST && b->type == IT_INTEGER) { - sbVm_npop(vm, 2); - hVal result = sbList_index_rvalue_ref(a->list, b->integer); - sbVm_push(vm, &result); - } else if (a->type == IT_HASH) { sbVm_npop(vm, 2); - hVal result = sbHash_find_rvalue_ref(a->hash, b); + hVal result = sbLibTable_find_ref(a->module, b->symbol); sbVm_push(vm, &result); - } else if (a->type == IT_MODULE && b->type == IT_SYMBOL) { - PANIC("TODO"); } else { sbVm_swap(vm); /* b a */ sbVm_push_immediate(vm, &HVSYM(S_OP_INDEX)); /* b a op::index */ diff --git a/src/vm/operations.h b/src/vm/operations.h index 12270e9..7c9844c 100644 --- a/src/vm/operations.h +++ b/src/vm/operations.h @@ -26,9 +26,7 @@ hVal sbV_append(hVal *a, hVal *b); void sbV_index_value(hVm vm); -void sbV_index_lref(hVm vm); - -void sbV_index_rref(hVm vm); +void sbV_index_ref(hVm vm, flag is_lref, flag is_indirect); hVal sbV_rangeindex(hVal *a, hVal *b, hVal *c);