#include #include #include #include #include #include #include #include #include #include #include #include #include char last_err[512]; char internal_error[256]; size_t last_jmp_ip = 0; size_t total_jmp_on_same = 0; fzl_vm_t *fzl_mkvm(fzl_vm_reader_t *reader) { if (!reader) { snprintf(last_err, sizeof(last_err), "reader is not provided"); return NULL; } fzl_vm_t *vm = malloc(sizeof(fzl_vm_t)); if (!vm) { snprintf(last_err, sizeof(last_err), "failed to allocate vm"); return NULL; } memset(vm, 0, sizeof(fzl_vm_t)); vm->reader = reader; return vm; } void print_object(fzl_vm_object_t *obj) { if (!obj) { printf("\n"); return; } printf("obj<"); for (size_t i = 0; i < obj->values_count; i++) { fzl_value_t arg = obj->values[i]; if (i > 0) printf(", "); if (arg.type == FZL_TYPE_STRING) printf("str(%s)", arg.as.s.value); else if (arg.type == FZL_TYPE_CHAR) printf("char(%c)", arg.as.c); else if (arg.type == FZL_TYPE_INT) printf("int(%ld)", arg.as.i); else if (arg.type == FZL_TYPE_UINT) printf("uint(%lu)", arg.as.u); else if (arg.type == FZL_TYPE_BOOL) printf("bool(%s)", arg.as.b ? "true" : "false"); else if (arg.type == FZL_TYPE_NULL) printf(""); else if (arg.type == FZL_TYPE_OBJECT) print_object(arg.as.obj); else printf(""); } printf(">"); } void print_err_data(fzl_vm_t *vm) { printf("===== ERROR =====\n"); printf("> Caused on IP: %zu\n", vm->ip); printf("\n> Data stack:\n"); if (vm->dtop > 0) { for (ssize_t i = vm->dtop - 1; i >= 0; i--) { printf("\t> [%d] ", vm->dstack[i].type); switch (vm->dstack[i].type) { case FZL_TYPE_OBJECT: printf("ref: %p\n", vm->dstack[i].as.obj); break; case FZL_TYPE_STRING: printf("str: '%s'\n", vm->dstack[i].as.s.value); break; case FZL_TYPE_NULL: printf("\n"); break; default: printf("%lu\n", vm->dstack[i].as.u); break; } } } else { printf("\tEmpty\n"); } printf("\n> Environments:\n"); for (ssize_t i = vm->etop - 1; i >= 0; i--) { fzl_vm_env_t *env = vm->estack[i]; printf("\t> [%zd] %p:\n", i, env); printf("\t\t> Owned objects (%zu/%zu):\n", env->owned_objects_count, env->owned_objects_remainder); for (size_t j = 0; j < env->owned_objects_count; j++) printf("\t\t\t> ref: %p (entries: %zu)\n", env->owned_objects[j], env->owned_objects[j]->values_count); printf("\t\t> Local entries (%zu/%zu):\n", env->size, env->remainder); for (size_t j = 0; j < env->size; j++) { switch (env->table[j].value.type) { case FZL_TYPE_OBJECT: printf("\t\t\t> [%d] %s = ref %p\n", env->table[j].value.type, env->table[j].name, env->table[j].value.as.obj); break; default: printf("\t\t\t> [%d] %s = %lu\n", env->table[j].value.type, env->table[j].name, env->table[j].value.as.u); break; } } } printf("\n> Call stack:\n"); for (ssize_t i = vm->ctop - 1; i >= 0; i--) printf("\t> [%zd] %lu\n", i, vm->cstack[i]); } int fzl_vm_run(fzl_vm_t *vm) { if (!vm) { snprintf(last_err, sizeof(last_err), "vm is null"); return -1; } vm->ip = 0; int result = 0; while (vm->ip < vm->reader->ops_count) { fzl_opcode_t opcode = vm->reader->ops[vm->ip]; size_t op_group = (opcode >> 16) & 0xFF; size_t op_fnnum = (opcode & 0xFF); if (master_tbl[op_group] == NULL || master_tbl[op_group][op_fnnum] == NULL) { snprintf(last_err, sizeof(last_err), "runtime error - unknown opcode %u", opcode); print_err_data(vm); return -1; } opcode_handler handler = master_tbl[op_group][op_fnnum]; result = handler(vm); if (result != 0) return result; vm->ip++; } return 0; } char *fzl_vm_geterror() { return last_err; } void fzl_freevm(fzl_vm_t *vm) { if (!vm) return; while (vm->etop > 0) fzl_freeenv(vm->estack[--vm->etop]); free(vm); }