summaryrefslogtreecommitdiffhomepage
path: root/types.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-07-11 07:18:37 +0200
committerJo-Philipp Wich <jo@mein.io>2021-07-11 15:49:14 +0200
commitd5b25f942147b09511d77d5470cd38a1e1643fb9 (patch)
tree40542b06a966366e2e8a3a0118e756874a838ce6 /types.c
parentcc4ce8dfd13e833702c949e56049443cd01c0dfb (diff)
treewide: harmonize function naming
- Ensure that most functions follow the subject_verb naming schema - Move type related function from value.c to types.c - Rename value.c to vallist.c Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'types.c')
-rw-r--r--types.c294
1 files changed, 291 insertions, 3 deletions
diff --git a/types.c b/types.c
index 777de00..82c93cb 100644
--- a/types.c
+++ b/types.c
@@ -20,6 +20,7 @@
#include <endian.h>
#include <errno.h>
#include <math.h>
+#include <ctype.h>
#include "ucode/types.h"
#include "ucode/util.h"
@@ -1658,8 +1659,80 @@ ucv_to_jsonstring_formatted(uc_vm_t *vm, uc_value_t *uv, char pad_char, size_t p
return ucv_to_string_any(vm, uv, pad_char ? pad_char : '\1', pad_size);
}
+uc_type_t
+ucv_cast_number(uc_value_t *v, int64_t *n, double *d)
+{
+ bool is_double = false;
+ const char *s;
+ char *e;
+
+ *d = 0.0;
+ *n = 0;
+
+ switch (ucv_type(v)) {
+ case UC_INTEGER:
+ *n = ucv_int64_get(v);
+
+ return UC_INTEGER;
+
+ case UC_DOUBLE:
+ *d = ucv_double_get(v);
+
+ return UC_DOUBLE;
+
+ case UC_NULL:
+ return UC_INTEGER;
+
+ case UC_BOOLEAN:
+ *n = ucv_boolean_get(v);
+
+ return UC_INTEGER;
+
+ case UC_STRING:
+ s = ucv_string_get(v);
+
+ while (isspace(*s))
+ s++;
+
+ if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && isxdigit(s[2])) {
+ *n = strtoll(s, &e, 16);
+ }
+ else if (s[0] == '0' && isdigit(s[2])) {
+ *n = strtoll(s, &e, 8);
+ }
+ else {
+ *n = strtoll(s, &e, 10);
+
+ if (*e == '.') {
+ *d = strtod(s, &e);
+ is_double = (e > s);
+ }
+ }
+
+ while (isspace(*e))
+ e++;
+
+ if (*e) {
+ *d = NAN;
+
+ return UC_DOUBLE;
+ }
+
+ if (is_double)
+ return UC_DOUBLE;
+
+ return UC_INTEGER;
+
+ default:
+ *d = NAN;
+
+ return UC_DOUBLE;
+ }
+}
+
+
bool
-ucv_equal(uc_value_t *uv1, uc_value_t *uv2)
+ucv_is_equal(uc_value_t *uv1, uc_value_t *uv2)
{
uc_type_t t1 = ucv_type(uv1);
uc_type_t t2 = ucv_type(uv2);
@@ -1724,7 +1797,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2)
return false;
for (u1 = 0; u1 < u2; u1++)
- if (!ucv_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1)))
+ if (!ucv_is_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1)))
return false;
return true;
@@ -1737,7 +1810,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2)
return false;
ucv_object_foreach(uv1, key, val) {
- if (!ucv_equal(val, ucv_object_get(uv2, key, NULL)))
+ if (!ucv_is_equal(val, ucv_object_get(uv2, key, NULL)))
return false;
}
@@ -1756,6 +1829,221 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2)
}
}
+bool
+ucv_is_truish(uc_value_t *val)
+{
+ double d;
+
+ switch (ucv_type(val)) {
+ case UC_INTEGER:
+ if (ucv_is_u64(val))
+ return (ucv_uint64_get(val) != 0);
+
+ return (ucv_int64_get(val) != 0);
+
+ case UC_DOUBLE:
+ d = ucv_double_get(val);
+
+ return (d != 0 && !isnan(d));
+
+ case UC_BOOLEAN:
+ return ucv_boolean_get(val);
+
+ case UC_STRING:
+ return (ucv_string_length(val) > 0);
+
+ case UC_NULL:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+
+bool
+ucv_compare(int how, uc_value_t *v1, uc_value_t *v2)
+{
+ uc_type_t t1 = ucv_type(v1);
+ uc_type_t t2 = ucv_type(v2);
+ int64_t n1, n2, delta;
+ double d1, d2;
+
+ if (t1 == UC_STRING && t2 == UC_STRING) {
+ delta = strcmp(ucv_string_get(v1), ucv_string_get(v2));
+ }
+ else {
+ if (t1 == t2 && !ucv_is_scalar(v1)) {
+ delta = (intptr_t)v1 - (intptr_t)v2;
+ }
+ else {
+ t1 = ucv_cast_number(v1, &n1, &d1);
+ t2 = ucv_cast_number(v2, &n2, &d2);
+
+ if (t1 == UC_DOUBLE || t2 == UC_DOUBLE) {
+ d1 = (t1 == UC_DOUBLE) ? d1 : (double)n1;
+ d2 = (t2 == UC_DOUBLE) ? d2 : (double)n2;
+
+ /* all comparison results except `!=` involving NaN are false */
+ if (isnan(d1) || isnan(d2))
+ return (how == I_NE);
+
+ if (d1 == d2)
+ delta = 0;
+ else if (d1 < d2)
+ delta = -1;
+ else
+ delta = 1;
+ }
+ else {
+ delta = n1 - n2;
+ }
+ }
+ }
+
+ switch (how) {
+ case I_LT:
+ return (delta < 0);
+
+ case I_LE:
+ return (delta <= 0);
+
+ case I_GT:
+ return (delta > 0);
+
+ case I_GE:
+ return (delta >= 0);
+
+ case I_EQ:
+ return (delta == 0);
+
+ case I_NE:
+ return (delta != 0);
+
+ default:
+ return false;
+ }
+}
+
+
+static char *
+ucv_key_to_string(uc_vm_t *vm, uc_value_t *val)
+{
+ if (ucv_type(val) != UC_STRING)
+ return ucv_to_string(vm, val);
+
+ return NULL;
+}
+
+static int64_t
+ucv_key_to_index(uc_value_t *val)
+{
+ const char *k;
+ int64_t idx;
+ double d;
+ char *e;
+
+ /* only consider doubles with integer values as array keys */
+ if (ucv_type(val) == UC_DOUBLE) {
+ d = ucv_double_get(val);
+
+ if ((double)(int64_t)(d) != d)
+ return -1;
+
+ return (int64_t)d;
+ }
+ else if (ucv_type(val) == UC_INTEGER) {
+ return ucv_int64_get(val);
+ }
+ else if (ucv_type(val) == UC_STRING) {
+ errno = 0;
+ k = ucv_string_get(val);
+ idx = strtoll(k, &e, 0);
+
+ if (errno != 0 || e == k || *e != 0)
+ return -1;
+
+ return idx;
+ }
+
+ return -1;
+}
+
+uc_value_t *
+ucv_key_get(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key)
+{
+ uc_value_t *o, *v = NULL;
+ int64_t idx;
+ bool found;
+ char *k;
+
+ if (ucv_type(scope) == UC_ARRAY) {
+ idx = ucv_key_to_index(key);
+
+ if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope))
+ return ucv_get(ucv_array_get(scope, idx));
+ }
+
+ k = ucv_key_to_string(vm, key);
+
+ for (o = scope; o; o = ucv_prototype_get(o)) {
+ if (ucv_type(o) != UC_OBJECT)
+ continue;
+
+ v = ucv_object_get(o, k ? k : ucv_string_get(key), &found);
+
+ if (found)
+ break;
+ }
+
+ free(k);
+
+ return ucv_get(v);
+}
+
+uc_value_t *
+ucv_key_set(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key, uc_value_t *val)
+{
+ int64_t idx;
+ char *s;
+ bool rv;
+
+ if (!key)
+ return NULL;
+
+ if (ucv_type(scope) == UC_ARRAY) {
+ idx = ucv_key_to_index(key);
+
+ if (idx < 0 || !ucv_array_set(scope, idx, val))
+ return NULL;
+
+ return ucv_get(val);
+ }
+
+ s = ucv_key_to_string(vm, key);
+ rv = ucv_object_add(scope, s ? s : ucv_string_get(key), val);
+ free(s);
+
+ return rv ? ucv_get(val) : NULL;
+}
+
+bool
+ucv_key_delete(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key)
+{
+ char *s;
+ bool rv;
+
+ if (!key)
+ return NULL;
+
+ s = ucv_key_to_string(vm, key);
+ rv = ucv_object_delete(scope, s ? s : ucv_string_get(key));
+ free(s);
+
+ return rv;
+}
+
+
static void
ucv_gc_common(uc_vm_t *vm, bool final)
{