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