/* --- */
void emit_arg(sbVmCompiler *cm, i64 actual_number) {
- debug(" arg %lld\n", actual_number);
+ debug(" arg %lld\n", (long long)actual_number);
u8 buf[9];
u64 number = actual_number;
if (0 <= actual_number && actual_number < 253) {
if (e->value.type == IT_NIL) {
debug("nil");
} else if (e->value.type == IT_INTEGER) {
- debug("%lld", e->value.integer);
+ debug("%lld", (long long)e->value.integer);
} else {
debug("some value");
}
static sbClosure *find_closure_by_handle(hRef handle) {
if (!(handle & FLAG_REAL)) PANIC("null closure");
- return sbPool_get_entry(&g_closure_pool, handle);
+ return sbPool_get_entry(&g_closure_pool, handle & ~FLAG_REAL);
}
const char *strval = sbString_get_value(obj->string, scratch, &length);
return sbHash_hash_bytes(strval, length);
} else {
- PANIC("don't know how to hash object of type %lld", obj->type);
+ PANIC("don't know how to hash object of type %lld", (long long)obj->type);
}
}
#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
+void list_each_cfunc(hVm vm, flag init);
+void list_map_cfunc(hVm vm, flag init);
+
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");
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);
- }
+ sbVm_push(vm, list);
+ sbVm_call_c_func(vm, list_each_cfunc);
}
} else {
- PANIC("method name to list is not symbol! (%lld)", method_name_val->type);
+ PANIC("method name to list is not symbol! (%ld)", method_name_val->type);
}
}
+void list_each_cfunc(hVm vm, flag init) {
+ if (init) {
+ /* store three state variables: the list we're iterating, the index into it, and the callback function */
+ sbVm_request_var_space(vm, 3);
+ hV iterating_list = sbVm_pop(vm);
+ hV loop_func = sbVm_pop(vm);
+ sbVm_pop(vm); /* remove method name */
+ hV index = HVINT(0);
+ vm->fp->locals[0] = iterating_list;
+ vm->fp->locals[1] = index;
+ vm->fp->locals[2] = loop_func;
+ } else {
+ /* loop func must have finished, so remove its result */
+ sbVm_pop(vm);
+ }
+
+ usize current_index = vm->fp->locals[1].integer++;
+ usize length;
+ hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+ if (current_index < length) {
+ sbVm_push(vm, iter_values[current_index]);
+ sbVm_push(vm, HVINT(1));
+ sbVm_call_func(vm, vm->fp->locals[2]);
+ } else {
+ /* if index was past the end, callback function won't be called, and we'll exit. return nil */
+ sbVm_push(vm, HVNIL);
+ }
+}
static void tinystr_into_buffer(char *buffer, hString handle, usize max_length) {
/* we have max_length because we may need to cut off early in some corner cases,
* like getting a mutable ptr of length 3 for a tinystr of length 6 */
- if (!is_tinystr(handle)) PANIC("%llx is not a tinystr! can't parse!", handle);
+ if (!is_tinystr(handle)) PANIC("%llx is not a tinystr! can't parse!", (long long)handle);
usize index = 0;
usize tinylength = tinystr_length(handle);
hString handle_to_eat = handle;
- if (tinylength >= REQ_ALLOC_LENGTH) PANIC("%llx has improper tinylength %zu", handle, tinylength);
+ if (tinylength >= REQ_ALLOC_LENGTH) PANIC("%llx has improper tinylength %zu", (long long)handle, tinylength);
/* string is stored backwards because it's easiest to just get the low byte */
while (index < tinylength && index < max_length) {
/* return already existing symbol */
return result.symbol;
} else {
- PANIC("Only symbol values are allowed in the symbol table! (%lld)", result.type);
+ PANIC("Only symbol values are allowed in the symbol table! (%lld)", (long long)result.type);
}
}
#include "data/closure.h"
void call_block(hVm vm, usize block_id, hClosure closure);
+void return_from_block(hVm vm);
void execute_instruction(hVm vm);
void push_stack(hVm vm, const hV *value);
hV pop_stack(hVm vm);
call_block(vm, func.type, func.closure);
}
+void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func) {
+ sbVmStackFrame frame = {
+ .return_addr = vm->ip,
+ .last_fp = vm->fp,
+ .last_rp = vm->rp,
+ .is_c_func = TRUE,
+ .c_func = func,
+ };
+ *(sbVmStackFrame*)vm->rp = frame;
+ vm->fp = (sbVmStackFrame*)vm->rp;
+ vm->rp += sizeof(sbVmStackFrame);
+
+ func(vm, TRUE);
+
+ if (vm->fp->is_c_func) {
+ /* if c_func didn't call another callback, return from it */
+ return_from_block(vm);
+ }
+}
+
+void sbVm_request_var_space(hVm vm, usize amount) {
+ /* have to set new rstack space to 0 so we don't accidentally decrement
+ * the ref count of variables from a previous stack frame (or of just garbage) */
+ memset(vm->rp, 0, amount * sizeof(hV));
+ vm->rp += amount * sizeof(hV);
+ vm->fp->num_locals += amount;
+}
+
/* --- */
void call_block(hVm vm, usize block_id, hClosure closure) {
.return_addr = vm->ip,
.last_fp = vm->fp,
.last_rp = vm->rp,
- .block = blk,
- .closure = closure,
+ .block_func.block = blk,
+ .block_func.closure = closure,
};
*(sbVmStackFrame*)vm->rp = frame;
vm->fp = (sbVmStackFrame*)vm->rp;
vm->fp = frame->last_fp;
vm->rp = frame->last_rp;
vm->ip = frame->return_addr;
+
+ if (vm->fp->is_c_func) {
+ /* if we returned into a c-function call frame, go back to the c-function */
+ vm->fp->c_func(vm, FALSE);
+
+ if (vm->fp->is_c_func) {
+ /* c-function didn't make a callback, so is done */
+ return_from_block(vm);
+ }
+ }
}
}
void debug_print_hv(const hV *value) {
- debug("%016llx %016llx\n", *(u64*)value, *((u64*)value+1));
+ debug("%016llx %016llx\n", *(long long*)value, *((long long*)value+1));
}
void store_local(hVm vm, usize local_index, const hV *value) {
}
sbOpcode get_opcode(hVm vm) {
- if (vm->ip >= vm->fp->block->bytecode_end) PANIC("execution outside defined code area");
+ if (vm->ip >= vm->fp->block_func.block->bytecode_end) PANIC("execution outside defined code area");
return *(vm->ip++);
}
* in big-endian format */
i64 get_param(hVm vm) {
u64 result = *((u8*)vm->ip++);
- if (vm->debugmode) debug("%02llX ", result);
+ if (vm->debugmode) debug("%02llX ", (long long)result);
i64 signed_result = result;
if (result == BC_LONG_NUM) {
break;
case BC_LD_CONST:
param = get_param(vm);
- push_stack(vm, &vm->fp->block->constants[param]);
+ push_stack(vm, &vm->fp->block_func.block->constants[param]);
break;
case BC_LD_CTX:
PANIC("todo");
case BC_LD_UPVAL:
/* Hey, was there upval in there? */
param = get_param(vm);
- v = sbClosure_get_var(vm->fp->closure, param);
+ v = sbClosure_get_var(vm->fp->block_func.closure, param);
push_stack(vm, v);
break;
case BC_LD_UPREF:
param = get_param(vm);
- res = sbClosure_get_ref(vm->fp->closure, param);
+ res = sbClosure_get_ref(vm->fp->block_func.closure, param);
push_stack(vm, &res);
break;
case BC_LD_BLK:
param = get_param(vm);
v = &vm->fp->locals[param];
if (v->type != IT_REF) {
- CHECK("indirect variables should be of type reference! (%lld)", v->type);
+ CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type);
}
w = sbRef_deref(v->ref);
push_stack(vm, w);
case BC_ST_UPVAL:
param = get_param(vm);
vv = pop_stack(vm);
- sbClosure_set_var(vm->fp->closure, param, &vv);
+ sbClosure_set_var(vm->fp->block_func.closure, param, &vv);
break;
case BC_ST_IND:
param = get_param(vm);
} else if (v->type == IT_REF) {
sbRef_set_ref(v->ref, w);
} else {
- CHECK("indirect variables should be of type reference! (%lld)", v->type);
+ CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type);
}
pop_stack(vm);
break;
} else if (v->type == IT_REF) {
sbRef_set_ref(v->ref, w);
} else {
- CHECK("indirect variables should be of type reference! (%lld)", v->type);
+ CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type);
}
pop_stack(vm);
xx.integer --;
break;
case BC_JMP:
param = get_param(vm);
- vm->ip = &vm->fp->block->bytecode[param];
+ vm->ip = &vm->fp->block_func.block->bytecode[param];
break;
case BC_JT:
param = get_param(vm);
vv = pop_stack(vm);
if (!sbV_c_falsy(&vv)) {
- vm->ip = &vm->fp->block->bytecode[param];
+ vm->ip = &vm->fp->block_func.block->bytecode[param];
}
break;
case BC_JF:
param = get_param(vm);
vv = pop_stack(vm);
if (sbV_c_falsy(&vv)) {
- vm->ip = &vm->fp->block->bytecode[param];
+ vm->ip = &vm->fp->block_func.block->bytecode[param];
}
break;
case BC_RET:
case BC_ALLOC_VARS:
/* TODO check for overflow */
param = get_param(vm);
- /* have to set new rstack space to 0 so we don't accidentally decrement
- * the ref count of variables from a previous stack frame (or of just garbage) */
- memset(vm->rp, 0, param * sizeof(hV));
- /* we allocate one more variable at 0 for internal use */
- vm->rp += (param + 1) * sizeof(hV);
- vm->fp->num_locals += param;
+ sbVm_request_var_space(vm, param);
break;
case BC_CLOSURE:
param = get_param(vm);
* have previously been being manipulated using the IND instructions */
w = peek_stack(vm, 0);
if (w->type != IT_REF) {
- CHECK("internal violation: closure should receive a set of reference variables (got %lld)", w->type);
+ CHECK("internal violation: closure should receive a set of reference variables (got %lld)", (long long)w->type);
}
sbClosure_set_ref(c, param, w);
pop_stack(vm);
/* Also these stacks grow upwards in memory, from low to high addresses. */
+typedef void (*sbRuntimeCFunc)(hVm, flag init);
+
typedef enum sbVmStatus {
VM_STAT_UNKNOWN,
VM_STAT_SUCCESS,
const u8 *return_addr;
struct sbVmStackFrame *last_fp;
u8 *last_rp;
- const sbVmBlock *block;
- hClosure closure;
+ flag is_c_func;
+ union {
+ struct {
+ const sbVmBlock *block;
+ hClosure closure;
+ } block_func;
+ sbRuntimeCFunc c_func;
+ };
usize num_locals;
hV locals[];
} sbVmStackFrame;
hV *sbVm_peek(hVm vm, usize where);
void sbVm_call_func(hVm vm, hV func);
+
+void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func);
+
+void sbVm_request_var_space(hVm vm, usize amount);
if (a->type == IT_INTEGER && b->type == IT_INTEGER) {
return sbV_int(sbInteger_sum(a->integer, b->integer));
} else {
- PANIC("todo (add type %llu and type %llu)", a->type, b->type);
+ PANIC("todo (add type %llu and type %llu)", (long long)a->type, (long long)b->type);
}
}
if (a->type == IT_INTEGER && b->type == IT_INTEGER) {
return sbV_int(sbInteger_diff(a->integer, b->integer));
} else {
- PANIC("todo (subtract type %llu minus %llu)", a->type, b->type);
+ PANIC("todo (subtract type %llu minus %llu)", (long long)a->type, (long long)b->type);
}
}
if (a->type == IT_LIST && b->type == IT_INTEGER) {
return sbList_index(a->list, b->integer);
} else {
- PANIC("todo %lld %lld", a->type, b->type);
+ PANIC("todo %lld %lld", (long long)a->type, (long long)b->type);
}
}
if (obj->type == IT_HASH) {
return sbHash_find(obj->hash, key);
} else {
- PANIC("todo %lld", obj->type);
+ PANIC("todo %lld", (long long)obj->type);
}
}
if (obj->type == IT_HASH) {
sbHash_insert(obj->hash, key, value);
} else {
- PANIC("todo %lld", obj->type);
+ PANIC("todo %lld", (long long)obj->type);
}
}