Files
fz-lang/src/vm/handlers/group_obj.c
T

226 lines
5.7 KiB
C

#include <stdlib.h>
#include <string.h>
#include <vm/fzl_vm.h>
#include <vm/internals/opcode.h>
// 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;
}