aboutsummaryrefslogtreecommitdiff
path: root/api/vm.c
blob: 73ec87eb92dee8cd1930f1ed50eda5706c55343d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <stdio.h>
#include <stdlib.h>
#include "../src/err.h"
#include "vm.h"
#include "str.h"
#include "ref.h"
#include "int.h"

void uwuvm_free_value(UwUVMValue value)
{
	value.type->delete(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)
{
	return (UwUVMValue) {
		.type = value.type,
		.data = value.type->copy(value.data),
	};
}

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 uwuref_create(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;
}