aboutsummaryrefslogtreecommitdiff
path: root/int.c
blob: 625595d4ea9175cbe1caad8943e9db753ce2099b (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <stdio.h>
#include <stdlib.h>
#include "common/err.h"
#include "api/vm.h"
#include "api/int.h"
#include "api/bool.h"
#include "api/util.h"

typedef enum
{
	BOP_SUB,
	BOP_DIV,
	BOP_MOD,
	BOP_SML,
	BOP_GRT,
	BOP_EQU,
} BinaryOP;

static long binary(const char *fnname, UwUVMArgs *args, BinaryOP op)
{
	uwuutil_require_exact(fnname, args, 2);

	UwUVMValue value0 = uwuvm_get_arg(args, 0);

	if (value0.type != &uwuint_type)
		error("type error: %s requires an integer as $1\n", fnname);

	UwUVMValue value1 = uwuvm_get_arg(args, 1);

	if (value1.type != &uwuint_type)
		error("type error: %s requires an integer as $2\n", fnname);

	long a = uwuint_get(value0);
	long b = uwuint_get(value1);

	switch (op) {
		case BOP_SUB: return a - b;
		case BOP_DIV: return a / b;
		case BOP_MOD: return a % b;
		case BOP_SML: return a < b;
		case BOP_GRT: return a > b;
		case BOP_EQU: return a == b;
	}

	return 0;
}

typedef enum
{
	ROP_ADD,
	ROP_MUL,
	ROP_EQU,
} ReduceOP;

static long reduce(const char *fnname, UwUVMArgs *args, ReduceOP op, long result)
{
	long first;

	for (size_t i = 0; i < args->num; i++) {
		UwUVMValue value = uwuvm_get_arg(args, i);

		if (value.type != &uwuint_type)
			error("type error: %s only accepts integers as arguments (invalid argument: $%lu)\n", fnname, i + 1);

		long this = uwuint_get(value);

		switch (op) {
			case ROP_ADD: result += this; break;
			case ROP_MUL: result *= this; break;
			case ROP_EQU:
				if (i == 0)
					first = this;
				else if (this != first)
					return 0;

				break;
		}
	}

	return result;
}

UwUVMValue uwu_add(UwUVMArgs *args)
{
	return uwuint_create(reduce("int.add", args, ROP_ADD, 0));
}

UwUVMValue uwu_sub(UwUVMArgs *args)
{
	return uwuint_create(binary("int.sub", args, BOP_SUB));
}

UwUVMValue uwu_mul(UwUVMArgs *args)
{
	return uwuint_create(reduce("int.mul", args, ROP_MUL, 1));
}

UwUVMValue uwu_div(UwUVMArgs *args)
{
	return uwuint_create(binary("int.div", args, BOP_DIV));
}

UwUVMValue uwu_mod(UwUVMArgs *args)
{
	return uwuint_create(binary("int.mod", args, BOP_MOD));
}

UwUVMValue uwu_smaller(UwUVMArgs *args)
{
	return uwubool_create(binary("int.smaller", args, BOP_SML) == 1);
}

UwUVMValue uwu_greater(UwUVMArgs *args)
{
	return uwubool_create(binary("int.greater", args, BOP_GRT) == 1);
}

UwUVMValue uwu_equal(UwUVMArgs *args)
{
	uwuutil_require_min("int.equal", args, 2);
	return uwubool_create(reduce("int.equal", args, ROP_EQU, 1) == 1);
}

UwUVMValue uwu_is(UwUVMArgs *args)
{
	return uwuutil_is_type("int.is", args, &uwuint_type);
}