summaryrefslogtreecommitdiffhomepage
path: root/lib/math.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-12-13 12:58:18 +0100
committerJo-Philipp Wich <jo@mein.io>2022-01-04 15:53:36 +0100
commitb605dbfcf04f310e08634b52507da7a4155bfce1 (patch)
tree04397dab9be96a5978e08366299671a8aa507267 /lib/math.c
parent8907ce41a36f8d42097d884550fb3cfbba62e6c5 (diff)
treewide: rework numeric value handling
- Parse integer literals as unsigned numeric values in order to be able to represent the entire unsigned 64bit value range - Stop parsing minus-prefixed integer literals as negative numbers but treat them as separate minus operator followed by a positive integer instead - Only store unsigned numeric constants in bytecode - Rework numeric comparison logic to be able to handle full 64bit unsigned integers - If possible, yield unsigned 64 bit results for additions - Simplify numeric value conversion API - Compile code with -fwrapv for defined signed overflow semantics Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'lib/math.c')
-rw-r--r--lib/math.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/lib/math.c b/lib/math.c
index c4a08e3..f16d309 100644
--- a/lib/math.c
+++ b/lib/math.c
@@ -15,6 +15,7 @@
*/
#include <math.h>
+#include <errno.h>
#include <sys/time.h>
#include "ucode/module.h"
@@ -24,20 +25,43 @@ static bool srand_called = false;
static uc_value_t *
uc_abs(uc_vm_t *vm, size_t nargs)
{
- uc_value_t *v = uc_fn_arg(0);
- uc_type_t t;
+ uc_value_t *v = uc_fn_arg(0), *nv, *res;
int64_t n;
double d;
- if (ucv_type(v) == UC_NULL)
- return ucv_double_new(NAN);
+ nv = v ? ucv_to_number(v) : NULL;
+
+ switch (ucv_type(nv)) {
+ case UC_INTEGER:
+ n = ucv_int64_get(nv);
+
+ if (n >= 0 || errno == ERANGE)
+ res = ucv_get(nv);
+ else if (n == INT64_MIN)
+ res = ucv_uint64_new((uint64_t)INT64_MAX + 1);
+ else
+ res = ucv_uint64_new(-n);
+
+ break;
- t = ucv_cast_number(v, &n, &d);
+ case UC_DOUBLE:
+ d = ucv_double_get(nv);
+
+ if (isnan(d) || d >= 0)
+ res = ucv_get(nv);
+ else
+ res = ucv_double_new(-d);
+
+ break;
+
+ default:
+ res = ucv_double_new(NAN);
+ break;
+ }
- if (t == UC_DOUBLE)
- return (isnan(d) || d < 0) ? ucv_double_new(-d) : ucv_get(v);
+ ucv_put(nv);
- return (n < 0) ? ucv_int64_new(-n) : ucv_get(v);
+ return res;
}
static uc_value_t *