aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/arrays.c25
-rw-r--r--stdlib/arrays.h21
-rw-r--r--stdlib/bools.c20
-rw-r--r--stdlib/bools.h2
-rw-r--r--stdlib/bytes.c10
-rw-r--r--stdlib/bytes.h2
-rw-r--r--stdlib/c_strings.c36
-rw-r--r--stdlib/c_strings.h6
-rw-r--r--stdlib/channels.c23
-rw-r--r--stdlib/channels.h21
-rw-r--r--stdlib/enums.c92
-rw-r--r--stdlib/enums.h24
-rw-r--r--stdlib/functiontype.c8
-rw-r--r--stdlib/functiontype.h18
-rw-r--r--stdlib/integers.c58
-rw-r--r--stdlib/integers.h14
-rw-r--r--stdlib/memory.c8
-rw-r--r--stdlib/metamethods.c234
-rw-r--r--stdlib/moments.c16
-rw-r--r--stdlib/moments.h4
-rw-r--r--stdlib/nums.c57
-rw-r--r--stdlib/nums.h12
-rw-r--r--stdlib/optionals.c77
-rw-r--r--stdlib/optionals.h14
-rw-r--r--stdlib/paths.c3
-rw-r--r--stdlib/patterns.c15
-rw-r--r--stdlib/pointers.c14
-rw-r--r--stdlib/pointers.h12
-rw-r--r--stdlib/ranges.c38
-rw-r--r--stdlib/rng.c10
-rw-r--r--stdlib/shell.c1
-rw-r--r--stdlib/stdlib.c4
-rw-r--r--stdlib/structs.c170
-rw-r--r--stdlib/structs.h24
-rw-r--r--stdlib/tables.c26
-rw-r--r--stdlib/tables.h22
-rw-r--r--stdlib/text.c47
-rw-r--r--stdlib/text.h16
-rw-r--r--stdlib/threads.c16
-rw-r--r--stdlib/threads.h2
-rw-r--r--stdlib/tomo.h2
-rw-r--r--stdlib/types.h40
42 files changed, 762 insertions, 502 deletions
diff --git a/stdlib/arrays.c b/stdlib/arrays.c
index 4db3d2d1..ff219203 100644
--- a/stdlib/arrays.c
+++ b/stdlib/arrays.c
@@ -283,8 +283,7 @@ public void *Array$random(Array_t arr, RNG_t rng)
public Table_t Array$counts(Array_t arr, const TypeInfo_t *type)
{
Table_t counts = {};
- const TypeInfo_t count_type = {.size=sizeof(Table_t), .align=__alignof__(Table_t),
- .tag=TableInfo, .TableInfo.key=type->ArrayInfo.item, .TableInfo.value=&Int$info};
+ const TypeInfo_t count_type = *Table$info(type->ArrayInfo.item, &Int$info);
for (int64_t i = 0; i < arr.length; i++) {
void *key = arr.data + i*arr.stride;
int64_t *count = Table$get(counts, key, &count_type);
@@ -515,14 +514,15 @@ public void Array$clear(Array_t *array)
*array = (Array_t){.data=0, .length=0};
}
-public int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo_t *type)
+public int32_t Array$compare(const void *vx, const void *vy, const TypeInfo_t *type)
{
+ const Array_t *x = (Array_t*)vx, *y = (Array_t*)vy;
// Early out for arrays with the same data, e.g. two copies of the same array:
if (x->data == y->data && x->stride == y->stride)
return (x->length > y->length) - (x->length < y->length);
const TypeInfo_t *item = type->ArrayInfo.item;
- if (item->tag == PointerInfo || (item->tag == CustomInfo && item->CustomInfo.compare == NULL)) { // data comparison
+ if (item->tag == PointerInfo || !item->metamethods.compare) { // data comparison
int64_t item_padded_size = type->ArrayInfo.item->size;
if (type->ArrayInfo.item->align > 1 && item_padded_size % type->ArrayInfo.item->align)
errx(1, "Item size is not padded!");
@@ -545,13 +545,14 @@ public int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo_
return (x->length > y->length) - (x->length < y->length);
}
-public bool Array$equal(const Array_t *x, const Array_t *y, const TypeInfo_t *type)
+public bool Array$equal(const void *x, const void *y, const TypeInfo_t *type)
{
- return x == y || (x->length == y->length && Array$compare(x, y, type) == 0);
+ return x == y || (((Array_t*)x)->length == ((Array_t*)y)->length && Array$compare(x, y, type) == 0);
}
-public Text_t Array$as_text(const Array_t *arr, bool colorize, const TypeInfo_t *type)
+public Text_t Array$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
{
+ Array_t *arr = (Array_t*)obj;
if (!arr)
return Text$concat(Text("["), generic_as_text(NULL, false, type->ArrayInfo.item), Text("]"));
@@ -567,12 +568,13 @@ public Text_t Array$as_text(const Array_t *arr, bool colorize, const TypeInfo_t
return text;
}
-public uint64_t Array$hash(const Array_t *arr, const TypeInfo_t *type)
+public uint64_t Array$hash(const void *obj, const TypeInfo_t *type)
{
+ const Array_t *arr = (Array_t*)obj;
const TypeInfo_t *item = type->ArrayInfo.item;
siphash sh;
siphashinit(&sh, sizeof(uint64_t[arr->length]));
- if (item->tag == PointerInfo || (item->tag == CustomInfo && item->CustomInfo.hash == NULL && item->size == sizeof(void*))) { // Raw data hash
+ if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void*))) { // Raw data hash
for (int64_t i = 0; i < arr->length; i++)
siphashadd64bits(&sh, (uint64_t)(arr->data + i*arr->stride));
} else {
@@ -694,4 +696,9 @@ public Int_t Array$binary_search(Array_t array, void *target, Closure_t comparis
return I(lo+1); // Return the index where the target would be inserted
}
+public PUREFUNC bool Array$is_none(const void *obj, const TypeInfo_t*)
+{
+ return ((Array_t*)obj)->length < 0;
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/arrays.h b/stdlib/arrays.h
index 251e9f92..192de806 100644
--- a/stdlib/arrays.h
+++ b/stdlib/arrays.h
@@ -85,10 +85,11 @@ PUREFUNC Array_t Array$to(Array_t array, Int_t last);
PUREFUNC Array_t Array$by(Array_t array, Int_t stride, int64_t padded_item_size);
PUREFUNC Array_t Array$reversed(Array_t array, int64_t padded_item_size);
Array_t Array$concat(Array_t x, Array_t y, int64_t padded_item_size);
-PUREFUNC uint64_t Array$hash(const Array_t *arr, const TypeInfo_t *type);
-PUREFUNC int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo_t *type);
-PUREFUNC bool Array$equal(const Array_t *x, const Array_t *y, const TypeInfo_t *type);
-Text_t Array$as_text(const Array_t *arr, bool colorize, const TypeInfo_t *type);
+PUREFUNC uint64_t Array$hash(const void *arr, const TypeInfo_t *type);
+PUREFUNC int32_t Array$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Array$equal(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Array$is_none(const void *obj, const TypeInfo_t*);
+Text_t Array$as_text(const void *arr, bool colorize, const TypeInfo_t *type);
void Array$heapify(Array_t *heap, Closure_t comparison, int64_t padded_item_size);
void Array$heap_push(Array_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size);
#define Array$heap_push_value(heap, _value, comparison, padded_item_size) ({ __typeof(_value) value = _value; Array$heap_push(heap, &value, comparison, padded_item_size); })
@@ -100,4 +101,16 @@ Int_t Array$binary_search(Array_t array, void *target, Closure_t comparison);
#define Array$binary_search_value(array, target, comparison) \
({ __typeof(target) _target = target; Array$binary_search(array, &_target, comparison); })
+#define Array$metamethods ((metamethods_t){ \
+ .as_text=Array$as_text, \
+ .compare=Array$compare, \
+ .equal=Array$equal, \
+ .hash=Array$hash, \
+ .is_none=Array$is_none, \
+})
+
+#define Array$info(item_info) &((TypeInfo_t){.size=sizeof(Array_t), .align=__alignof__(Array_t), \
+ .tag=ArrayInfo, .ArrayInfo.item=item_info, \
+ .metamethods=Array$metamethods})
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/bools.c b/stdlib/bools.c
index 50cd3f4c..5e0ade37 100644
--- a/stdlib/bools.c
+++ b/stdlib/bools.c
@@ -12,14 +12,13 @@
#include "text.h"
#include "util.h"
-PUREFUNC public Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo_t *type)
+PUREFUNC public Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t*)
{
- (void)type;
if (!b) return Text("Bool");
if (colorize)
- return *b ? Text("\x1b[35myes\x1b[m") : Text("\x1b[35mno\x1b[m");
+ return *(Bool_t*)b ? Text("\x1b[35myes\x1b[m") : Text("\x1b[35mno\x1b[m");
else
- return *b ? Text("yes") : Text("no");
+ return *(Bool_t*)b ? Text("yes") : Text("no");
}
PUREFUNC public OptionalBool_t Bool$parse(Text_t text)
@@ -39,11 +38,20 @@ PUREFUNC public OptionalBool_t Bool$parse(Text_t text)
}
}
+static bool Bool$is_none(const void *b, const TypeInfo_t*)
+{
+ return *(OptionalBool_t*)b == NONE_BOOL;
+}
+
+static const metamethods_t Bool$metamethods = {
+ .as_text=Bool$as_text,
+ .is_none=Bool$is_none,
+};
+
public const TypeInfo_t Bool$info = {
.size=sizeof(bool),
.align=__alignof__(bool),
- .tag=CustomInfo,
- .CustomInfo={.as_text=(void*)Bool$as_text},
+ .metamethods=Bool$metamethods,
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/bools.h b/stdlib/bools.h
index 7dec5711..c1b344b8 100644
--- a/stdlib/bools.h
+++ b/stdlib/bools.h
@@ -13,7 +13,7 @@
#define yes (Bool_t)true
#define no (Bool_t)false
-PUREFUNC Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo_t *type);
+PUREFUNC Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *type);
OptionalBool_t Bool$parse(Text_t text);
extern const TypeInfo_t Bool$info;
diff --git a/stdlib/bytes.c b/stdlib/bytes.c
index 0119cb49..6c94c054 100644
--- a/stdlib/bytes.c
+++ b/stdlib/bytes.c
@@ -10,11 +10,10 @@
public const Byte_t Byte$min = 0;
public const Byte_t Byte$max = UINT8_MAX;
-PUREFUNC public Text_t Byte$as_text(const Byte_t *b, bool colorize, const TypeInfo_t *type)
+PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t*)
{
- (void)type;
if (!b) return Text("Byte");
- return Text$format(colorize ? "\x1b[35m0x%02X\x1b[m" : "0x%02X", *b);
+ return Text$format(colorize ? "\x1b[35m0x%02X\x1b[m" : "0x%02X", *(Byte_t*)b);
}
public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
@@ -33,8 +32,9 @@ public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
public const TypeInfo_t Byte$info = {
.size=sizeof(Byte_t),
.align=__alignof__(Byte_t),
- .tag=CustomInfo,
- .CustomInfo={.as_text=(void*)Byte$as_text},
+ .metamethods={
+ .as_text=Byte$as_text,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/bytes.h b/stdlib/bytes.h
index 8c14ef1e..757f986f 100644
--- a/stdlib/bytes.h
+++ b/stdlib/bytes.h
@@ -11,7 +11,7 @@
#define Byte_t uint8_t
#define Byte(b) ((Byte_t)(b))
-PUREFUNC Text_t Byte$as_text(const Byte_t *b, bool colorize, const TypeInfo_t *type);
+PUREFUNC Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *type);
#define Byte_to_Int64(b, _) ((Int64_t)(b))
#define Byte_to_Int32(b, _) ((Int32_t)(b))
diff --git a/stdlib/c_strings.c b/stdlib/c_strings.c
index 5ac7d4b4..99632a53 100644
--- a/stdlib/c_strings.c
+++ b/stdlib/c_strings.c
@@ -10,11 +10,11 @@
#include "siphash.h"
#include "util.h"
-public Text_t CString$as_text(const char **c_string, bool colorize, const TypeInfo_t *info)
+public Text_t CString$as_text(const void *c_string, bool colorize, const TypeInfo_t *info)
{
(void)info;
if (!c_string) return Text("CString");
- Text_t text = Text$from_str(*c_string);
+ Text_t text = Text$from_str(*(char**)c_string);
return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), Text$quoted(text, colorize), Text(")"));
}
@@ -23,33 +23,43 @@ public Text_t CString$as_text_simple(const char *str)
return Text$format("%s", str);
}
-PUREFUNC public int32_t CString$compare(const char **x, const char **y)
+PUREFUNC public int32_t CString$compare(const void *x, const void *y, const TypeInfo_t*)
{
if (x == y)
return 0;
- if (!*x != !*y)
- return (!*y) - (!*x);
+ if (!*(char**)x != !*(char**)y)
+ return (!*(char**)y) - (!*(char**)x);
- return strcmp(*x, *y);
+ return strcmp(*(char**)x, *(char**)y);
}
-PUREFUNC public bool CString$equal(const char **x, const char **y)
+PUREFUNC public bool CString$equal(const void *x, const void *y, const TypeInfo_t *type)
{
- return CString$compare(x, y) == 0;
+ return CString$compare(x, y, type) == 0;
}
-PUREFUNC public uint64_t CString$hash(const char **c_str)
+PUREFUNC public uint64_t CString$hash(const void *c_str, const TypeInfo_t*)
{
- if (!*c_str) return 0;
- return siphash24((void*)*c_str, strlen(*c_str));
+ if (!*(char**)c_str) return 0;
+ return siphash24(*(void**)c_str, strlen(*(char**)c_str));
+}
+
+PUREFUNC public bool CString$is_none(const void *c_str, const TypeInfo_t*)
+{
+ return *(char**)c_str == NULL;
}
public const TypeInfo_t CString$info = {
.size=sizeof(char*),
.align=__alignof__(char*),
- .tag=CStringInfo,
- .CustomInfo={.as_text=(void*)CString$as_text, .compare=(void*)CString$compare, .equal=(void*)CString$equal, .hash=(void*)CString$hash},
+ .metamethods={
+ .hash=CString$hash,
+ .compare=CString$compare,
+ .equal=CString$equal,
+ .as_text=CString$as_text,
+ .is_none=CString$is_none,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/c_strings.h b/stdlib/c_strings.h
index 745333ad..7b736a0c 100644
--- a/stdlib/c_strings.h
+++ b/stdlib/c_strings.h
@@ -9,9 +9,9 @@
Text_t CString$as_text(char **str, bool colorize, const TypeInfo_t *info);
Text_t CString$as_text_simple(const char *str);
-PUREFUNC int CString$compare(const char **x, const char **y);
-PUREFUNC bool CString$equal(const char **x, const char **y);
-PUREFUNC uint64_t CString$hash(const char **str);
+PUREFUNC int CString$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool CString$equal(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC uint64_t CString$hash(const void *str, const TypeInfo_t *type);
extern const TypeInfo_t CString$info;
diff --git a/stdlib/channels.c b/stdlib/channels.c
index ac3d697f..8ab4e665 100644
--- a/stdlib/channels.c
+++ b/stdlib/channels.c
@@ -99,25 +99,23 @@ public void Channel$clear(Channel_t *channel)
(void)pthread_cond_signal(&channel->cond);
}
-PUREFUNC public uint64_t Channel$hash(Channel_t **channel, const TypeInfo_t *type)
+PUREFUNC public uint64_t Channel$hash(const void *channel, const TypeInfo_t *type)
{
(void)type;
- return siphash24((void*)*channel, sizeof(Channel_t*));
+ return siphash24(*(void**)channel, sizeof(Channel_t*));
}
-PUREFUNC public int32_t Channel$compare(Channel_t **x, Channel_t **y, const TypeInfo_t *type)
+PUREFUNC public int32_t Channel$compare(const void *x, const void *y, const TypeInfo_t*)
{
- (void)type;
- return (*x > *y) - (*x < *y);
+ return (*(Channel_t**)x > *(Channel_t**)y) - (*(Channel_t**)x < *(Channel_t**)y);
}
-PUREFUNC public bool Channel$equal(Channel_t **x, Channel_t **y, const TypeInfo_t *type)
+PUREFUNC public bool Channel$equal(const void *x, const void *y, const TypeInfo_t*)
{
- (void)type;
- return (*x == *y);
+ return (*(void**)x == *(void**)y);
}
-public Text_t Channel$as_text(Channel_t **channel, bool colorize, const TypeInfo_t *type)
+public Text_t Channel$as_text(const void *channel, bool colorize, const TypeInfo_t *type)
{
const TypeInfo_t *item_type = type->ChannelInfo.item;
if (!channel) {
@@ -129,9 +127,14 @@ public Text_t Channel$as_text(Channel_t **channel, bool colorize, const TypeInfo
colorize ? Text("\x1b[34;1m|:") : Text("|:"),
typename,
Text("|<"),
- Int64$hex((int64_t)(void*)*channel, I_small(0), true, true),
+ Int64$hex(*(int64_t*)channel, I_small(0), true, true),
colorize ? Text(">\x1b[m") : Text(">")
);
}
+public PUREFUNC bool Channel$is_none(const void *obj, const TypeInfo_t*)
+{
+ return *(void**)obj == NULL;
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/channels.h b/stdlib/channels.h
index c960452a..9a848107 100644
--- a/stdlib/channels.h
+++ b/stdlib/channels.h
@@ -20,9 +20,22 @@ void Channel$peek(Channel_t *channel, void *out, bool front, int64_t item_size);
#define Channel$peek_value(channel, front, t) ({ t _val; Channel$peek(channel, &_val, front, sizeof(t)); _val; })
void Channel$clear(Channel_t *channel);
Array_t Channel$view(Channel_t *channel);
-PUREFUNC uint64_t Channel$hash(Channel_t **channel, const TypeInfo_t *type);
-PUREFUNC int32_t Channel$compare(Channel_t **x, Channel_t **y, const TypeInfo_t *type);
-PUREFUNC bool Channel$equal(Channel_t **x, Channel_t **y, const TypeInfo_t *type);
-Text_t Channel$as_text(Channel_t **channel, bool colorize, const TypeInfo_t *type);
+PUREFUNC uint64_t Channel$hash(const void *channel, const TypeInfo_t *type);
+PUREFUNC int32_t Channel$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Channel$equal(const void *x, const void *y, const TypeInfo_t *type);
+Text_t Channel$as_text(const void *channel, bool colorize, const TypeInfo_t *type);
+PUREFUNC bool Channel$is_none(const void *obj, const TypeInfo_t*);
+
+#define Channel$metamethods ((metamethods_t){ \
+ .as_text=Channel$as_text, \
+ .compare=Channel$compare, \
+ .equal=Channel$equal, \
+ .hash=Channel$hash, \
+ .is_none=Channel$is_none, \
+})
+
+#define Channel$info(item_info) &((TypeInfo_t){.size=sizeof(Channel_t), .align=__alignof__(Channel_t), \
+ .tag=ChannelInfo, .ChannelInfo.item=item_info, \
+ .metamethods=Channel$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/enums.c b/stdlib/enums.c
new file mode 100644
index 00000000..ea2a443b
--- /dev/null
+++ b/stdlib/enums.c
@@ -0,0 +1,92 @@
+// Metamethods for enums
+
+#include <stdint.h>
+#include <string.h>
+
+#include "arrays.h"
+#include "bools.h"
+#include "channels.h"
+#include "functiontype.h"
+#include "metamethods.h"
+#include "optionals.h"
+#include "pointers.h"
+#include "siphash.h"
+#include "tables.h"
+#include "text.h"
+#include "util.h"
+
+PUREFUNC public uint64_t Enum$hash(const void *obj, const TypeInfo_t *type)
+{
+ int32_t tag = *(int32_t*)obj;
+ uint32_t components[2] = {(uint32_t)tag, 0};
+
+ const TypeInfo_t *value = type->EnumInfo.tags[tag-1].type;
+ if (value && value->size > 0) {
+ ptrdiff_t byte_offset = sizeof(int32_t);
+ if (value->align && byte_offset % value->align > 0)
+ byte_offset += value->align - (byte_offset % value->align);
+ components[1] = generic_hash(obj + byte_offset, value);
+ }
+ return siphash24((void*)components, sizeof(components));
+}
+
+PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInfo_t *type)
+{
+ if (x == y) return 0;
+
+ int32_t x_tag = *(int32_t*)x;
+ int32_t y_tag = *(int32_t*)y;
+ if (x_tag != y_tag)
+ return x_tag > y_tag ? 1 : -1;
+
+ const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type;
+ if (value && value->size > 0) {
+ ptrdiff_t byte_offset = sizeof(int32_t);
+ if (value->align && byte_offset % value->align > 0)
+ byte_offset += value->align - (byte_offset % value->align);
+ return generic_compare(x + byte_offset, y + byte_offset, value);
+ }
+ return 0;
+}
+
+PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t *type)
+{
+ if (x == y) return true;
+
+ int32_t x_tag = *(int32_t*)x;
+ int32_t y_tag = *(int32_t*)y;
+ if (x_tag != y_tag)
+ return false;
+
+ const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type;
+ if (value && value->size > 0) {
+ ptrdiff_t byte_offset = sizeof(int32_t);
+ if (value->align && byte_offset % value->align > 0)
+ byte_offset += value->align - (byte_offset % value->align);
+ return generic_equal(x + byte_offset, y + byte_offset, value);
+ }
+ return true;
+}
+
+public Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
+{
+ if (!obj) return Text$from_str(type->EnumInfo.name);
+
+ int32_t tag = *(int32_t*)obj;
+ NamedType_t value = type->EnumInfo.tags[tag-1];
+ if (!value.type || value.type->size == 0)
+ return Text$format(colorize ? "\x1b[36;1m%s\x1b[m.\x1b[1m%s\x1b[m" : "%s.%s", type->EnumInfo.name, value.name);
+
+ ptrdiff_t byte_offset = sizeof(int32_t);
+ if (value.type->align && byte_offset % value.type->align > 0)
+ byte_offset += value.type->align - (byte_offset % value.type->align);
+ return Text$concat(Text$format(colorize ? "\x1b[36;1m%s\x1b[m." : "%s.", type->EnumInfo.name),
+ generic_as_text(obj + byte_offset, colorize, value.type));
+}
+
+PUREFUNC public bool Enum$is_none(const void *x, const TypeInfo_t*)
+{
+ return *(int32_t*)x == 0;
+}
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/enums.h b/stdlib/enums.h
new file mode 100644
index 00000000..8afa5c9b
--- /dev/null
+++ b/stdlib/enums.h
@@ -0,0 +1,24 @@
+// Metamethods for enums
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "datatypes.h"
+#include "types.h"
+#include "util.h"
+
+PUREFUNC uint64_t Enum$hash(const void *obj, const TypeInfo_t *type);
+PUREFUNC int32_t Enum$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Enum$equal(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *type);
+PUREFUNC bool Enum$is_none(const void *obj, const TypeInfo_t *type);
+
+#define Enum$metamethods ((metamethods_t){ \
+ .as_text=Enum$as_text, \
+ .compare=Enum$compare, \
+ .equal=Enum$equal, \
+ .hash=Enum$hash, \
+ .is_none=Enum$is_none, \
+})
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/functiontype.c b/stdlib/functiontype.c
index ce07c063..b62ef2a7 100644
--- a/stdlib/functiontype.c
+++ b/stdlib/functiontype.c
@@ -1,6 +1,9 @@
// Logic for handling function type values
+#include <stdbool.h>
+
#include "datatypes.h"
+#include "functiontype.h"
#include "tables.h"
#include "text.h"
#include "types.h"
@@ -32,4 +35,9 @@ public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type
return text;
}
+public PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t*)
+{
+ return *(void**)obj == NULL;
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/functiontype.h b/stdlib/functiontype.h
index 8fdabb8c..7745bff8 100644
--- a/stdlib/functiontype.h
+++ b/stdlib/functiontype.h
@@ -1,9 +1,27 @@
#pragma once
+#include <stdbool.h>
+
+#include "types.h"
+#include "util.h"
+
// Logic for handling function type values
void register_function(void *fn, Text_t name);
Text_t *get_function_name(void *fn);
Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type);
+PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t*);
+
+#define Func$metamethods ((metamethods_t){ \
+ .as_text=Func$as_text, \
+ .is_none=Func$is_none, \
+})
+
+#define Function$info(typestr) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
+ .tag=FunctionInfo, .FunctionInfo.type_str=typestr, \
+ .metamethods=Func$metamethods})
+#define Closure$info(typestr) &((TypeInfo_t){.size=sizeof(void*[2]), .align=__alignof__(void*), \
+ .tag=FunctionInfo, .FunctionInfo.type_str=typestr, \
+ .metamethods=Func$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/integers.c b/stdlib/integers.c
index baf1b0c8..6c00527d 100644
--- a/stdlib/integers.c
+++ b/stdlib/integers.c
@@ -23,17 +23,16 @@ public Text_t Int$value_as_text(Int_t i) {
}
}
-public Text_t Int$as_text(const Int_t *i, bool colorize, const TypeInfo_t *type) {
- (void)type;
+public Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t*) {
if (!i) return Text("Int");
-
- Text_t text = Int$value_as_text(*i);
+ Text_t text = Int$value_as_text(*(Int_t*)i);
if (colorize) text = Text$concat(Text("\x1b[35m"), text, Text("\x1b[m"));
return text;
}
-public PUREFUNC int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo_t *type) {
- (void)type;
+public PUREFUNC int32_t Int$compare(const void *vx, const void *vy, const TypeInfo_t*) {
+ Int_t *x = (Int_t*)vx;
+ Int_t *y = (Int_t*)vy;
if (__builtin_expect(((x->small | y->small) & 1) == 0, 0))
return x->big == y->big ? 0 : mpz_cmp(*x->big, *y->big);
return (x->small > y->small) - (x->small < y->small);
@@ -45,8 +44,9 @@ public PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) {
return (x.small > y.small) - (x.small < y.small);
}
-public PUREFUNC bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo_t *type) {
- (void)type;
+public PUREFUNC bool Int$equal(const void *vx, const void *vy, const TypeInfo_t*) {
+ Int_t *x = (Int_t*)vx;
+ Int_t *y = (Int_t*)vy;
return x->small == y->small || (__builtin_expect(((x->small | y->small) & 1) == 0, 0) && mpz_cmp(*x->big, *y->big) == 0);
}
@@ -54,8 +54,8 @@ public PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) {
return x.small == y.small || (__builtin_expect(((x.small | y.small) & 1) == 0, 0) && mpz_cmp(*x.big, *y.big) == 0);
}
-public PUREFUNC uint64_t Int$hash(const Int_t *x, const TypeInfo_t *type) {
- (void)type;
+public PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t*) {
+ Int_t *x = (Int_t*)vx;
if (__builtin_expect(x->small & 1, 1)) {
return siphash24((void*)x, sizeof(Int_t));
} else {
@@ -362,31 +362,33 @@ public Int_t Int$prev_prime(Int_t x)
return Int$from_mpz(p);
}
+static bool Int$is_none(const void *i, const TypeInfo_t*)
+{
+ return ((Int_t*)i)->small == 0;
+}
+
public const TypeInfo_t Int$info = {
.size=sizeof(Int_t),
.align=__alignof__(Int_t),
- .tag=CustomInfo,
- .CustomInfo={
- .compare=(void*)Int$compare,
- .equal=(void*)Int$equal,
- .hash=(void*)Int$hash,
- .as_text=(void*)Int$as_text,
+ .metamethods={
+ .compare=Int$compare,
+ .equal=Int$equal,
+ .hash=Int$hash,
+ .as_text=Int$as_text,
+ .is_none=Int$is_none,
},
};
#define DEFINE_INT_TYPE(c_type, KindOfInt, fmt, min_val, max_val, to_attr)\
- public Text_t KindOfInt ## $as_text(const c_type *i, bool colorize, const TypeInfo_t *type) { \
- (void)type; \
+ public Text_t KindOfInt ## $as_text(const void *i, bool colorize, const TypeInfo_t*) { \
if (!i) return Text(#KindOfInt); \
- return Text$format(colorize ? "\x1b[35m" fmt "\x1b[m" : fmt, *i); \
+ return Text$format(colorize ? "\x1b[35m" fmt "\x1b[m" : fmt, *(c_type*)i); \
} \
- public PUREFUNC int32_t KindOfInt ## $compare(const c_type *x, const c_type *y, const TypeInfo_t *type) { \
- (void)type; \
- return (*x > *y) - (*x < *y); \
+ public PUREFUNC int32_t KindOfInt ## $compare(const void *x, const void *y, const TypeInfo_t*) { \
+ return (*(c_type*)x > *(c_type*)y) - (*(c_type*)x < *(c_type*)y); \
} \
- public PUREFUNC bool KindOfInt ## $equal(const c_type *x, const c_type *y, const TypeInfo_t *type) { \
- (void)type; \
- return *x == *y; \
+ public PUREFUNC bool KindOfInt ## $equal(const void *x, const void *y, const TypeInfo_t*) { \
+ return *(c_type*)x == *(c_type*)y; \
} \
public Text_t KindOfInt ## $format(c_type i, Int_t digits_int) { \
Int_t as_int = KindOfInt##_to_Int(i); \
@@ -428,8 +430,10 @@ public const TypeInfo_t Int$info = {
public const TypeInfo_t KindOfInt##$info = { \
.size=sizeof(c_type), \
.align=__alignof__(c_type), \
- .tag=CustomInfo, \
- .CustomInfo={.compare=(void*)KindOfInt##$compare, .as_text=(void*)KindOfInt##$as_text}, \
+ .metamethods={ \
+ .compare=KindOfInt##$compare, \
+ .as_text=KindOfInt##$as_text, \
+ }, \
};
DEFINE_INT_TYPE(int64_t, Int64, "%ld", INT64_MIN, INT64_MAX, __attribute__(()))
diff --git a/stdlib/integers.h b/stdlib/integers.h
index 12cb90f4..a5016d40 100644
--- a/stdlib/integers.h
+++ b/stdlib/integers.h
@@ -27,9 +27,9 @@
c_type i; \
bool is_null:1; \
} Optional ## type_name ## _t; \
- Text_t type_name ## $as_text(const c_type *i, bool colorize, const TypeInfo_t *type); \
- PUREFUNC int32_t type_name ## $compare(const c_type *x, const c_type *y, const TypeInfo_t *type); \
- PUREFUNC bool type_name ## $equal(const c_type *x, const c_type *y, const TypeInfo_t *type); \
+ Text_t type_name ## $as_text(const void *i, bool colorize, const TypeInfo_t *type); \
+ PUREFUNC int32_t type_name ## $compare(const void *x, const void *y, const TypeInfo_t *type); \
+ PUREFUNC bool type_name ## $equal(const void *x, const void *y, const TypeInfo_t *type); \
Text_t type_name ## $format(c_type i, Int_t digits); \
Text_t type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \
Text_t type_name ## $octal(c_type i, Int_t digits, bool prefix); \
@@ -85,12 +85,12 @@ DEFINE_INT_TYPE(int8_t, Int8, CONSTFUNC)
#define OptionalInt_t Int_t
-Text_t Int$as_text(const Int_t *i, bool colorize, const TypeInfo_t *type);
+Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *type);
Text_t Int$value_as_text(Int_t i);
-PUREFUNC uint64_t Int$hash(const Int_t *x, const TypeInfo_t *type);
-PUREFUNC int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo_t *type);
+PUREFUNC uint64_t Int$hash(const void *x, const TypeInfo_t *type);
+PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y);
-PUREFUNC bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo_t *type);
+PUREFUNC bool Int$equal(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y);
Text_t Int$format(Int_t i, Int_t digits);
Text_t Int$hex(Int_t i, Int_t digits, bool uppercase, bool prefix);
diff --git a/stdlib/memory.c b/stdlib/memory.c
index 17b6172f..70ca574c 100644
--- a/stdlib/memory.c
+++ b/stdlib/memory.c
@@ -12,8 +12,7 @@
#include "types.h"
#include "util.h"
-public Text_t Memory__as_text(const void *p, bool colorize, const TypeInfo_t *type) {
- (void)type;
+public Text_t Memory$as_text(const void *p, bool colorize, const TypeInfo_t *) {
if (!p) return Text("Memory");
return Text$format(colorize ? "\x1b[0;34;1mMemory<%p>\x1b[m" : "Memory<%p>", p);
}
@@ -21,8 +20,9 @@ public Text_t Memory__as_text(const void *p, bool colorize, const TypeInfo_t *ty
public const TypeInfo_t Memory$info = {
.size=0,
.align=0,
- .tag=CustomInfo,
- .CustomInfo={.as_text=(void*)Memory__as_text},
+ .metamethods={
+ .as_text=Memory$as_text,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/metamethods.c b/stdlib/metamethods.c
index 6c8583f3..28d97730 100644
--- a/stdlib/metamethods.c
+++ b/stdlib/metamethods.c
@@ -15,247 +15,40 @@
#include "text.h"
#include "util.h"
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstack-protector"
PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type)
{
- switch (type->tag) {
- case TextInfo: return Text$hash((void*)obj);
- case ArrayInfo: return Array$hash(obj, type);
- case ChannelInfo: return Channel$hash((Channel_t**)obj, type);
- case TableInfo: return Table$hash(obj, type);
- case OptionalInfo: return is_null(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type);
- case StructInfo: {
- if (type->StructInfo.num_fields == 0) {
- return 0;
- } else if (type->StructInfo.num_fields == 1) {
- return generic_hash(obj, type->StructInfo.fields[0].type);
- } else {
- uint32_t field_hashes[type->StructInfo.num_fields] = {};
- ptrdiff_t byte_offset = 0;
- ptrdiff_t bit_offset = 0;
- for (int i = 0; i < type->StructInfo.num_fields; i++) {
- NamedType_t field = type->StructInfo.fields[i];
- if (field.type == &Bool$info) {
- bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
- field_hashes[i] = (uint32_t)b;
- bit_offset += 1;
- if (bit_offset >= 8) {
- byte_offset += 1;
- bit_offset = 0;
- }
- } else {
- if (bit_offset > 0) {
- byte_offset += 1;
- bit_offset = 0;
- }
- if (field.type->align && byte_offset % field.type->align > 0)
- byte_offset += field.type->align - (byte_offset % field.type->align);
- field_hashes[i] = generic_hash(obj + byte_offset, field.type);
- byte_offset += field.type->size;
- }
- }
- return siphash24((void*)field_hashes, sizeof(field_hashes));
- }
- }
- case EnumInfo: {
- int32_t tag = *(int32_t*)obj;
- uint32_t components[2] = {(uint32_t)tag, 0};
-
- const TypeInfo_t *value = type->EnumInfo.tags[tag-1].type;
- if (value && value->size > 0) {
- ptrdiff_t byte_offset = sizeof(int32_t);
- if (value->align && byte_offset % value->align > 0)
- byte_offset += value->align - (byte_offset % value->align);
- components[1] = generic_hash(obj + byte_offset, value);
- }
- return siphash24((void*)components, sizeof(components));
+ if (type->metamethods.hash)
+ return type->metamethods.hash(obj, type);
- }
- case CustomInfo: case CStringInfo: // These all share the same info
- if (!type->CustomInfo.hash)
- goto hash_data;
- return type->CustomInfo.hash(obj, type);
- case PointerInfo: case FunctionInfo: case TypeInfoInfo: case OpaqueInfo: default: {
- hash_data:;
- return siphash24((void*)obj, (size_t)(type->size));
- }
- }
+ return siphash24((void*)obj, (size_t)(type->size));
}
-#pragma GCC diagnostic pop
PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type)
{
if (x == y) return 0;
- switch (type->tag) {
- case PointerInfo: case FunctionInfo: return Pointer$compare(x, y, type);
- case TextInfo: return Text$compare(x, y);
- case ArrayInfo: return Array$compare(x, y, type);
- case ChannelInfo: return Channel$compare((Channel_t**)x, (Channel_t**)y, type);
- case TableInfo: return Table$compare(x, y, type);
- case OptionalInfo: {
- bool x_is_null = is_null(x, type->OptionalInfo.type);
- bool y_is_null = is_null(y, type->OptionalInfo.type);
- if (x_is_null && y_is_null) return 0;
- else if (x_is_null != y_is_null) return (int32_t)y_is_null - (int32_t)x_is_null;
- else return generic_compare(x, y, type->OptionalInfo.type);
- }
- case StructInfo: {
- ptrdiff_t byte_offset = 0;
- ptrdiff_t bit_offset = 0;
- for (int i = 0; i < type->StructInfo.num_fields; i++) {
- NamedType_t field = type->StructInfo.fields[i];
- if (field.type == &Bool$info) {
- bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1;
- bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1;
- if (bx != by)
- return (int32_t)bx - (int32_t)by;
- bit_offset += 1;
- if (bit_offset >= 8) {
- byte_offset += 1;
- bit_offset = 0;
- }
- } else {
- if (bit_offset > 0) {
- byte_offset += 1;
- bit_offset = 0;
- }
- if (field.type->align && byte_offset % field.type->align > 0)
- byte_offset += field.type->align - (byte_offset % field.type->align);
- int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type);
- if (cmp != 0)
- return cmp;
- byte_offset += field.type->size;
- }
- }
- return 0;
- }
- case EnumInfo: {
- int32_t x_tag = *(int32_t*)x;
- int32_t y_tag = *(int32_t*)y;
- if (x_tag != y_tag)
- return x_tag > y_tag ? 1 : -1;
+ if (type->metamethods.compare)
+ return type->metamethods.compare(x, y, type);
- const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type;
- if (value && value->size > 0) {
- ptrdiff_t byte_offset = sizeof(int32_t);
- if (value->align && byte_offset % value->align > 0)
- byte_offset += value->align - (byte_offset % value->align);
- return generic_compare(x + byte_offset, y + byte_offset, value);
- }
- return 0;
- }
- case CustomInfo: case CStringInfo: // These all share the same info
- if (!type->CustomInfo.compare)
- goto compare_data;
- return type->CustomInfo.compare(x, y, type);
- case TypeInfoInfo: case OpaqueInfo: default:
- compare_data:
- return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size));
- }
+ return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size));
}
PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type)
{
if (x == y) return true;
- switch (type->tag) {
- case PointerInfo: case FunctionInfo: return Pointer$equal(x, y, type);
- case TextInfo: return Text$equal(x, y);
- case ArrayInfo: return Array$equal(x, y, type);
- case ChannelInfo: return Channel$equal((Channel_t**)x, (Channel_t**)y, type);
- case TableInfo: return Table$equal(x, y, type);
- case OptionalInfo: {
- bool x_is_null = is_null(x, type->OptionalInfo.type);
- bool y_is_null = is_null(y, type->OptionalInfo.type);
- if (x_is_null && y_is_null) return true;
- else if (x_is_null != y_is_null) return false;
- else return generic_equal(x, y, type->OptionalInfo.type);
- }
- case StructInfo: case EnumInfo:
- return (generic_compare(x, y, type) == 0);
- case CustomInfo: case CStringInfo: // These all share the same info
- if (!type->CustomInfo.equal)
- goto use_generic_compare;
- return type->CustomInfo.equal(x, y, type);
- case TypeInfoInfo: case OpaqueInfo: default:
- use_generic_compare:
- return (generic_compare(x, y, type) == 0);
- }
+ if (type->metamethods.equal)
+ return type->metamethods.equal(x, y, type);
+
+ return (generic_compare(x, y, type) == 0);
}
public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type)
{
- switch (type->tag) {
- case PointerInfo: return Pointer$as_text(obj, colorize, type);
- case FunctionInfo: return Func$as_text(obj, colorize, type);
- case TextInfo: return Text$as_text(obj, colorize, type);
- case ArrayInfo: return Array$as_text(obj, colorize, type);
- case ChannelInfo: return Channel$as_text((Channel_t**)obj, colorize, type);
- case TableInfo: return Table$as_text(obj, colorize, type);
- case TypeInfoInfo: return Type$as_text(obj, colorize, type);
- case OptionalInfo: return Optional$as_text(obj, colorize, type);
- case StructInfo: {
- if (!obj) return Text$from_str(type->StructInfo.name);
-
- if (type->StructInfo.is_secret)
- return Text$format(colorize ? "\x1b[0;1m%s\x1b[m(...)" : "%s(...)", type->StructInfo.name);
-
- Text_t text = Text$format(colorize ? "\x1b[0;1m%s\x1b[m(" : "%s(", type->StructInfo.name);
- ptrdiff_t byte_offset = 0;
- ptrdiff_t bit_offset = 0;
- for (int i = 0; i < type->StructInfo.num_fields; i++) {
- NamedType_t field = type->StructInfo.fields[i];
- if (i > 0)
- text = Text$concat(text, Text(", "));
+ if (!type->metamethods.as_text)
+ fail("No text metamethod provided for type!");
- if (type->StructInfo.num_fields > 1)
- text = Text$concat(text, Text$from_str(field.name), Text("="));
-
- if (field.type == &Bool$info) {
- bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
- text = Text$concat(text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no")));
- bit_offset += 1;
- if (bit_offset >= 8) {
- byte_offset += 1;
- bit_offset = 0;
- }
- } else {
- if (bit_offset > 0) {
- byte_offset += 1;
- bit_offset = 0;
- }
- if (field.type->align && byte_offset % field.type->align > 0)
- byte_offset += field.type->align - (byte_offset % field.type->align);
- text = Text$concat(text, generic_as_text(obj + byte_offset, colorize, field.type));
- byte_offset += field.type->size;
- }
- }
- return Text$concat(text, Text(")"));
- }
- case EnumInfo: {
- if (!obj) return Text$from_str(type->EnumInfo.name);
-
- int32_t tag = *(int32_t*)obj;
- NamedType_t value = type->EnumInfo.tags[tag-1];
- if (!value.type || value.type->size == 0)
- return Text$format(colorize ? "\x1b[36;1m%s\x1b[m.\x1b[1m%s\x1b[m" : "%s.%s", type->EnumInfo.name, value.name);
-
- ptrdiff_t byte_offset = sizeof(int32_t);
- if (value.type->align && byte_offset % value.type->align > 0)
- byte_offset += value.type->align - (byte_offset % value.type->align);
- return Text$concat(Text$format(colorize ? "\x1b[36;1m%s\x1b[m." : "%s.", type->EnumInfo.name),
- generic_as_text(obj + byte_offset, colorize, value.type));
- }
- case CustomInfo: case CStringInfo: // These all share the same info
- if (!type->CustomInfo.as_text)
- fail("No text function provided for type!\n");
- return type->CustomInfo.as_text(obj, colorize, type);
- case OpaqueInfo: return Text("???");
- default: fail("Invalid type tag: %d", type->tag);
- }
+ return type->metamethods.as_text(obj, colorize, type);
}
public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type)
@@ -264,5 +57,4 @@ public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type)
return Text$print(stdout, text) + printf("\n");
}
-
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/moments.c b/stdlib/moments.c
index 848626cb..ba72ff7f 100644
--- a/stdlib/moments.c
+++ b/stdlib/moments.c
@@ -25,14 +25,13 @@ static OptionalText_t _local_timezone = NONE_TEXT;
body; \
}})
-public Text_t Moment$as_text(const Moment_t *moment, bool colorize, const TypeInfo_t *type)
+public Text_t Moment$as_text(const void *moment, bool colorize, const TypeInfo_t*)
{
- (void)type;
if (!moment)
return Text("Moment");
struct tm info;
- struct tm *final_info = localtime_r(&moment->tv_sec, &info);
+ struct tm *final_info = localtime_r(&((Moment_t*)moment)->tv_sec, &info);
static char buf[256];
size_t len = strftime(buf, sizeof(buf), "%c %Z", final_info);
Text_t text = Text$format("%.*s", (int)len, buf);
@@ -41,9 +40,9 @@ public Text_t Moment$as_text(const Moment_t *moment, bool colorize, const TypeIn
return text;
}
-PUREFUNC public int32_t Moment$compare(const Moment_t *a, const Moment_t *b, const TypeInfo_t *type)
+PUREFUNC public int32_t Moment$compare(const void *va, const void *vb, const TypeInfo_t*)
{
- (void)type;
+ Moment_t *a = (Moment_t*)va, *b = (Moment_t*)vb;
if (a->tv_sec != b->tv_sec)
return (a->tv_sec > b->tv_sec) - (a->tv_sec < b->tv_sec);
return (a->tv_usec > b->tv_usec) - (a->tv_usec < b->tv_usec);
@@ -307,10 +306,9 @@ public Text_t Moment$get_local_timezone(void)
public const TypeInfo_t Moment$info = {
.size=sizeof(Moment_t),
.align=__alignof__(Moment_t),
- .tag=CustomInfo,
- .CustomInfo={
- .as_text=(void*)Moment$as_text,
- .compare=(void*)Moment$compare,
+ .metamethods={
+ .as_text=Moment$as_text,
+ .compare=Moment$compare,
},
};
diff --git a/stdlib/moments.h b/stdlib/moments.h
index 8e423124..48899b8b 100644
--- a/stdlib/moments.h
+++ b/stdlib/moments.h
@@ -10,8 +10,8 @@
#include "types.h"
#include "util.h"
-Text_t Moment$as_text(const Moment_t *moment, bool colorize, const TypeInfo_t *type);
-PUREFUNC int32_t Moment$compare(const Moment_t *a, const Moment_t *b, const TypeInfo_t *type);
+Text_t Moment$as_text(const void *moment, bool colorize, const TypeInfo_t *type);
+PUREFUNC int32_t Moment$compare(const void *a, const void *b, const TypeInfo_t *type);
Moment_t Moment$now(void);
Moment_t Moment$new(Int_t year, Int_t month, Int_t day, Int_t hour, Int_t minute, double second, OptionalText_t timezone);
Moment_t Moment$after(Moment_t moment, double seconds, double minutes, double hours, Int_t days, Int_t weeks, Int_t months, Int_t years, OptionalText_t timezone);
diff --git a/stdlib/nums.c b/stdlib/nums.c
index 4c9be226..47eb6851 100644
--- a/stdlib/nums.c
+++ b/stdlib/nums.c
@@ -13,13 +13,12 @@
#include "text.h"
#include "types.h"
-public PUREFUNC Text_t Num$as_text(const double *f, bool colorize, const TypeInfo_t *type) {
- (void)type;
+public PUREFUNC Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t*) {
if (!f) return Text("Num");
- return Text$format(colorize ? "\x1b[35m%.16g\x1b[33;2m\x1b[m" : "%.16g", *f);
+ return Text$format(colorize ? "\x1b[35m%.16g\x1b[33;2m\x1b[m" : "%.16g", *(double*)f);
}
-public PUREFUNC int32_t Num$compare(const double *x, const double *y, const TypeInfo_t *) {
+public PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t*) {
int64_t rx = *(int64_t*)x,
ry = *(int64_t*)y;
@@ -31,9 +30,8 @@ public PUREFUNC int32_t Num$compare(const double *x, const double *y, const Type
return (rx > ry) - (rx < ry);
}
-public PUREFUNC bool Num$equal(const double *x, const double *y, const TypeInfo_t *type) {
- (void)type;
- return *x == *y;
+public PUREFUNC bool Num$equal(const void *x, const void *y, const TypeInfo_t*) {
+ return *(double*)x == *(double*)y;
}
public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute) {
@@ -78,6 +76,11 @@ public OptionalNum_t Num$parse(Text_t text) {
return nan("null");
}
+static bool Num$is_none(const void *n, const TypeInfo_t*)
+{
+ return isnan(*(Num_t*)n);
+}
+
public CONSTFUNC bool Num$isinf(double n) { return (fpclassify(n) == FP_INFINITE); }
public CONSTFUNC bool Num$finite(double n) { return (fpclassify(n) != FP_INFINITE); }
public CONSTFUNC bool Num$isnan(double n) { return (fpclassify(n) == FP_NAN); }
@@ -85,28 +88,25 @@ public CONSTFUNC bool Num$isnan(double n) { return (fpclassify(n) == FP_NAN); }
public const TypeInfo_t Num$info = {
.size=sizeof(double),
.align=__alignof__(double),
- .tag=CustomInfo,
- .CustomInfo={
- .compare=(void*)Num$compare,
- .equal=(void*)Num$equal,
- .as_text=(void*)Num$as_text,
+ .metamethods={
+ .compare=Num$compare,
+ .equal=Num$equal,
+ .as_text=Num$as_text,
+ .is_none=Num$is_none,
},
};
-public PUREFUNC Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo_t *type) {
- (void)type;
+public PUREFUNC Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t*) {
if (!f) return Text("Num32");
- return Text$format(colorize ? "\x1b[35m%.8g\x1b[33;2m\x1b[m" : "%.8g", (double)*f);
+ return Text$format(colorize ? "\x1b[35m%.8g\x1b[33;2m\x1b[m" : "%.8g", (double)*(float*)f);
}
-public PUREFUNC int32_t Num32$compare(const float *x, const float *y, const TypeInfo_t *type) {
- (void)type;
- return (*x > *y) - (*x < *y);
+public PUREFUNC int32_t Num32$compare(const void *x, const void *y, const TypeInfo_t*) {
+ return (*(float*)x > *(float*)y) - (*(float*)x < *(float*)y);
}
-public PUREFUNC bool Num32$equal(const float *x, const float *y, const TypeInfo_t *type) {
- (void)type;
- return *x == *y;
+public PUREFUNC bool Num32$equal(const void *x, const void *y, const TypeInfo_t*) {
+ return *(float*)x == *(float*)y;
}
public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) {
@@ -151,6 +151,11 @@ public OptionalNum32_t Num32$parse(Text_t text) {
return nan("null");
}
+static bool Num32$is_none(const void *n, const TypeInfo_t*)
+{
+ return isnan(*(Num32_t*)n);
+}
+
public CONSTFUNC bool Num32$isinf(float n) { return (fpclassify(n) == FP_INFINITE); }
public CONSTFUNC bool Num32$finite(float n) { return (fpclassify(n) != FP_INFINITE); }
public CONSTFUNC bool Num32$isnan(float n) { return (fpclassify(n) == FP_NAN); }
@@ -158,11 +163,11 @@ public CONSTFUNC bool Num32$isnan(float n) { return (fpclassify(n) == FP_NAN); }
public const TypeInfo_t Num32$info = {
.size=sizeof(float),
.align=__alignof__(float),
- .tag=CustomInfo,
- .CustomInfo={
- .compare=(void*)Num32$compare,
- .equal=(void*)Num32$equal,
- .as_text=(void*)Num32$as_text,
+ .metamethods={
+ .compare=Num32$compare,
+ .equal=Num32$equal,
+ .as_text=Num32$as_text,
+ .is_none=Num32$is_none,
},
};
diff --git a/stdlib/nums.h b/stdlib/nums.h
index dc7f9ff8..f000ca8b 100644
--- a/stdlib/nums.h
+++ b/stdlib/nums.h
@@ -16,9 +16,9 @@
#define N32(n) ((float)n)
#define N64(n) ((double)n)
-Text_t Num$as_text(const double *f, bool colorize, const TypeInfo_t *type);
-PUREFUNC int32_t Num$compare(const double *x, const double *y, const TypeInfo_t *type);
-PUREFUNC bool Num$equal(const double *x, const double *y, const TypeInfo_t *type);
+Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *type);
+PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Num$equal(const void *x, const void *y, const TypeInfo_t *type);
CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute);
Text_t Num$format(double f, Int_t precision);
Text_t Num$scientific(double f, Int_t precision);
@@ -34,9 +34,9 @@ MACROLIKE CONSTFUNC double Num$clamped(double x, double low, double high) {
}
extern const TypeInfo_t Num$info;
-Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo_t *type);
-PUREFUNC int32_t Num32$compare(const float *x, const float *y, const TypeInfo_t *type);
-PUREFUNC bool Num32$equal(const float *x, const float *y, const TypeInfo_t *type);
+Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *type);
+PUREFUNC int32_t Num32$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Num32$equal(const void *x, const void *y, const TypeInfo_t *type);
CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute);
Text_t Num32$format(float f, Int_t precision);
Text_t Num32$scientific(float f, Int_t precision);
diff --git a/stdlib/optionals.c b/stdlib/optionals.c
index 2fb734f0..810f6172 100644
--- a/stdlib/optionals.c
+++ b/stdlib/optionals.c
@@ -15,55 +15,36 @@
public PUREFUNC bool is_null(const void *obj, const TypeInfo_t *non_optional_type)
{
- if (non_optional_type == &Int$info)
- return ((Int_t*)obj)->small == 0;
- else if (non_optional_type == &Bool$info)
- return *((OptionalBool_t*)obj) == NONE_BOOL;
- else if (non_optional_type == &Num$info)
- return isnan(*((Num_t*)obj));
- else if (non_optional_type == &Num32$info)
- return isnan(*((Num32_t*)obj));
- else if (non_optional_type == &Int64$info)
- return ((OptionalInt64_t*)obj)->is_null;
- else if (non_optional_type == &Int32$info)
- return ((OptionalInt32_t*)obj)->is_null;
- else if (non_optional_type == &Int16$info)
- return ((OptionalInt16_t*)obj)->is_null;
- else if (non_optional_type == &Int8$info)
- return ((OptionalInt8_t*)obj)->is_null;
- else if (non_optional_type == &Byte$info)
- return ((OptionalByte_t*)obj)->is_null;
- else if (non_optional_type == &Thread$info)
- return *(pthread_t**)obj == NULL;
- else if (non_optional_type == &Moment$info)
- return ((OptionalMoment_t*)obj)->tv_usec < 0;
- else if (non_optional_type == &Match$info)
- return ((OptionalMatch_t*)obj)->index.small == 0;
+ if (non_optional_type->metamethods.is_none)
+ return non_optional_type->metamethods.is_none(obj, non_optional_type);
- switch (non_optional_type->tag) {
- case ChannelInfo: return *(Channel_t**)obj == NULL;
- case PointerInfo: return *(void**)obj == NULL;
- case TextInfo: return ((Text_t*)obj)->length < 0;
- case ArrayInfo: return ((Array_t*)obj)->length < 0;
- case TableInfo: return ((Table_t*)obj)->entries.length < 0;
- case FunctionInfo: return *(void**)obj == NULL;
- case StructInfo: {
- int64_t offset = 0;
- for (int i = 0; i < non_optional_type->StructInfo.num_fields; i++) {
- NamedType_t field = non_optional_type->StructInfo.fields[i];
- if (offset > 0 && (offset % field.type->align) > 0)
- offset += field.type->align - (offset % field.type->align);
- offset += field.type->size;
- }
- return *(bool*)(obj + offset);
- }
- case EnumInfo: return (*(int*)obj) == 0; // NULL tag
- case CStringInfo: return (*(char**)obj) == NULL;
- default: {
- Text_t t = generic_as_text(NULL, false, non_optional_type);
- errx(1, "is_null() not implemented for: %k", &t);
- }
- }
+ return *(bool*)(obj + non_optional_type->size);
+}
+
+PUREFUNC public uint64_t Optional$hash(const void *obj, const TypeInfo_t *type)
+{
+ return is_null(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type);
+}
+
+PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const TypeInfo_t *type)
+{
+ if (x == y) return 0;
+ bool x_is_null = is_null(x, type->OptionalInfo.type);
+ bool y_is_null = is_null(y, type->OptionalInfo.type);
+ if (x_is_null && y_is_null) return 0;
+ else if (x_is_null != y_is_null) return (int32_t)y_is_null - (int32_t)x_is_null;
+ else return generic_compare(x, y, type->OptionalInfo.type);
+}
+
+PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo_t *type)
+{
+ if (x == y) return true;
+
+ bool x_is_null = is_null(x, type->OptionalInfo.type);
+ bool y_is_null = is_null(y, type->OptionalInfo.type);
+ if (x_is_null && y_is_null) return true;
+ else if (x_is_null != y_is_null) return false;
+ else return generic_equal(x, y, type->OptionalInfo.type);
}
public Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
diff --git a/stdlib/optionals.h b/stdlib/optionals.h
index 7d52375b..53f2aa9b 100644
--- a/stdlib/optionals.h
+++ b/stdlib/optionals.h
@@ -25,6 +25,20 @@
#define NONE_MOMENT ((OptionalMoment_t){.tv_usec=-1})
PUREFUNC bool is_null(const void *obj, const TypeInfo_t *non_optional_type);
+PUREFUNC uint64_t Optional$hash(const void *obj, const TypeInfo_t *type);
+PUREFUNC int32_t Optional$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Optional$equal(const void *x, const void *y, const TypeInfo_t *type);
Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type);
+#define Optional$metamethods ((metamethods_t){ \
+ .hash=Optional$hash, \
+ .compare=Optional$compare, \
+ .equal=Optional$equal, \
+ .as_text=Optional$as_text, \
+})
+
+#define Optional$info(_size, _align, t) &((TypeInfo_t){.size=_size, .align=_align, \
+ .tag=OptionalInfo, .OptionalInfo.type=t, \
+ .metamethods=Optional$metamethods})
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/paths.c b/stdlib/paths.c
index ee73647d..98bcab56 100644
--- a/stdlib/paths.c
+++ b/stdlib/paths.c
@@ -89,7 +89,7 @@ public Path_t Path$cleanup(Path_t path)
} else { // (../..) -> (../..)
i += 1;
}
- } else if (Text$equal(&component, (Path_t*)(components.data + (i-1)*components.stride))) { // (___/../..) -> (____/../..)
+ } else if (Text$equal(&component, (Path_t*)(components.data + (i-1)*components.stride), &Text$info)) { // (___/../..) -> (____/../..)
i += 1;
} else { // (___/foo/..) -> (___)
Array$remove_at(&components, I(i), I(2), sizeof(Path_t));
@@ -569,6 +569,7 @@ public const TypeInfo_t Path$info = {
.align=__alignof__(Path_t),
.tag=TextInfo,
.TextInfo={.lang="Path"},
+ .metamethods=Text$metamethods,
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/patterns.c b/stdlib/patterns.c
index 3bf2ebfd..f6a7aa85 100644
--- a/stdlib/patterns.c
+++ b/stdlib/patterns.c
@@ -9,6 +9,7 @@
#include "integers.h"
#include "optionals.h"
#include "patterns.h"
+#include "structs.h"
#include "tables.h"
#include "text.h"
#include "types.h"
@@ -1160,6 +1161,7 @@ public const TypeInfo_t Pattern$info = {
.align=__alignof__(Pattern_t),
.tag=TextInfo,
.TextInfo={.lang="Pattern"},
+ .metamethods=Text$metamethods,
};
static NamedType_t _match_fields[3] = {
@@ -1167,6 +1169,12 @@ static NamedType_t _match_fields[3] = {
{"index", &Int$info},
{"captures", Array$info(&Text$info)},
};
+
+static bool Match$is_none(const void *m, const TypeInfo_t*)
+{
+ return ((OptionalMatch_t*)m)->index.small == 0;
+}
+
public const TypeInfo_t Match$info = {
.size=sizeof(Match_t),
.align=__alignof__(Match_t),
@@ -1176,6 +1184,13 @@ public const TypeInfo_t Match$info = {
.num_fields=3,
.fields=_match_fields,
},
+ .metamethods={
+ .as_text=Struct$as_text,
+ .hash=Struct$hash,
+ .compare=Struct$compare,
+ .equal=Struct$equal,
+ .is_none=Match$is_none,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/pointers.c b/stdlib/pointers.c
index 41defb95..97c7f5d1 100644
--- a/stdlib/pointers.c
+++ b/stdlib/pointers.c
@@ -45,8 +45,7 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *ty
} else if (ptr == root) {
return Text$format(colorize ? "\x1b[34;1m%s~1\x1b[m" : "%s~1", ptr_info.sigil);
} else {
- TypeInfo_t rec_table = ((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
- .tag=TableInfo, .TableInfo.key=type, .TableInfo.value=&Int64$info});
+ TypeInfo_t rec_table = *Table$info(type, &Int64$info);
int64_t *id = Table$get(pending, x, &rec_table);
if (id)
return Text$format(colorize ? "\x1b[34;1m%s~%ld\x1b[m" : "%s~%ld", ptr_info.sigil, *id);
@@ -69,16 +68,19 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *ty
return text;
}
-PUREFUNC public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t *type) {
- (void)type;
+PUREFUNC public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t*) {
const void *xp = *(const void**)x, *yp = *(const void**)y;
return (xp > yp) - (xp < yp);
}
-PUREFUNC public bool Pointer$equal(const void *x, const void *y, const TypeInfo_t *type) {
- (void)type;
+PUREFUNC public bool Pointer$equal(const void *x, const void *y, const TypeInfo_t*) {
const void *xp = *(const void**)x, *yp = *(const void**)y;
return xp == yp;
}
+PUREFUNC public bool Pointer$is_none(const void *x, const TypeInfo_t*)
+{
+ return *(void**)x == NULL;
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/pointers.h b/stdlib/pointers.h
index 116160fd..0c9f2ade 100644
--- a/stdlib/pointers.h
+++ b/stdlib/pointers.h
@@ -11,9 +11,21 @@
Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type);
PUREFUNC int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool Pointer$equal(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Pointer$is_none(const void *x, const TypeInfo_t*);
#define Null(t) (t*)NULL
#define POINTER_TYPE(_sigil, _pointed) (&(TypeInfo_t){\
.size=sizeof(void*), .align=alignof(void*), .tag=PointerInfo, .PointerInfo.sigil=_sigil, .PointerInfo.pointed=_pointed})
+#define Pointer$metamethods ((metamethods_t){ \
+ .as_text=Pointer$as_text, \
+ .compare=Pointer$compare, \
+ .equal=Pointer$equal, \
+ .is_none=Pointer$is_none, \
+})
+
+#define Pointer$info(sigil_expr, pointed_info) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
+ .tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info}, \
+ .metamethods=Pointer$metamethods})
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/ranges.c b/stdlib/ranges.c
index 3f673b52..dfb878ea 100644
--- a/stdlib/ranges.c
+++ b/stdlib/ranges.c
@@ -15,10 +15,10 @@
#include "util.h"
-PUREFUNC static int32_t Range$compare(const Range_t *x, const Range_t *y, const TypeInfo_t *type)
+PUREFUNC static int32_t Range$compare(const void *vx, const void *vy, const TypeInfo_t *)
{
- (void)type;
- if (x == y) return 0;
+ if (vx == vy) return 0;
+ Range_t *x = (Range_t*)vx, *y = (Range_t*)vy;
int32_t diff = Int$compare(&x->first, &y->first, &Int$info);
if (diff != 0) return diff;
diff = Int$compare(&x->last, &y->last, &Int$info);
@@ -26,18 +26,18 @@ PUREFUNC static int32_t Range$compare(const Range_t *x, const Range_t *y, const
return Int$compare(&x->step, &y->step, &Int$info);
}
-PUREFUNC static bool Range$equal(const Range_t *x, const Range_t *y, const TypeInfo_t *type)
+PUREFUNC static bool Range$equal(const void *vx, const void *vy, const TypeInfo_t*)
{
- (void)type;
- if (x == y) return true;
+ if (vx == vy) return true;
+ Range_t *x = (Range_t*)vx, *y = (Range_t*)vy;
return Int$equal(&x->first, &y->first, &Int$info) && Int$equal(&x->last, &y->last, &Int$info) && Int$equal(&x->step, &y->step, &Int$info);
}
-static Text_t Range$as_text(const Range_t *r, bool use_color, const TypeInfo_t *type)
+static Text_t Range$as_text(const void *obj, bool use_color, const TypeInfo_t *)
{
- (void)type;
- if (!r) return Text("Range");
+ if (!obj) return Text("Range");
+ Range_t *r = (Range_t*)obj;
Text_t first = Int$as_text(&r->first, use_color, &Int$info);
Text_t last = Int$as_text(&r->last, use_color, &Int$info);
Text_t step = Int$as_text(&r->step, use_color, &Int$info);
@@ -55,10 +55,20 @@ PUREFUNC public Range_t Range$by(Range_t r, Int_t step)
return (Range_t){r.first, r.last, Int$times(step, r.step)};
}
-public const TypeInfo_t Range$info = {sizeof(Range_t), __alignof(Range_t), {.tag=CustomInfo, .CustomInfo={
- .as_text=(void*)Range$as_text,
- .compare=(void*)Range$compare,
- .equal=(void*)Range$equal,
-}}};
+static bool Range$is_none(const void *obj, const TypeInfo_t*)
+{
+ return ((Range_t*)obj)->step.small == 0x1;
+}
+
+public const TypeInfo_t Range$info = {
+ .size=sizeof(Range_t),
+ .align=__alignof(Range_t),
+ .metamethods={
+ .as_text=Range$as_text,
+ .compare=Range$compare,
+ .equal=Range$equal,
+ .is_none=Range$is_none,
+ },
+};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/rng.c b/stdlib/rng.c
index 357537b6..8104c451 100644
--- a/stdlib/rng.c
+++ b/stdlib/rng.c
@@ -26,11 +26,10 @@ struct RNGState_t {
uint8_t random_bytes[1024];
};
-PUREFUNC static Text_t RNG$as_text(const RNG_t *rng, bool colorize, const TypeInfo_t *type)
+PUREFUNC static Text_t RNG$as_text(const void *rng, bool colorize, const TypeInfo_t*)
{
- (void)type;
if (!rng) return Text("RNG");
- return Text$format(colorize ? "\x1b[34;1mRNG(%p)\x1b[m" : "RNG(%p)", *rng);
+ return Text$format(colorize ? "\x1b[34;1mRNG(%p)\x1b[m" : "RNG(%p)", *(RNG_t**)rng);
}
#define KEYSZ 32
@@ -259,8 +258,9 @@ public Array_t RNG$bytes(RNG_t rng, Int_t count)
public const TypeInfo_t RNG$info = {
.size=sizeof(void*),
.align=__alignof__(void*),
- .tag=CustomInfo,
- .CustomInfo={.as_text=(void*)RNG$as_text},
+ .metamethods={
+ .as_text=RNG$as_text,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/shell.c b/stdlib/shell.c
index ec78f5e7..4a48f5c2 100644
--- a/stdlib/shell.c
+++ b/stdlib/shell.c
@@ -141,6 +141,7 @@ public const TypeInfo_t Shell$info = {
.align=__alignof__(Shell_t),
.tag=TextInfo,
.TextInfo={.lang="Shell"},
+ .metamethods=Text$metamethods,
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/stdlib.c b/stdlib/stdlib.c
index 5d51f651..6d0ddcad 100644
--- a/stdlib/stdlib.c
+++ b/stdlib/stdlib.c
@@ -467,12 +467,12 @@ public void end_test(const void *expr, const TypeInfo_t *type, const char *expec
if (expected && expected[0]) {
Text_t expected_text = Text$from_str(expected);
Text_t expr_plain = USE_COLOR ? generic_as_text(expr, false, type) : expr_text;
- bool success = Text$equal(&expr_plain, &expected_text);
+ bool success = Text$equal(&expr_plain, &expected_text, &Text$info);
if (!success) {
OptionalMatch_t colon = Text$find(expected_text, Text(":"), I_small(1));
if (colon.index.small) {
Text_t with_type = Text$concat(expr_plain, Text(" : "), type_name);
- success = Text$equal(&with_type, &expected_text);
+ success = Text$equal(&with_type, &expected_text, &Text$info);
}
}
diff --git a/stdlib/structs.c b/stdlib/structs.c
new file mode 100644
index 00000000..c23e4b7b
--- /dev/null
+++ b/stdlib/structs.c
@@ -0,0 +1,170 @@
+// Metamethods for structs
+
+#include <stdint.h>
+#include <string.h>
+
+#include "arrays.h"
+#include "bools.h"
+#include "channels.h"
+#include "functiontype.h"
+#include "metamethods.h"
+#include "optionals.h"
+#include "pointers.h"
+#include "siphash.h"
+#include "tables.h"
+#include "text.h"
+#include "util.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstack-protector"
+PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type)
+{
+ if (type->StructInfo.num_fields == 0)
+ return 0;
+
+ if (type->StructInfo.num_fields == 1)
+ return generic_hash(obj, type->StructInfo.fields[0].type);
+
+ uint32_t field_hashes[type->StructInfo.num_fields] = {};
+ ptrdiff_t byte_offset = 0;
+ ptrdiff_t bit_offset = 0;
+ for (int i = 0; i < type->StructInfo.num_fields; i++) {
+ NamedType_t field = type->StructInfo.fields[i];
+ if (field.type == &Bool$info) {
+ bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
+ field_hashes[i] = (uint32_t)b;
+ bit_offset += 1;
+ if (bit_offset >= 8) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ } else {
+ if (bit_offset > 0) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ if (field.type->align && byte_offset % field.type->align > 0)
+ byte_offset += field.type->align - (byte_offset % field.type->align);
+ field_hashes[i] = generic_hash(obj + byte_offset, field.type);
+ byte_offset += field.type->size;
+ }
+ }
+ return siphash24((void*)field_hashes, sizeof(field_hashes));
+}
+#pragma GCC diagnostic pop
+
+PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type)
+{
+ if (x == y)
+ return 0;
+
+ ptrdiff_t byte_offset = 0;
+ ptrdiff_t bit_offset = 0;
+ for (int i = 0; i < type->StructInfo.num_fields; i++) {
+ NamedType_t field = type->StructInfo.fields[i];
+ if (field.type == &Bool$info) {
+ bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1;
+ bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1;
+ if (bx != by)
+ return (int32_t)bx - (int32_t)by;
+ bit_offset += 1;
+ if (bit_offset >= 8) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ } else {
+ if (bit_offset > 0) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ if (field.type->align && byte_offset % field.type->align > 0)
+ byte_offset += field.type->align - (byte_offset % field.type->align);
+ int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type);
+ if (cmp != 0)
+ return cmp;
+ byte_offset += field.type->size;
+ }
+ }
+ return 0;
+}
+
+PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type)
+{
+ if (x == y)
+ return true;
+
+ ptrdiff_t byte_offset = 0;
+ ptrdiff_t bit_offset = 0;
+ for (int i = 0; i < type->StructInfo.num_fields; i++) {
+ NamedType_t field = type->StructInfo.fields[i];
+ if (field.type == &Bool$info) {
+ bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1;
+ bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1;
+ if (bx != by)
+ return false;
+ bit_offset += 1;
+ if (bit_offset >= 8) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ } else {
+ if (bit_offset > 0) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ if (field.type->align && byte_offset % field.type->align > 0)
+ byte_offset += field.type->align - (byte_offset % field.type->align);
+ if (!generic_equal(x + byte_offset, y + byte_offset, field.type))
+ return false;
+ byte_offset += field.type->size;
+ }
+ }
+ return true;
+}
+
+PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
+{
+ if (!obj) return Text$from_str(type->StructInfo.name);
+
+ if (type->StructInfo.is_secret)
+ return Text$format(colorize ? "\x1b[0;1m%s\x1b[m(...)" : "%s(...)", type->StructInfo.name);
+
+ Text_t text = Text$format(colorize ? "\x1b[0;1m%s\x1b[m(" : "%s(", type->StructInfo.name);
+ ptrdiff_t byte_offset = 0;
+ ptrdiff_t bit_offset = 0;
+ for (int i = 0; i < type->StructInfo.num_fields; i++) {
+ NamedType_t field = type->StructInfo.fields[i];
+ if (i > 0)
+ text = Text$concat(text, Text(", "));
+
+ if (type->StructInfo.num_fields > 1)
+ text = Text$concat(text, Text$from_str(field.name), Text("="));
+
+ if (field.type == &Bool$info) {
+ bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
+ text = Text$concat(text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no")));
+ bit_offset += 1;
+ if (bit_offset >= 8) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ } else {
+ if (bit_offset > 0) {
+ byte_offset += 1;
+ bit_offset = 0;
+ }
+ if (field.type->align && byte_offset % field.type->align > 0)
+ byte_offset += field.type->align - (byte_offset % field.type->align);
+ text = Text$concat(text, generic_as_text(obj + byte_offset, colorize, field.type));
+ byte_offset += field.type->size;
+ }
+ }
+ return Text$concat(text, Text(")"));
+}
+
+PUREFUNC public bool Struct$is_none(const void *obj, const TypeInfo_t *type)
+{
+ return *(bool*)(obj + type->size);
+}
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/structs.h b/stdlib/structs.h
new file mode 100644
index 00000000..b41dde77
--- /dev/null
+++ b/stdlib/structs.h
@@ -0,0 +1,24 @@
+// Metamethods for structs
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "datatypes.h"
+#include "types.h"
+#include "util.h"
+
+PUREFUNC uint64_t Struct$hash(const void *obj, const TypeInfo_t *type);
+PUREFUNC int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type);
+PUREFUNC bool Struct$is_none(const void *obj, const TypeInfo_t *type);
+
+#define Struct$metamethods ((metamethods_t){ \
+ .hash=Struct$hash, \
+ .compare=Struct$compare, \
+ .equal=Struct$equal, \
+ .as_text=Struct$as_text, \
+ .is_none=Struct$is_none, \
+})
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/tables.c b/stdlib/tables.c
index e55b1f5f..97fee8af 100644
--- a/stdlib/tables.c
+++ b/stdlib/tables.c
@@ -21,6 +21,7 @@
#include "datatypes.h"
#include "memory.h"
#include "metamethods.h"
+#include "pointers.h"
#include "siphash.h"
#include "tables.h"
#include "text.h"
@@ -42,7 +43,7 @@
#define GET_ENTRY(t, i) ((t).entries.data + (t).entries.stride*(i))
-static const TypeInfo_t MemoryPointer = {
+static TypeInfo_t MemoryPointer = {
.size=sizeof(void*),
.align=__alignof__(void*),
.tag=PointerInfo,
@@ -50,6 +51,7 @@ static const TypeInfo_t MemoryPointer = {
.sigil="@",
.pointed=&Memory$info,
},
+ .metamethods=Pointer$metamethods,
};
const TypeInfo_t CStrToVoidStarTable = {
@@ -57,6 +59,7 @@ const TypeInfo_t CStrToVoidStarTable = {
.align=__alignof__(Table_t),
.tag=TableInfo,
.TableInfo={.key=&CString$info, .value=&MemoryPointer},
+ .metamethods=Table$metamethods,
};
PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info)
@@ -396,9 +399,10 @@ public Table_t Table$sorted(Table_t t, const TypeInfo_t *type)
return Table$from_entries(entries, type);
}
-PUREFUNC public bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo_t *type)
+PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_t *type)
{
- if (x == y) return true;
+ if (vx == vy) return true;
+ Table_t *x = (Table_t*)vx, *y = (Table_t*)vy;
assert(type->tag == TableInfo);
if (Table$length(*x) != Table$length(*y))
@@ -410,10 +414,11 @@ PUREFUNC public bool Table$equal(const Table_t *x, const Table_t *y, const TypeI
return (Table$compare(x, y, type) == 0);
}
-PUREFUNC public int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo_t *type)
+PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const TypeInfo_t *type)
{
- if (x == y) return 0;
+ if (vx == vy) return 0;
+ Table_t *x = (Table_t*)vx, *y = (Table_t*)vy;
assert(type->tag == TableInfo);
auto table = type->TableInfo;
if (x->entries.length == 0)
@@ -441,9 +446,10 @@ PUREFUNC public int32_t Table$compare(const Table_t *x, const Table_t *y, const
return 0;
}
-PUREFUNC public uint64_t Table$hash(const Table_t *t, const TypeInfo_t *type)
+PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type)
{
assert(type->tag == TableInfo);
+ Table_t *t = (Table_t*)obj;
// Table hashes are computed as:
// hash(hash(t.keys), hash(t.values), hash(t.fallback), hash(t.default))
// Where fallback and default hash to zero if absent
@@ -456,8 +462,9 @@ PUREFUNC public uint64_t Table$hash(const Table_t *t, const TypeInfo_t *type)
return siphash24((void*)&components, sizeof(components));
}
-public Text_t Table$as_text(const Table_t *t, bool colorize, const TypeInfo_t *type)
+public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
{
+ Table_t *t = (Table_t*)obj;
assert(type->tag == TableInfo);
auto table = type->TableInfo;
@@ -635,4 +642,9 @@ CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n)
return Table$entry(t, n);
}
+PUREFUNC public bool Table$is_none(const void *obj, const TypeInfo_t*)
+{
+ return ((Table_t*)obj)->entries.length < 0;
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
diff --git a/stdlib/tables.h b/stdlib/tables.h
index 14b50ef8..1f62a13a 100644
--- a/stdlib/tables.h
+++ b/stdlib/tables.h
@@ -65,10 +65,11 @@ Table_t Table$sorted(Table_t t, const TypeInfo_t *type);
void Table$mark_copy_on_write(Table_t *t);
#define TABLE_INCREF(t) ({ ARRAY_INCREF((t).entries); if ((t).bucket_info) (t).bucket_info->data_refcount += ((t).bucket_info->data_refcount < TABLE_MAX_DATA_REFCOUNT); })
#define TABLE_COPY(t) ({ TABLE_INCREF(t); t; })
-PUREFUNC int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo_t *type);
-PUREFUNC bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo_t *type);
-PUREFUNC uint64_t Table$hash(const Table_t *t, const TypeInfo_t *type);
-Text_t Table$as_text(const Table_t *t, bool colorize, const TypeInfo_t *type);
+PUREFUNC int32_t Table$compare(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC bool Table$equal(const void *x, const void *y, const TypeInfo_t *type);
+PUREFUNC uint64_t Table$hash(const void *t, const TypeInfo_t *type);
+Text_t Table$as_text(const void *t, bool colorize, const TypeInfo_t *type);
+PUREFUNC bool Table$is_none(const void *obj, const TypeInfo_t*);
CONSTFUNC void *Table$str_entry(Table_t t, int64_t n);
PUREFUNC void *Table$str_get(Table_t t, const char *key);
@@ -81,4 +82,17 @@ void Table$str_remove(Table_t *t, const char *key);
extern const TypeInfo_t CStrToVoidStarTable;
+#define Table$metamethods ((metamethods_t){ \
+ .as_text=Table$as_text, \
+ .compare=Table$compare, \
+ .equal=Table$equal, \
+ .hash=Table$hash, \
+ .is_none=Table$is_none, \
+})
+
+#define Table$info(key_expr, value_expr) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
+ .tag=TableInfo, .TableInfo.key=key_expr, .TableInfo.value=value_expr, .metamethods=Table$metamethods})
+#define Set$info(item_info) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
+ .tag=TableInfo, .TableInfo.key=item_info, .TableInfo.value=&Void$info, .metamethods=Table$metamethods})
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
diff --git a/stdlib/text.c b/stdlib/text.c
index 8a05f968..40a3988b 100644
--- a/stdlib/text.c
+++ b/stdlib/text.c
@@ -92,28 +92,27 @@ static int32_t num_synthetic_graphemes = 0;
static Text_t text_from_u32(ucs4_t *codepoints, int64_t num_codepoints, bool normalize);
-PUREFUNC static bool graphemes_equal(ucs4_t **a, ucs4_t **b) {
- if ((*a)[0] != (*b)[0]) return false;
- for (int i = 0; i < (int)(*a)[0]; i++)
- if ((*a)[i] != (*b)[i]) return false;
+PUREFUNC static bool graphemes_equal(const void *va, const void *vb, const TypeInfo_t*) {
+ ucs4_t *a = *(ucs4_t**)va;
+ ucs4_t *b = *(ucs4_t**)vb;
+ if (a[0] != b[0]) return false;
+ for (int i = 0; i < (int)a[0]; i++)
+ if (a[i] != b[i]) return false;
return true;
}
-PUREFUNC static uint64_t grapheme_hash(ucs4_t **g) {
- ucs4_t *cluster = *g;
+PUREFUNC static uint64_t grapheme_hash(const void *g, const TypeInfo_t*) {
+ ucs4_t *cluster = *(ucs4_t**)g;
return siphash24((void*)&cluster[1], sizeof(ucs4_t[cluster[0]]));
}
static const TypeInfo_t GraphemeClusterInfo = {
.size=sizeof(ucs4_t*),
.align=__alignof__(ucs4_t*),
- .tag=CustomInfo,
- .CustomInfo={.equal=(void*)graphemes_equal, .hash=(void*)grapheme_hash},
-};
-
-static const TypeInfo_t GraphemeIDLookupTableInfo = {
- .size=sizeof(Table_t), .align=__alignof__(Table_t),
- .tag=TableInfo, .TableInfo={.key=&GraphemeClusterInfo, .value=&Int32$info},
+ .metamethods={
+ .equal=graphemes_equal,
+ .hash=grapheme_hash,
+ },
};
#pragma GCC diagnostic push
@@ -128,9 +127,10 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le
// Optimization for common case of one frequently used synthetic grapheme:
static int32_t last_grapheme = 0;
- if (last_grapheme != 0 && graphemes_equal(&ptr, &synthetic_graphemes[-last_grapheme-1].utf32_cluster))
+ if (last_grapheme != 0 && graphemes_equal(&ptr, &synthetic_graphemes[-last_grapheme-1].utf32_cluster, NULL))
return last_grapheme;
+ TypeInfo_t GraphemeIDLookupTableInfo = *Table$info(&GraphemeClusterInfo, &Int32$info);
int32_t *found = Table$get(grapheme_ids_by_codepoints, &ptr, &GraphemeIDLookupTableInfo);
if (found) return *found;
@@ -765,8 +765,9 @@ public char *Text$as_c_string(Text_t text)
return buf;
}
-PUREFUNC public uint64_t Text$hash(Text_t *text)
+PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t*)
{
+ Text_t *text = (Text_t*)obj;
if (text->hash != 0) return text->hash;
siphash sh;
siphashinit(&sh, sizeof(int32_t[text->length]));
@@ -906,9 +907,11 @@ public uint32_t Text$get_main_grapheme_fast(TextIter_t *state, int64_t index)
return (g) >= 0 ? (ucs4_t)(g) : synthetic_graphemes[-(g)-1].main_codepoint;
}
-PUREFUNC public int32_t Text$compare(const Text_t *a, const Text_t *b)
+PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t*)
{
- if (a == b) return 0;
+ if (va == vb) return 0;
+ const Text_t *a = (const Text_t*)va;
+ const Text_t *b = (const Text_t*)vb;
int64_t len = MAX(a->length, b->length);
TextIter_t a_state = {*a, 0, 0}, b_state = {*b, 0, 0};
@@ -981,10 +984,10 @@ PUREFUNC public bool Text$equal_values(Text_t a, Text_t b)
return true;
}
-PUREFUNC public bool Text$equal(const Text_t *a, const Text_t *b)
+PUREFUNC public bool Text$equal(const void *a, const void *b, const TypeInfo_t*)
{
if (a == b) return true;
- return Text$equal_values(*a, *b);
+ return Text$equal_values(*(Text_t*)a, *(Text_t*)b);
}
PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b)
@@ -1369,11 +1372,17 @@ public Array_t Text$lines(Text_t text)
return lines;
}
+PUREFUNC public bool Text$is_none(const void *t, const TypeInfo_t*)
+{
+ return ((Text_t*)t)->length < 0;
+}
+
public const TypeInfo_t Text$info = {
.size=sizeof(Text_t),
.align=__alignof__(Text_t),
.tag=TextInfo,
.TextInfo={.lang="Text"},
+ .metamethods=Text$metamethods,
};
public Pattern_t Pattern$escape_text(Text_t text)
diff --git a/stdlib/text.h b/stdlib/text.h
index 4f23834f..04c867c5 100644
--- a/stdlib/text.h
+++ b/stdlib/text.h
@@ -10,6 +10,7 @@
#include "datatypes.h"
#include "integers.h"
#include "optionals.h"
+#include "types.h"
#include "util.h"
typedef struct {
@@ -31,11 +32,12 @@ Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int);
Text_t Text$cluster(Text_t text, Int_t index_int);
OptionalText_t Text$from_str(const char *str);
OptionalText_t Text$from_strn(const char *str, size_t len);
-PUREFUNC uint64_t Text$hash(Text_t *text);
-PUREFUNC int32_t Text$compare(const Text_t *a, const Text_t *b);
-PUREFUNC bool Text$equal(const Text_t *a, const Text_t *b);
+PUREFUNC uint64_t Text$hash(const void *text, const TypeInfo_t*);
+PUREFUNC int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t*);
+PUREFUNC bool Text$equal(const void *a, const void *b, const TypeInfo_t*);
PUREFUNC bool Text$equal_values(Text_t a, Text_t b);
PUREFUNC bool Text$equal_ignoring_case(Text_t a, Text_t b);
+PUREFUNC bool Text$is_none(const void *t, const TypeInfo_t*);
Text_t Text$upper(Text_t text);
Text_t Text$lower(Text_t text);
Text_t Text$title(Text_t text);
@@ -67,4 +69,12 @@ MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index)
extern const TypeInfo_t Text$info;
+#define Text$metamethods ((metamethods_t){ \
+ .as_text=Text$as_text, \
+ .hash=Text$hash, \
+ .compare=Text$compare, \
+ .equal=Text$equal, \
+ .is_none=Text$is_none, \
+})
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/threads.c b/stdlib/threads.c
index 3ae2980b..860b4880 100644
--- a/stdlib/threads.c
+++ b/stdlib/threads.c
@@ -53,19 +53,25 @@ public void Thread$detach(Thread_t thread)
pthread_detach(*thread);
}
-Text_t Thread$as_text(const Thread_t *thread, bool colorize, const TypeInfo_t *type)
+Text_t Thread$as_text(const void *thread, bool colorize, const TypeInfo_t*)
{
- (void)type;
if (!thread) {
return colorize ? Text("\x1b[34;1mThread\x1b[m") : Text("Thread");
}
- return Text$format(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *thread);
+ return Text$format(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *(Thread_t**)thread);
+}
+
+static bool Thread$is_none(const void *obj, const TypeInfo_t*)
+{
+ return *(Thread_t*)obj == NULL;
}
public const TypeInfo_t Thread$info = {
.size=sizeof(Thread_t), .align=__alignof(Thread_t),
- .tag=CustomInfo,
- .CustomInfo={.as_text=(void*)Thread$as_text},
+ .metamethods={
+ .as_text=Thread$as_text,
+ .is_none=Thread$is_none,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/threads.h b/stdlib/threads.h
index 049b0116..9f1c3d33 100644
--- a/stdlib/threads.h
+++ b/stdlib/threads.h
@@ -15,7 +15,7 @@ Thread_t Thread$new(Closure_t fn);
void Thread$cancel(Thread_t thread);
void Thread$join(Thread_t thread);
void Thread$detach(Thread_t thread);
-Text_t Thread$as_text(const Thread_t *thread, bool colorize, const TypeInfo_t *type);
+Text_t Thread$as_text(const void *thread, bool colorize, const TypeInfo_t *type);
extern const TypeInfo_t Thread$info;
diff --git a/stdlib/tomo.h b/stdlib/tomo.h
index 159b6426..03257937 100644
--- a/stdlib/tomo.h
+++ b/stdlib/tomo.h
@@ -13,6 +13,7 @@
#include "c_strings.h"
#include "channels.h"
#include "datatypes.h"
+#include "enums.h"
#include "functiontype.h"
#include "integers.h"
#include "memory.h"
@@ -27,6 +28,7 @@
#include "rng.h"
#include "shell.h"
#include "siphash.h"
+#include "structs.h"
#include "tables.h"
#include "text.h"
#include "threads.h"
diff --git a/stdlib/types.h b/stdlib/types.h
index a8a9b4e6..652a2e70 100644
--- a/stdlib/types.h
+++ b/stdlib/types.h
@@ -9,10 +9,13 @@
typedef struct TypeInfo_s TypeInfo_t;
-typedef uint64_t (*hash_fn_t)(const void*, const TypeInfo_t*);
-typedef int32_t (*compare_fn_t)(const void*, const void*, const TypeInfo_t*);
-typedef bool (*equal_fn_t)(const void*, const void*, const TypeInfo_t*);
-typedef Text_t (*text_fn_t)(const void*, bool, const TypeInfo_t*);
+typedef struct {
+ uint64_t (*hash)(const void*, const TypeInfo_t*);
+ int32_t (*compare)(const void*, const void*, const TypeInfo_t*);
+ bool (*equal)(const void*, const void*, const TypeInfo_t*);
+ Text_t (*as_text)(const void*, bool, const TypeInfo_t*);
+ bool (*is_none)(const void*, const TypeInfo_t*);
+} metamethods_t;
typedef struct {
const char *name;
@@ -21,16 +24,12 @@ typedef struct {
struct TypeInfo_s {
int64_t size, align;
+ metamethods_t metamethods;
struct { // Anonymous tagged union for convenience
- enum { Invalid, CustomInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo,
- OptionalInfo, TypeInfoInfo, OpaqueInfo, CStringInfo } tag;
+ enum { OpaqueInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo,
+ OptionalInfo, TypeInfoInfo } tag;
union {
- struct {
- equal_fn_t equal;
- compare_fn_t compare;
- hash_fn_t hash;
- text_fn_t as_text;
- } CustomInfo;
+ struct {} OpaqueInfo;
struct {
const char *sigil;
const TypeInfo_t *pointed;
@@ -53,7 +52,6 @@ struct TypeInfo_s {
struct {
const TypeInfo_t *type;
} OptionalInfo;
- struct {} OpaqueInfo;
struct {
const char *name;
int num_tags;
@@ -69,24 +67,8 @@ struct TypeInfo_s {
};
};
-#define Pointer$info(sigil_expr, pointed_info) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
- .tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info}})
-#define Array$info(item_info) &((TypeInfo_t){.size=sizeof(Array_t), .align=__alignof__(Array_t), \
- .tag=ArrayInfo, .ArrayInfo.item=item_info})
-#define Set$info(item_info) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
- .tag=TableInfo, .TableInfo.key=item_info, .TableInfo.value=&Void$info})
-#define Channel$info(item_info) &((TypeInfo_t){.size=sizeof(Channel_t), .align=__alignof__(Channel_t), \
- .tag=ChannelInfo, .ChannelInfo.item=item_info})
-#define Table$info(key_expr, value_expr) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
- .tag=TableInfo, .TableInfo.key=key_expr, .TableInfo.value=value_expr})
-#define Function$info(typestr) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
- .tag=FunctionInfo, .FunctionInfo.type_str=typestr})
-#define Closure$info(typestr) &((TypeInfo_t){.size=sizeof(void*[2]), .align=__alignof__(void*), \
- .tag=FunctionInfo, .FunctionInfo.type_str=typestr})
#define Type$info(typestr) &((TypeInfo_t){.size=sizeof(TypeInfo_t), .align=__alignof__(TypeInfo_t), \
.tag=TypeInfoInfo, .TypeInfoInfo.type_str=typestr})
-#define Optional$info(_size, _align, t) &((TypeInfo_t){.size=_size, .align=_align, \
- .tag=OptionalInfo, .OptionalInfo.type=t})
extern const TypeInfo_t Void$info;
extern const TypeInfo_t Abort$info;