diff options
author | Elias Fleckenstein <eliasfleckenstein@web.de> | 2021-12-30 14:18:15 +0100 |
---|---|---|
committer | Elias Fleckenstein <eliasfleckenstein@web.de> | 2021-12-30 14:18:15 +0100 |
commit | ecc06c082036aa93f6810ec21e73610c55f5a57b (patch) | |
tree | aff479c3bc5b39ead9f65dffb01d399b341fa4ba /api/vm.c | |
download | uwu-lang-ecc06c082036aa93f6810ec21e73610c55f5a57b.tar.xz |
Initial commit
Diffstat (limited to 'api/vm.c')
-rw-r--r-- | api/vm.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/api/vm.c b/api/vm.c new file mode 100644 index 0000000..547805c --- /dev/null +++ b/api/vm.c @@ -0,0 +1,104 @@ +#include <stdio.h> +#include <stdlib.h> +#include "../src/err.h" +#include "vm.h" +#include "str.h" +#include "int.h" + +void uwuvm_free_value(UwUVMValue value) +{ + if (value.type == VT_STR) + free(value.value.str_value); + else if (value.type == VT_NAT) + value.value.nat_value.type->delete(value.value.nat_value.data); +} + +void uwuvm_free_args(UwUVMArgs *args) +{ + if (args->evaluated) { + for (size_t i = 0; i < args->num; i++) { + UwUVMValue *value = args->evaluated[i]; + + if (value) { + uwuvm_free_value(*value); + free(value); + } + } + + free(args->evaluated); + } +} + +UwUVMValue uwuvm_copy_value(UwUVMValue value) +{ + if (value.type == VT_STR) + return uwustr_create(value.value.str_value); + else if (value.type == VT_NAT) + return (UwUVMValue) { + .type = value.type, + .value = { + .nat_value = { + .type = value.value.nat_value.type, + .data = value.value.nat_value.type->copy(value.value.nat_value.data), + } + } + }; + else + return value; +} + +UwUVMValue uwuvm_get_arg(UwUVMArgs *args, size_t i) +{ + if (! args->evaluated[i]) { + args->evaluated[i] = malloc(sizeof(UwUVMValue)); + *(args->evaluated[i]) = uwuvm_evaluate_expression(&args->unevaluated[i], args->super); + } + + return *(args->evaluated[i]); +} + +UwUVMValue uwuvm_evaluate_expression(UwUVMExpression *expression, UwUVMArgs *args) +{ + switch (expression->type) { + case EX_INTLIT: + return uwuint_create(expression->value.int_value); + + case EX_STRLIT: + return uwustr_create(expression->value.str_value); + + case EX_ARGNUM: + if ((size_t) expression->value.int_value >= args->num) + error("error: not enough arguments (accessed argument $%d, but only %lu arguments were passed)\n", expression->value.int_value, args->num); + + return uwuvm_copy_value(uwuvm_get_arg(args, expression->value.int_value)); + + case EX_FNNAME: + return (UwUVMValue) { + .type = VT_REF, + .value = { + .ref_value = expression->value.ref_value, + }, + }; + + case EX_FNCALL: + return uwuvm_run_function(expression->value.cll_value.function, (UwUVMArgs) { + .num = expression->value.cll_value.num_args, + .evaluated = expression->value.cll_value.num_args == 0 ? NULL : calloc(expression->value.cll_value.num_args, sizeof(UwUVMValue *)), + .unevaluated = expression->value.cll_value.args, + .super = args, + }); + + default: + return (UwUVMValue) {}; + } +} + +UwUVMValue uwuvm_run_function(UwUVMFunction *function, UwUVMArgs args) +{ + UwUVMValue value = function->type == MODULE_PLAIN + ? uwuvm_evaluate_expression(function->value.plain, &args) + : function->value.native(&args); + + uwuvm_free_args(&args); + return value; +} |