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