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);
}
|