aboutsummaryrefslogtreecommitdiff
path: root/int.c
diff options
context:
space:
mode:
Diffstat (limited to 'int.c')
-rw-r--r--int.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/int.c b/int.c
new file mode 100644
index 0000000..625595d
--- /dev/null
+++ b/int.c
@@ -0,0 +1,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);
+}