#include #include #include #include // Escape objects with nested objects check void escape_recursive(fzl_vm_env_t *current, fzl_vm_env_t *parent, fzl_vm_object_t *obj) { if (!current || !parent || !obj) return; bool found_in_current = false; for (size_t i = 0; i < current->owned_objects_count; i++) { if (current->owned_objects[i] == obj) { current->owned_objects[i] = NULL; found_in_current = true; break; } } if (found_in_current) { bool found_in_parent = false; for (size_t i = 0; i < parent->owned_objects_count; i++) { if (parent->owned_objects[i] == obj) { found_in_parent = true; break; } } if (!found_in_parent) { if (parent->owned_objects_remainder <= parent->owned_objects_count) { parent->owned_objects_remainder *= 2; parent->owned_objects = realloc(parent->owned_objects, parent->owned_objects_remainder * sizeof(fzl_vm_object_t *)); } parent->owned_objects[parent->owned_objects_count++] = obj; } } for (size_t i = 0; i < obj->values_count; i++) { if (obj->values[i].type == FZL_TYPE_OBJECT && obj->values[i].as.obj != NULL) escape_recursive(current, parent, obj->values[i].as.obj); } } // Allocate specified count of fields and create object int op_alloc_object(fzl_vm_t *vm) { uint64_t values_count = vm->ops[++vm->ip]; fzl_vm_object_t *obj = malloc(sizeof(fzl_vm_object_t)); if (values_count < 1) values_count = 1; obj->values = malloc(values_count * sizeof(fzl_value_t)); obj->values_count = values_count; memset(obj->values, 0, values_count * sizeof(fzl_value_t)); fzl_vm_env_t *current_env = vm->estack[vm->etop - 1]; if (current_env->owned_objects_remainder <= current_env->owned_objects_count) { current_env->owned_objects_remainder *= 2; current_env->owned_objects = realloc(current_env->owned_objects, current_env->owned_objects_remainder * sizeof(fzl_vm_object_t *)); } current_env->owned_objects[current_env->owned_objects_count++] = obj; vm->dstack[vm->dtop++] = (fzl_value_t){.type = FZL_TYPE_OBJECT, .as.obj = obj}; return 0; } // Pop object from stack and push its field value int op_get_field(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; } uint64_t field_slot = vm->ops[++vm->ip]; fzl_value_t val = vm->dstack[--vm->dtop]; if (val.type != FZL_TYPE_OBJECT) { snprintf(last_err, sizeof(last_err), "runtime error - cannot access field #%lu of non-object type", field_slot); print_err_data(vm); return -1; } fzl_vm_object_t *obj = val.as.obj; if (obj->values_count <= field_slot) { snprintf(last_err, sizeof(last_err), "runtime error - cannot access field #%lu", field_slot); print_err_data(vm); return -1; } vm->dstack[vm->dtop++] = obj->values[field_slot]; return 0; } // Pop object and write value from stack and write value into objects' field int op_set_field(fzl_vm_t *vm) { if (vm->dtop < 2) { snprintf(last_err, sizeof(last_err), "runtime error - expected two values in data stack"); print_err_data(vm); return -1; } uint64_t field_slot = vm->ops[++vm->ip]; fzl_value_t objval = vm->dstack[--vm->dtop]; fzl_value_t wrval = vm->dstack[--vm->dtop]; if (objval.type != FZL_TYPE_OBJECT) { snprintf(last_err, sizeof(last_err), "runtime error - cannot access field #%lu of non-object type", field_slot); print_err_data(vm); return -1; } fzl_vm_object_t *obj = objval.as.obj; if (obj->values_count <= field_slot) { snprintf(last_err, sizeof(last_err), "runtime error - cannot access field #%lu", field_slot); print_err_data(vm); return -1; } obj->values[field_slot] = wrval; return 0; } // Escape object to the parent scope int op_escape_object(fzl_vm_t *vm) { if (vm->dtop < 1) { snprintf(last_err, sizeof(last_err), "runtime error - missing value in data stack"); print_err_data(vm); return -1; } fzl_value_t obj = vm->dstack[--vm->dtop]; if (obj.type != FZL_TYPE_OBJECT) { snprintf(last_err, sizeof(last_err), "runtime error - cannot escape non-object type"); print_err_data(vm); return -1; } fzl_vm_env_t *parent = vm->estack[vm->etop - 2]; fzl_vm_env_t *current = vm->estack[vm->etop - 1]; if (vm->etop < 2) { snprintf(last_err, sizeof(last_err), "runtime error - cannot escape object from global env"); print_err_data(vm); return -1; } escape_recursive(current, parent, obj.as.obj); vm->dstack[vm->dtop++] = obj; return 0; } // Pop value from data stack and store dereferenced value int op_dereference(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 addr = vm->dstack[--vm->dtop]; if (addr.type < FZL_TYPE_INT8) { snprintf(last_err, sizeof(last_err), "runtime error - expected address"); print_err_data(vm); return -1; } if (addr.as.u == 0) { vm->dstack[vm->dtop++] = (fzl_value_t){.type = FZL_TYPE_OBJECT, .as.obj = NULL}; } else { vm->dstack[vm->dtop++] = (fzl_value_t){ .type = FZL_TYPE_OBJECT, .as.obj = (fzl_vm_object_t *)addr.as.u}; } return 0; }