Files
fz-lang/src/vm/fzl_vm.c
T

194 lines
4.4 KiB
C

#include <common/fzl_opcodes.h>
#include <common/fzl_types.h>
#include <common/fzl_value.h>
#include <compiler/utils/fzl_const_pool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vm/fzl_vm.h>
#include <vm/fzl_vm_env.h>
#include <vm/fzl_vm_object.h>
#include <vm/fzl_vm_reader.h>
#include <vm/internals/opcode.h>
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("<null>\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("<null>");
else if (arg.type == FZL_TYPE_OBJECT)
print_object(arg.as.obj);
else
printf("<unknown>");
}
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("<null>\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);
}