aboutsummaryrefslogtreecommitdiff
path: root/api/vm.c
blob: 5cab6c08465485025b5fc7cc89dd831ed2c643c9 (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
88
89
90
91
92
93
94
95
96
97
98
99
#include <stdio.h>
#include <stdlib.h>
#include "../src/err.h"
#include "vm.h"
#include "str.h"
#include "ref.h"
#include "int.h"

UwUVMValue uwuvm_clone_value(UwUVMValue value)
{
	return (UwUVMValue) {
		.type = value.type,
		.data = value.type->clone(value.data),
	};
}

void uwuvm_delet_value(UwUVMValue value)
{
	value.type->delet(value.data);
}

char *uwuvm_print_value(UwUVMValue value)
{
	return value.type->print(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_clone_value(uwuvm_get_arg(args, expression->value.int_value));

		case EX_FNNAME:
			return uwuref_create(expression->value.ref_value);

		case EX_FNCALL:
			return uwuvm_call_function(
				expression->value.cll_value.function,
				expression->value.cll_value.num_args,
				expression->value.cll_value.args,
				args
			);

		default:
			return (UwUVMValue) {};
	}
}

UwUVMValue uwuvm_call_function(UwUVMFunction *function, size_t num_args, UwUVMExpression *unevaluated_args, UwUVMArgs *super_args)
{
	UwUVMValue *evaluated_args[num_args];

	for (size_t i = 0; i < num_args; i++)
		evaluated_args[i] = NULL;

	UwUVMArgs args = {
		.num = num_args,
		.evaluated = evaluated_args,
		.unevaluated = unevaluated_args,
		.super = super_args,
	};

	UwUVMValue return_value = function->type == MODULE_PLAIN
		? uwuvm_evaluate_expression(function->value.plain, &args)
		: function->value.native(&args);

	if (num_args > 0) {
		for (size_t i = 0; i < num_args; i++) {
			UwUVMValue *value = evaluated_args[i];

			if (value) {
				uwuvm_delet_value(*value);
				free(value);
			}
		}

	}

	return return_value;
}