feat: optimize VM using dispatch table
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
#include <vm/fzl_vm.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;
|
||||
}
|
||||
Reference in New Issue
Block a user