Parcourir la source

veery basic control flow

master
Martin Dørum il y a 3 ans
Parent
révision
3bf458897b
5 fichiers modifiés avec 72 ajouts et 7 suppressions
  1. 1
    0
      include/lang2/builtins.x.h
  2. 5
    5
      include/lang2/vm/vm.h
  3. 33
    2
      lib/vm/builtins.c
  4. 4
    0
      lib/vm/print.c
  5. 29
    0
      lib/vm/vm.c

+ 1
- 0
include/lang2/builtins.x.h Voir le fichier

@@ -13,4 +13,5 @@ X("*", l2_builtin_mul)
X("/", l2_builtin_div)
X("print", l2_builtin_print)
X("len", l2_builtin_len)
X("if", l2_builtin_if)
#endif

+ 5
- 5
include/lang2/vm/vm.h Voir le fichier

@@ -9,13 +9,8 @@

struct l2_vm;
struct l2_vm_array;
struct l2_vm_args;
typedef l2_word (*l2_vm_cfunction)(struct l2_vm *vm, l2_word argc, l2_word *argv);

struct l2_vm_args {
l2_word argc;
};

enum l2_value_type {
L2_VAL_TYPE_NONE,
L2_VAL_TYPE_ATOM,
@@ -25,6 +20,7 @@ enum l2_value_type {
L2_VAL_TYPE_NAMESPACE,
L2_VAL_TYPE_FUNCTION,
L2_VAL_TYPE_CFUNCTION,
L2_VAL_TYPE_CONTINUATION,
L2_VAL_TYPE_ERROR,
};

@@ -60,6 +56,10 @@ struct l2_vm_value {
l2_word ns;
} func;
l2_vm_cfunction cfunc;
struct {
l2_word call;
l2_word arg;
} cont;
char *error;
};
};

+ 33
- 2
lib/vm/builtins.c Voir le fichier

@@ -57,6 +57,10 @@ static void print_val(struct l2_vm *vm, struct l2_io_writer *out, struct l2_vm_v
case L2_VAL_TYPE_ERROR:
l2_io_printf(out, "(error: %s)", val->error);
break;

case L2_VAL_TYPE_CONTINUATION:
l2_io_printf(out, "(continuation)");
break;
}
}

@@ -175,8 +179,8 @@ l2_word l2_builtin_print(struct l2_vm *vm, l2_word argc, l2_word *argv) {
}

l2_word l2_builtin_len(struct l2_vm *vm, l2_word argc, l2_word *argv) {
if (argc < 1) {
return l2_vm_error(vm, "Expected at least 1 argument");
if (argc != 1) {
return l2_vm_error(vm, "Expected 1 argument");
}

l2_word ret_id = l2_vm_alloc(vm, L2_VAL_TYPE_REAL, 0);
@@ -191,6 +195,7 @@ l2_word l2_builtin_len(struct l2_vm *vm, l2_word argc, l2_word *argv) {
case L2_VAL_TYPE_FUNCTION:
case L2_VAL_TYPE_CFUNCTION:
case L2_VAL_TYPE_ERROR:
case L2_VAL_TYPE_CONTINUATION:
break;

case L2_VAL_TYPE_BUFFER:
@@ -213,3 +218,29 @@ l2_word l2_builtin_len(struct l2_vm *vm, l2_word argc, l2_word *argv) {

return ret_id;
}

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

struct l2_vm_value *cond = &vm->values[argv[0]];

if (
l2_vm_value_type(cond) == L2_VAL_TYPE_ATOM &&
cond->atom == vm->values[vm->ktrue].atom) {
l2_word ret_id = l2_vm_alloc(vm, L2_VAL_TYPE_CONTINUATION, 0);
struct l2_vm_value *ret = &vm->values[ret_id];
ret->cont.call = argv[1];
ret->cont.arg = 0;
return ret_id;
} else if (argc == 3) {
l2_word ret_id = l2_vm_alloc(vm, L2_VAL_TYPE_CONTINUATION, 0);
struct l2_vm_value *ret = &vm->values[ret_id];
ret->cont.call = argv[2];
ret->cont.arg = 0;
return ret_id;
} else {
return 0;
}
}

+ 4
- 0
lib/vm/print.c Voir le fichier

@@ -76,6 +76,10 @@ void l2_vm_print_val(struct l2_vm_value *val) {
case L2_VAL_TYPE_ERROR:
printf("ERROR, %s\n", val->error);
break;

case L2_VAL_TYPE_CONTINUATION:
printf("CONTINUATION, call %u, arg %u\n", val->cont.call, val->cont.arg);
break;
}
}


+ 29
- 0
lib/vm/vm.c Voir le fichier

@@ -137,6 +137,7 @@ const char *l2_value_type_name(enum l2_value_type typ) {
case L2_VAL_TYPE_FUNCTION: return "FUNCTION";
case L2_VAL_TYPE_CFUNCTION: return "CFUNCTION";
case L2_VAL_TYPE_ERROR: return "ERROR";
case L2_VAL_TYPE_CONTINUATION: return "CONTINUATION";
}

return "(unknown)";
@@ -297,7 +298,35 @@ static void call_func(

// C functions are called differently from language functions
if (typ == L2_VAL_TYPE_CFUNCTION) {
// Make this a while loop, because using call_func would
// make the call stack depth unbounded
vm->stack[vm->sptr++] = func->cfunc(vm, argc, argv);
while (1) {
struct l2_vm_value *val = &vm->values[vm->stack[vm->sptr - 1]];
if (l2_vm_value_type(val) != L2_VAL_TYPE_CONTINUATION) {
break;
}

l2_word cont_id = val->cont.call;
struct l2_vm_value *cont = &vm->values[cont_id];

l2_word new_argc;
l2_word new_argv[1];
if (val->cont.arg == 0) {
new_argc = 0;
} else {
new_argc = 1;
new_argv[0] = val->cont.arg;
}

if (l2_vm_value_type(cont) == L2_VAL_TYPE_CFUNCTION) {
vm->stack[vm->sptr - 1] = cont->cfunc(vm, new_argc, new_argv);
} else {
vm->sptr -= 1;
call_func(vm, cont_id, new_argc, new_argv);
break;
}
}
return;
}


Chargement…
Annuler
Enregistrer