226 lines
5.7 KiB
C
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;
|
|
}
|