#include "global.h"
-#define FLAG_SQUIGGLY (1ULL << 62)
+#define IT_FLAG_BOUND_METHOD (1ULL << 62)
#define HVINT(n) ((hV) { .type = IT_INTEGER, .integer = n })
#define HVFLOAT(f) ((hV) { .type = IT_FLOAT, .float_val = f })
#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 })
#define HVBUILTIN(b) ((hV) { .type = IT_BUILTIN, .builtin = b })
+#define HVBOUNDMETHOD(m, t) ((hV) { .type = m | IT_FLAG_BOUND_METHOD, .ref = t })
#define HVMODULE(m) ((hV) { .type = IT_MODULE, .module = m })
struct sbVm;
#include "common.h"
-#include "data/symbol.h"
#include "vm/exec.h"
+#include "data/symbol.h"
+#include "data/reference.h"
+
#include "lib/table.h"
#include "lib/sentinel.h"
#include "lib/method.h"
* (non-intrinsic types are always functions, so they can be resolved just by
* calling them)*/
void sbLib_resolve_property(hVm vm) {
- printf("Resolving property\n");
- sbVm_print_stack(vm);
hV *target = sbVm_pop(vm);
hV *argc = sbVm_pop(vm);
if (argc->type != IT_INTEGER) {
} else {
/* it is a method, but it is being called without parameters.
* annoyingly, we need to construct a bound version of this method. */
- PANIC("I haven't done this yet!");
+ hRef ref = sbRef_create(target);
+ sbVm_push_immediate(vm, &HVBOUNDMETHOD(method_name_val->symbol, ref));
}
} else {
PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol));
void call_block(hVm vm, usize block_id, hClosure closure);
void call_builtin(hVm vm, hV *to_call);
+void call_bound_method(hVm vm, hV *to_call);
void return_from_block(hVm vm);
void execute_instruction(hVm vm);
void push_stack(hVm vm, hV *value);
void sbVm_call_func(hVm vm, hV *func) {
if (func->type == IT_BUILTIN) {
call_builtin(vm, func);
+ } else if (func->type <= 0) {
+ /* intrinsic type: resolve a property on it */
+ push_stack(vm, func);
+ sbLib_resolve_property(vm);
+ } else if (func->type & IT_FLAG_BOUND_METHOD) {
+ call_bound_method(vm, func);
} else {
call_block(vm, func->type, func->closure);
}
vm->ip = &blk->bytecode[0];
}
+void call_bound_method(hVm vm, hV *to_call) {
+ if (!(to_call->type & IT_FLAG_BOUND_METHOD)) {
+ CHECK("call_bound_method can only call bound methods!");
+ }
+
+ /* bound method is just a symbol + a closure containing one variable */
+ hSymbol sym = (hSymbol)(to_call->type & ~IT_FLAG_BOUND_METHOD);
+ hRef ref = (to_call->ref);
+
+ /* we should already have parameters, so we just need to line it back up
+ * on the stack and call the method again */
+ push_stack_immediate(vm, &HVSYM(sym));
+ swap_stack_top(vm);
+ if (peek_stack(vm, 0)->type != IT_INTEGER) {
+ CHECK("bound method call should receive an integer arg count!");
+ }
+ peek_stack(vm, 0)->integer ++;
+ push_stack(vm, sbRef_deref(ref));
+ sbLib_resolve_method(vm);
+}
+
void return_from_block(hVm vm) {
for (usize i = 0; i < vm->fp->num_locals; i++) {
sbV_release(&vm->fp->locals[i]);
break;
case BC_CALL:
v = pop_stack(vm);
- if (v->type == IT_BUILTIN) {
- call_builtin(vm, v);
- } else if (v->type <= 0) {
- /* intrinsic type: resolve a property on it */
- push_stack(vm, v);
- sbLib_resolve_property(vm);
- } else {
- call_block(vm, v->type, v->closure);
- }
+ sbVm_call_func(vm, v);
break;
case BC_SEND:
sbLib_resolve_method(vm);