aboutsummaryrefslogtreecommitdiff
path: root/api/vm.c
diff options
context:
space:
mode:
authorElias Fleckenstein <eliasfleckenstein@web.de>2021-12-30 14:18:15 +0100
committerElias Fleckenstein <eliasfleckenstein@web.de>2021-12-30 14:18:15 +0100
commitecc06c082036aa93f6810ec21e73610c55f5a57b (patch)
treeaff479c3bc5b39ead9f65dffb01d399b341fa4ba /api/vm.c
downloaduwu-lang-ecc06c082036aa93f6810ec21e73610c55f5a57b.tar.xz
Initial commit
Diffstat (limited to 'api/vm.c')
-rw-r--r--api/vm.c104
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;
+}