Kaynağa Gözat

add continuation call args, implement 'for'

master
Martin Dørum 8 ay önce
ebeveyn
işleme
652edda8e2
5 değiştirilmiş dosya ile 141 ekleme ve 42 silme
  1. 1
    0
      include/lang2/builtins.x.h
  2. 1
    0
      include/lang2/vm/vm.h
  3. 72
    2
      lib/vm/builtins.c
  4. 4
    8
      lib/vm/print.c
  5. 63
    32
      lib/vm/vm.c

+ 1
- 0
include/lang2/builtins.x.h Dosyayı Görüntüle

@@ -29,4 +29,5 @@ XFUNCTION("len", l2_builtin_len)
XFUNCTION("if", l2_builtin_if)
XFUNCTION("loop", l2_builtin_loop)
XFUNCTION("while", l2_builtin_while)
XFUNCTION("for", l2_builtin_for)
#endif

+ 1
- 0
include/lang2/vm/vm.h Dosyayı Görüntüle

@@ -39,6 +39,7 @@ enum l2_value_flags {
struct l2_vm_contcontext {
l2_vm_contcallback callback;
l2_vm_gcmarker marker;
l2_word args;
};

// The smallest size an l2_vm_value can be is 16 bytes on common platforms.

+ 72
- 2
lib/vm/builtins.c Dosyayı Görüntüle

@@ -324,6 +324,7 @@ l2_word l2_builtin_loop(struct l2_vm *vm, l2_word argc, l2_word *argv) {

ctx->base.callback = loop_callback;
ctx->base.marker = loop_marker;
ctx->base.args = vm->knone;
ctx->func = argv[0];

l2_word cont_id = l2_vm_alloc(vm, L2_VAL_TYPE_CONTINUATION, 0);
@@ -341,16 +342,20 @@ struct while_context {
static l2_word while_callback(struct l2_vm *vm, l2_word retval, l2_word cont_id) {
struct l2_vm_value *cont = &vm->values[cont_id];
struct while_context *ctx = (struct while_context *)cont->cont;
struct l2_vm_value *ret = &vm->values[retval];

if (l2_value_get_type(ret) == L2_VAL_TYPE_ERROR) {
return retval;
}

if (cont->extra.cont_call == ctx->cond) {
if (l2_vm_val_is_true(vm, &vm->values[retval])) {
if (l2_vm_val_is_true(vm, ret)) {
cont->extra.cont_call = ctx->body;
return cont_id;
} else {
return retval;
}
} else {
struct l2_vm_value *ret = &vm->values[retval];
if (l2_value_get_type(ret) == L2_VAL_TYPE_ERROR) {
return retval;
} else {
@@ -379,6 +384,7 @@ l2_word l2_builtin_while(struct l2_vm *vm, l2_word argc, l2_word *argv) {

ctx->base.callback = while_callback;
ctx->base.marker = while_marker;
ctx->base.args = vm->knone;
ctx->cond = argv[0];
ctx->body = argv[1];

@@ -388,3 +394,67 @@ l2_word l2_builtin_while(struct l2_vm *vm, l2_word argc, l2_word *argv) {
cont->cont = &ctx->base;
return cont_id;
}

struct for_context {
struct l2_vm_contcontext base;
l2_word iter;
l2_word func;
};

static l2_word for_callback(struct l2_vm *vm, l2_word retval, l2_word cont_id) {
struct l2_vm_value *cont = &vm->values[cont_id];
struct for_context *ctx = (struct for_context *)cont->cont;
struct l2_vm_value *ret = &vm->values[retval];

if (l2_value_get_type(ret) == L2_VAL_TYPE_ERROR) {
return retval;
}

struct l2_vm_value *args = &vm->values[cont->cont->args];
if (cont->extra.cont_call == ctx->iter) {
if (
l2_value_get_type(ret) == L2_VAL_TYPE_ATOM &&
ret->atom == vm->values[vm->kstop].atom) {
return vm->knone;
} else {
cont->extra.cont_call = ctx->func;
args->extra.arr_length = 1;
args->shortarray[0] = retval;
return cont_id;
}
} else {
cont->extra.cont_call = ctx->iter;
args->extra.arr_length = 0;
return cont_id;
}
}

static void for_marker(
struct l2_vm *vm, void *data, void (*mark)(struct l2_vm *vm, l2_word id)) {
struct for_context *ctx = data;
mark(vm, ctx->iter);
mark(vm, ctx->func);
}

l2_word l2_builtin_for(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc != 2) {
return l2_vm_error(vm, "Expected 2 arguments");
}

l2_word args_id = l2_vm_alloc(vm, L2_VAL_TYPE_ARRAY, L2_VAL_SBO);
struct l2_vm_value *args = &vm->values[args_id];
args->extra.arr_length = 0;

struct for_context *ctx = malloc(sizeof(*ctx));
ctx->base.callback = for_callback;
ctx->base.marker = for_marker;
ctx->base.args = args_id;
ctx->iter = argv[0];
ctx->func = argv[1];

l2_word cont_id = l2_vm_alloc(vm, L2_VAL_TYPE_CONTINUATION, 0);
struct l2_vm_value *cont = &vm->values[cont_id];
cont->extra.cont_call = ctx->iter;
cont->cont = &ctx->base;
return cont_id;
}

+ 4
- 8
lib/vm/print.c Dosyayı Görüntüle

@@ -53,15 +53,11 @@ void l2_vm_print_val(struct l2_vm_value *val) {

case L2_VAL_TYPE_ARRAY:
{
if (val->array == NULL) {
printf("ARRAY, empty\n");
return;
}

printf("ARRAY, len %u\n", val->extra.arr_length);
for (size_t i = 0; i < val->extra.arr_length; ++i) {
printf(" %zu: %u\n", i, val->array->data[i]);
}
l2_word *data = val->flags & L2_VAL_SBO ? val->shortarray : val->array->data;
for (size_t i = 0; i < val->extra.arr_length; ++i) {
printf(" %zu: %u\n", i, data[i]);
}
}
break;


+ 63
- 32
lib/vm/vm.c Dosyayı Görüntüle

@@ -49,10 +49,13 @@ static void gc_mark(struct l2_vm *vm, l2_word id) {
gc_mark_namespace(vm, val);
} else if (typ == L2_VAL_TYPE_FUNCTION) {
gc_mark(vm, val->func.ns);
} else if (
typ == L2_VAL_TYPE_CONTINUATION &&
val->cont != NULL && val->cont->marker != NULL) {
val->cont->marker(vm, val->cont, gc_mark);
} else if (typ == L2_VAL_TYPE_CONTINUATION && val->cont != NULL) {
if (val->cont->marker != NULL) {
val->cont->marker(vm, val->cont, gc_mark);
}
if (val->cont->args != 0) {
gc_mark(vm, val->cont->args);
}
}
}

@@ -103,7 +106,7 @@ static void gc_free(struct l2_vm *vm, l2_word id) {
free(val->ns);
} else if (typ == L2_VAL_TYPE_ERROR) {
free(val->error);
} else if (typ == L2_VAL_TYPE_CONTINUATION) {
} else if (typ == L2_VAL_TYPE_CONTINUATION && val->cont) {
free(val->cont);
}
}
@@ -334,14 +337,29 @@ void l2_vm_run(struct l2_vm *vm) {
}
}

static void call_func_with_args(struct l2_vm *vm, l2_word func_id, l2_word args_id) {
l2_word stack_base = vm->sptr;
vm->stack[vm->sptr++] = args_id;

l2_word ns_id = alloc_val(vm);
struct l2_vm_value *func = &vm->values[func_id]; // func might be stale after alloc_val
vm->values[ns_id].extra.ns_parent = func->func.ns;
vm->values[ns_id].ns = NULL;
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE;
vm->fstack[vm->fsptr].ns = ns_id;
vm->fstack[vm->fsptr].retptr = vm->iptr;
vm->fstack[vm->fsptr].sptr = stack_base;
vm->fsptr += 1;

vm->iptr = func->func.pos;
}

// The 'call_func' function assumes that all relevant values have been popped off
// the stack, so that the return value can be pushed to the top of the stack
// straight away
static void call_func(
struct l2_vm *vm, l2_word func_id,
l2_word argc, l2_word *argv) {
l2_word stack_base = vm->sptr;

struct l2_vm_value *func = &vm->values[func_id];
enum l2_value_type typ = l2_value_get_type(func);

@@ -369,13 +387,34 @@ static void call_func(
struct l2_vm_value *call = &vm->values[call_id];

if (l2_value_get_type(call) == L2_VAL_TYPE_CFUNCTION) {
l2_word retval = call->cfunc(vm, 0, NULL);
int argc = 0;
l2_word *argv = NULL;
if (cont->cont && cont->cont->args != 0) {
struct l2_vm_value *args = &vm->values[cont->cont->args];
if (l2_value_get_type(args) != L2_VAL_TYPE_ARRAY) {
vm->stack[vm->sptr - 1] = l2_vm_type_error(vm, args);
break;
}

argc = args->extra.arr_length;
if (args->flags & L2_VAL_SBO) {
argv = args->shortarray;
} else {
argv = args->array->data;
}
}

l2_word retval = call->cfunc(vm, argc, argv);
vm->stack[vm->sptr - 1] = cont->cont->callback(vm, retval, cont_id);
} else if (l2_value_get_type(call) == L2_VAL_TYPE_FUNCTION) {
// Leave the continuation on the stack,
// let the L2_OP_RET code deal with it
cont->flags |= L2_VAL_CONT_CALLBACK;
call_func(vm, call_id, 0, NULL);
if (cont->cont && cont->cont->args) {
call_func_with_args(vm, call_id, cont->cont->args);
} else {
call_func(vm, call_id, 0, NULL);
}
break;
} else {
l2_word err = l2_vm_type_error(vm, call);
@@ -392,33 +431,21 @@ static void call_func(
return;
}

l2_word arr_id = alloc_val(vm);
struct l2_vm_value *arr = &vm->values[arr_id];
arr->extra.arr_length = argc;
l2_word args_id = alloc_val(vm);
struct l2_vm_value *args = &vm->values[args_id];
args->extra.arr_length = argc;
if (argc <= 2) {
arr->flags = L2_VAL_TYPE_ARRAY | L2_VAL_SBO;
memcpy(arr->shortarray, argv, argc * sizeof(l2_word));
args->flags = L2_VAL_TYPE_ARRAY | L2_VAL_SBO;
memcpy(args->shortarray, argv, argc * sizeof(l2_word));
} else {
arr->flags = L2_VAL_TYPE_ARRAY;
arr->array = malloc(
args->flags = L2_VAL_TYPE_ARRAY;
args->array = malloc(
sizeof(struct l2_vm_array) + sizeof(l2_word) * argc);
arr->array->size = argc;
memcpy(arr->array->data, argv, argc * sizeof(l2_word));
args->array->size = argc;
memcpy(args->array->data, argv, argc * sizeof(l2_word));
}

vm->stack[vm->sptr++] = arr_id;

l2_word ns_id = alloc_val(vm);
func = &vm->values[func_id]; // func might be stale after alloc
vm->values[ns_id].extra.ns_parent = func->func.ns;
vm->values[ns_id].ns = NULL;
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE;
vm->fstack[vm->fsptr].ns = ns_id;
vm->fstack[vm->fsptr].retptr = vm->iptr;
vm->fstack[vm->fsptr].sptr = stack_base;
vm->fsptr += 1;

vm->iptr = func->func.pos;
call_func_with_args(vm, func_id, args_id);
}

static l2_word read_u4le(struct l2_vm *vm) {
@@ -573,7 +600,11 @@ void l2_vm_step(struct l2_vm *vm) {
}

cont->flags |= L2_VAL_CONT_CALLBACK;
call_func(vm, cont->extra.cont_call, 0, NULL);
if (cont->cont && cont->cont->args != 0) {
call_func_with_args(vm, cont->extra.cont_call, cont->cont->args);
} else {
call_func(vm, cont->extra.cont_call, 0, NULL);
}
}
break;


Loading…
İptal
Kaydet