#include "common/fzl_types.h" #include #include #include #include #include // Allocate environment table and increment scope level int op_mk_envtable(fzl_vm_t *vm) { vm->estack[vm->etop++] = fzl_mkenv(); return 0; } // Remove environment table and decrement scope level int op_rm_envtable(fzl_vm_t *vm) { fzl_freeenv(vm->estack[--vm->etop]); return 0; } // Store new variable int op_store(fzl_vm_t *vm) { if (vm->dtop < 1) { snprintf(last_err, sizeof(last_err), "runtime error - expected var name in data stack"); print_err_data(vm); return -1; } fzl_value_t varname = vm->dstack[--vm->dtop]; fzl_env_storevalue(vm->estack[vm->etop - 1], (char *)varname.as.s.value, (fzl_value_t){}); return 0; } // Lookup environment(s) for variable using name on stack int op_lookup_env(fzl_vm_t *vm) { if (vm->dtop < 1) { snprintf(last_err, sizeof(last_err), "runtime error - LOOKUP_ENV: empty data stack"); print_err_data(vm); return -1; } fzl_value_t val = vm->dstack[--vm->dtop]; fzl_value_t env_val; bool result; for (ssize_t i = vm->etop - 1; i >= 0; i--) { if ((result = fzl_env_lookup(vm->estack[i], (char *)val.as.s.value, &env_val))) break; } vm->dstack[vm->dtop++] = env_val; return 0; } // Writable variable value int op_write(fzl_vm_t *vm) { if (vm->dtop < 2) { snprintf(last_err, sizeof(last_err), "runtime error - expected 2 values in data stack"); print_err_data(vm); return -1; } fzl_value_t writevar = vm->dstack[--vm->dtop]; fzl_value_t value = vm->dstack[--vm->dtop]; char *wrname = (char *)writevar.as.s.value; bool wrfound; fzl_value_t wrenv; ssize_t wrlvl = -1; for (ssize_t i = vm->etop - 1; i >= 0; i--) { if ((wrfound = fzl_env_lookup(vm->estack[i], wrname, &wrenv))) { wrlvl = i; break; } } if (wrlvl <= -1) { snprintf(last_err, sizeof(last_err), "runtime error - name '%s' not found in this scope", wrname); print_err_data(vm); return -1; } fzl_vm_env_wresult_t wresult = fzl_env_writevalue(vm->estack[wrlvl], (char *)wrname, value); if (wresult != FZL_VM_ENV_WRESULT_OK) { switch (wresult) { case FZL_VM_ENV_WRESULT_ERR: snprintf(last_err, sizeof(last_err), "runtime error - failed to write variable"); print_err_data(vm); return -1; case FZL_VM_ENV_WRESULT_ERR_EXISTS: snprintf(last_err, sizeof(last_err), "runtime error - redefenition of '%s'", writevar.as.s.value); print_err_data(vm); return -1; case FZL_VM_ENV_WRESULT_ERR_NOT_FOUND: snprintf(last_err, sizeof(last_err), "runtime error - cannot find name '%s'", writevar.as.s.value); print_err_data(vm); return -1; default: print_err_data(vm); return -1; } } return 0; } int op_load_local(fzl_vm_t *vm) { size_t depth = vm->reader->ops[++vm->ip]; size_t slot = vm->reader->ops[++vm->ip]; if (depth >= vm->etop) { snprintf(last_err, sizeof(last_err), "runtime error - local depth out of range"); print_err_data(vm); return -1; } fzl_vm_env_t *env = vm->estack[vm->etop - 1 - depth]; if (env->size <= slot) { snprintf(last_err, sizeof(last_err), "runtime error - local slot out of range"); print_err_data(vm); return -1; } vm->dstack[vm->dtop++] = env->table[slot].value; return 0; } int op_store_local(fzl_vm_t *vm) { if (vm->dtop < 1) { snprintf(last_err, sizeof(last_err), "runtime error - expected value in data stack"); print_err_data(vm); return -1; } fzl_value_t value = vm->dstack[--vm->dtop]; size_t depth = vm->reader->ops[++vm->ip]; size_t slot = vm->reader->ops[++vm->ip]; if (depth >= vm->etop) { snprintf(last_err, sizeof(last_err), "runtime error - local depth out of range"); print_err_data(vm); return -1; } fzl_vm_env_t *env = vm->estack[vm->etop - 1 - depth]; if (env->size <= slot) { snprintf(last_err, sizeof(last_err), "runtime error - local slot out of range"); print_err_data(vm); return -1; } if (value.type == FZL_TYPE_OBJECT && depth != 0) { for (size_t i = 0; i < depth; i++) { escape_recursive(vm->estack[vm->etop - i], vm->estack[vm->etop - 1 - i], value.as.obj); } } env->table[slot].value = value; return 0; }