// SPDX-License-Identifier: MIT // Copyright (c) 2023 John Watts and the LuminaSensum contributors #include "number.h" #include "boolean.h" #include "error.h" #include "object.h" #include "vm.h" #include <mini-gmp.h> #include <mini-mpq.h> #include <stddef.h> static struct object_class num_class; struct number { mpq_t value; }; Object number_create(VmState state, int value) { Object obj = object_create(state, &num_class, sizeof(struct number)); abort_if(state, !obj, "unable to allocate number"); struct number *num = (struct number *)object_priv(state, obj, &num_class); mpq_init(num->value); mpq_set_ui(num->value, value, 1); return obj; } static void number_cleanup(VmState state, Object obj) { struct number *num = (struct number *)object_priv(state, obj, &num_class); mpq_clear(num->value); } int number_value(VmState state, Object obj) { struct number *num = (struct number *)object_priv(state, obj, &num_class); mpz_t out; mpz_init(out); mpq_get_num(out, num->value); int out_int = (int)mpz_get_si(out); mpz_clear(out); return out_int; } #define OP_ADD (void *)1 #define OP_SUBTRACT (void *)2 static void number_math(VmState state, Object obj, void *priv) { int arg_count = vm_stack_depth(state); abort_if(state, arg_count != 2, "number_math called without 2 arguments"); Object arg1 = vm_stack_get(state, 1); int result = 0; if (priv == OP_ADD) { result = number_value(state, obj) + number_value(state, arg1); } else if (priv == OP_SUBTRACT) { result = number_value(state, obj) - number_value(state, arg1); } else { abort_msg(state, "number_math called with invalid priv"); } vm_stack_set(state, 0, number_create(state, result)); vm_stack_drop(state, 1); object_drop(state, &arg1); } static void number_equals(VmState state, Object obj, void *priv) { (void)priv; int arg_count = vm_stack_depth(state); abort_if(state, arg_count != 2, "number_equals called without 2 arguments"); Object arg1 = vm_stack_get(state, 1); bool equals = number_value(state, obj) == number_value(state, arg1); vm_stack_set(state, 0, boolean_create(state, equals)); vm_stack_drop(state, 1); object_drop(state, &arg1); } static struct object_call calls[] = { {.name = "Add", .handler = number_math, .priv = OP_ADD}, {.name = "Subtract", .handler = number_math, .priv = OP_SUBTRACT}, {.name = "Equals", .handler = number_equals, .priv = NULL}, {.name = NULL, /* end */}}; static struct object_class num_class = { .cleanup = number_cleanup, .calls = &calls[0], };