- Feat: add usage of vm reader instead of old way in vm.c - Ref: update debug opcodes printing
203 lines
4.6 KiB
C
203 lines
4.6 KiB
C
#include "common/fzl_types.h"
|
|
#include <common/fzl_value.h>
|
|
#include <stdio.h>
|
|
#include <vm/fzl_vm.h>
|
|
#include <vm/fzl_vm_env.h>
|
|
#include <vm/internals/opcode.h>
|
|
|
|
// 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;
|
|
}
|