| } | } | ||||
| } | } | ||||
| // 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_vm_value_type(func); | |||||
| // C functions are called differently from language functions | |||||
| if (typ == L2_VAL_TYPE_CFUNCTION) { | |||||
| vm->stack[vm->sptr++] = func->cfunc(vm, argc, argv); | |||||
| return; | |||||
| } | |||||
| // Don't interpret a non-function as a function | |||||
| if (typ != L2_VAL_TYPE_FUNCTION) { | |||||
| vm->stack[vm->sptr++] = l2_vm_error(vm, "Attempt to call non-function"); | |||||
| return; | |||||
| } | |||||
| l2_word arr_id = alloc_val(vm); | |||||
| vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY; | |||||
| vm->values[arr_id].array = malloc( | |||||
| sizeof(struct l2_vm_array) + sizeof(l2_word) * argc); | |||||
| struct l2_vm_array *arr = vm->values[arr_id].array; | |||||
| arr->len = argc; | |||||
| arr->size = argc; | |||||
| for (l2_word i = 0; i < argc; ++i) { | |||||
| arr->data[i] = argv[i]; | |||||
| } | |||||
| 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; | |||||
| } | |||||
| void l2_vm_step(struct l2_vm *vm) { | void l2_vm_step(struct l2_vm *vm) { | ||||
| enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++]; | enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++]; | ||||
| l2_word *argv = vm->stack + vm->sptr; | l2_word *argv = vm->stack + vm->sptr; | ||||
| l2_word func_id = vm->stack[--vm->sptr]; | l2_word func_id = vm->stack[--vm->sptr]; | ||||
| struct l2_vm_value *func = &vm->values[func_id]; | |||||
| l2_word stack_base = vm->sptr; | |||||
| enum l2_value_type typ = l2_vm_value_type(func); | |||||
| // C functions are called differently from language functions | |||||
| if (typ == L2_VAL_TYPE_CFUNCTION) { | |||||
| vm->stack[vm->sptr++] = func->cfunc(vm, argc, argv); | |||||
| break; | |||||
| } | |||||
| // Don't interpret a non-function as a function | |||||
| if (typ != L2_VAL_TYPE_FUNCTION) { | |||||
| vm->stack[vm->sptr++] = l2_vm_error(vm, "Attempt to call non-function"); | |||||
| break; | |||||
| } | |||||
| l2_word arr_id = alloc_val(vm); | |||||
| vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY; | |||||
| vm->values[arr_id].array = malloc( | |||||
| sizeof(struct l2_vm_array) + sizeof(l2_word) * argc); | |||||
| struct l2_vm_array *arr = vm->values[arr_id].array; | |||||
| arr->len = argc; | |||||
| arr->size = argc; | |||||
| for (l2_word i = 0; i < argc; ++i) { | |||||
| arr->data[i] = argv[i]; | |||||
| } | |||||
| 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(vm, func_id, argc, argv); | |||||
| } | } | ||||
| break; | break; | ||||
| l2_word func_id = vm->stack[--vm->sptr]; | l2_word func_id = vm->stack[--vm->sptr]; | ||||
| l2_word lhs = vm->stack[--vm->sptr]; | l2_word lhs = vm->stack[--vm->sptr]; | ||||
| struct l2_vm_value *func = &vm->values[func_id]; | |||||
| l2_word stack_base = vm->sptr; | |||||
| enum l2_value_type typ = l2_vm_value_type(func); | |||||
| // C functions are called differently from language functions | |||||
| if (typ == L2_VAL_TYPE_CFUNCTION) { | |||||
| l2_word argv[] = { lhs, rhs }; | |||||
| vm->stack[vm->sptr++] = func->cfunc(vm, 2, argv); | |||||
| break; | |||||
| } | |||||
| // Don't interpret a non-function as a function | |||||
| if (typ != L2_VAL_TYPE_FUNCTION) { | |||||
| vm->stack[vm->sptr++] = l2_vm_error(vm, "Attempt to call non-function"); | |||||
| break; | |||||
| } | |||||
| l2_word arr_id = alloc_val(vm); | |||||
| vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY; | |||||
| vm->values[arr_id].array = malloc( | |||||
| sizeof(struct l2_vm_array) + sizeof(l2_word) * 2); | |||||
| struct l2_vm_array *arr = vm->values[arr_id].array; | |||||
| arr->len = 2; | |||||
| arr->size = 2; | |||||
| arr->data[0] = lhs; | |||||
| arr->data[1] = rhs; | |||||
| 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; | |||||
| l2_word argv[] = {lhs, rhs}; | |||||
| call_func(vm, func_id, 2, argv); | |||||
| } | } | ||||
| break; | break; | ||||