]> git.lizzy.rs Git - uwu-std.git/blob - int.c
Initial commit
[uwu-std.git] / int.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "common/err.h"
4 #include "api/vm.h"
5 #include "api/int.h"
6 #include "api/bool.h"
7 #include "api/util.h"
8
9 typedef enum
10 {
11         BOP_SUB,
12         BOP_DIV,
13         BOP_MOD,
14         BOP_SML,
15         BOP_GRT,
16         BOP_EQU,
17 } BinaryOP;
18
19 static long binary(const char *fnname, UwUVMArgs *args, BinaryOP op)
20 {
21         uwuutil_require_exact(fnname, args, 2);
22
23         UwUVMValue value0 = uwuvm_get_arg(args, 0);
24
25         if (value0.type != &uwuint_type)
26                 error("type error: %s requires an integer as $1\n", fnname);
27
28         UwUVMValue value1 = uwuvm_get_arg(args, 1);
29
30         if (value1.type != &uwuint_type)
31                 error("type error: %s requires an integer as $2\n", fnname);
32
33         long a = uwuint_get(value0);
34         long b = uwuint_get(value1);
35
36         switch (op) {
37                 case BOP_SUB: return a - b;
38                 case BOP_DIV: return a / b;
39                 case BOP_MOD: return a % b;
40                 case BOP_SML: return a < b;
41                 case BOP_GRT: return a > b;
42                 case BOP_EQU: return a == b;
43         }
44
45         return 0;
46 }
47
48 typedef enum
49 {
50         ROP_ADD,
51         ROP_MUL,
52         ROP_EQU,
53 } ReduceOP;
54
55 static long reduce(const char *fnname, UwUVMArgs *args, ReduceOP op, long result)
56 {
57         long first;
58
59         for (size_t i = 0; i < args->num; i++) {
60                 UwUVMValue value = uwuvm_get_arg(args, i);
61
62                 if (value.type != &uwuint_type)
63                         error("type error: %s only accepts integers as arguments (invalid argument: $%lu)\n", fnname, i + 1);
64
65                 long this = uwuint_get(value);
66
67                 switch (op) {
68                         case ROP_ADD: result += this; break;
69                         case ROP_MUL: result *= this; break;
70                         case ROP_EQU:
71                                 if (i == 0)
72                                         first = this;
73                                 else if (this != first)
74                                         return 0;
75
76                                 break;
77                 }
78         }
79
80         return result;
81 }
82
83 UwUVMValue uwu_add(UwUVMArgs *args)
84 {
85         return uwuint_create(reduce("int.add", args, ROP_ADD, 0));
86 }
87
88 UwUVMValue uwu_sub(UwUVMArgs *args)
89 {
90         return uwuint_create(binary("int.sub", args, BOP_SUB));
91 }
92
93 UwUVMValue uwu_mul(UwUVMArgs *args)
94 {
95         return uwuint_create(reduce("int.mul", args, ROP_MUL, 1));
96 }
97
98 UwUVMValue uwu_div(UwUVMArgs *args)
99 {
100         return uwuint_create(binary("int.div", args, BOP_DIV));
101 }
102
103 UwUVMValue uwu_mod(UwUVMArgs *args)
104 {
105         return uwuint_create(binary("int.mod", args, BOP_MOD));
106 }
107
108 UwUVMValue uwu_smaller(UwUVMArgs *args)
109 {
110         return uwubool_create(binary("int.smaller", args, BOP_SML) == 1);
111 }
112
113 UwUVMValue uwu_greater(UwUVMArgs *args)
114 {
115         return uwubool_create(binary("int.greater", args, BOP_GRT) == 1);
116 }
117
118 UwUVMValue uwu_equal(UwUVMArgs *args)
119 {
120         uwuutil_require_min("int.equal", args, 2);
121         return uwubool_create(reduce("int.equal", args, ROP_EQU, 1) == 1);
122 }
123
124 UwUVMValue uwu_is(UwUVMArgs *args)
125 {
126         return uwuutil_is_type("int.is", args, &uwuint_type);
127 }