aboutsummaryrefslogtreecommitdiff
path: root/builtins
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-09-11 01:31:31 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-09-11 01:31:31 -0400
commit7126755275f12e6278031e78ff33f65801b133dd (patch)
tree7f43f3449eb7bb69b0879dd41eb174e89fdc34cc /builtins
parent89234e34e292861fccb8e5bdbefc695a7e443eea (diff)
Add optional types
Diffstat (limited to 'builtins')
-rw-r--r--builtins/functions.c11
-rw-r--r--builtins/optionals.c49
-rw-r--r--builtins/optionals.h25
-rw-r--r--builtins/pointer.c9
-rw-r--r--builtins/tomo.h1
-rw-r--r--builtins/types.c1
-rw-r--r--builtins/types.h13
7 files changed, 96 insertions, 13 deletions
diff --git a/builtins/functions.c b/builtins/functions.c
index b4e1a5cc..d6778d4c 100644
--- a/builtins/functions.c
+++ b/builtins/functions.c
@@ -16,6 +16,7 @@
#include "files.h"
#include "functions.h"
#include "integers.h"
+#include "optionals.h"
#include "pointer.h"
#include "siphash.h"
#include "string.h"
@@ -113,6 +114,9 @@ PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo *type)
case ArrayInfo: return Array$hash(obj, type);
case ChannelInfo: return Channel$hash((const channel_t**)obj, type);
case TableInfo: return Table$hash(obj, type);
+ case OptionalInfo: {
+ errx(1, "Optional hash not implemented");
+ }
case EmptyStruct: return 0;
case CustomInfo:
if (!type->CustomInfo.hash)
@@ -135,6 +139,9 @@ PUREFUNC public int32_t generic_compare(const void *x, const void *y, const Type
case ArrayInfo: return Array$compare(x, y, type);
case ChannelInfo: return Channel$compare((const channel_t**)x, (const channel_t**)y, type);
case TableInfo: return Table$compare(x, y, type);
+ case OptionalInfo: {
+ errx(1, "Optional compare not implemented");
+ }
case EmptyStruct: return 0;
case CustomInfo:
if (!type->CustomInfo.compare)
@@ -157,6 +164,9 @@ PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo
case ChannelInfo: return Channel$equal((const channel_t**)x, (const channel_t**)y, type);
case TableInfo: return Table$equal(x, y, type);
case EmptyStruct: return true;
+ case OptionalInfo: {
+ errx(1, "Optional equal not implemented");
+ }
case CustomInfo:
if (!type->CustomInfo.equal)
goto use_generic_compare;
@@ -177,6 +187,7 @@ public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo *ty
case ChannelInfo: return Channel$as_text((const 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 EmptyStruct: return colorize ?
Text$concat(Text("\x1b[0;1m"), Text$from_str(type->EmptyStruct.name), Text("\x1b[m()"))
: Text$concat(Text$from_str(type->EmptyStruct.name), Text("()"));
diff --git a/builtins/optionals.c b/builtins/optionals.c
new file mode 100644
index 00000000..869ee4cd
--- /dev/null
+++ b/builtins/optionals.c
@@ -0,0 +1,49 @@
+// Optional types
+
+#include "bool.h"
+#include "datatypes.h"
+#include "text.h"
+#include "util.h"
+
+public const Array_t NULL_ARRAY = {.length=-1};
+public const Bool_t NULL_BOOL = -1;
+public const Int_t NULL_INT = {.small=0};
+public const Table_t NULL_TABLE = {.entries.length=-1};
+public const closure_t NULL_CLOSURE = {.fn=NULL};
+public const Text_t NULL_TEXT = {.length=-1};
+
+static inline bool is_null(const void *obj, const TypeInfo *non_optional_type)
+{
+ if (non_optional_type == &Int$info)
+ return ((Int_t*)obj)->small == 0;
+ else if (non_optional_type == &Bool$info)
+ return *((Bool_t*)obj) == NULL_BOOL;
+ else if (non_optional_type == &Num$info)
+ return isnan(*((Num_t*)obj));
+
+ switch (non_optional_type->tag) {
+ 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;
+ default: {
+ Text_t t = generic_as_text(NULL, false, non_optional_type);
+ errx(1, "is_null() not implemented for: %k", &t);
+ }
+ }
+}
+
+#pragma GCC diagnostic ignored "-Wstack-protector"
+public Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo *type)
+{
+ if (!obj)
+ return Text$concat(generic_as_text(obj, colorize, type->OptionalInfo.type), Text("?"));
+
+ if (is_null(obj, type->OptionalInfo.type))
+ return Text$concat(colorize ? Text("\x1b[31m!") : Text("!"), generic_as_text(NULL, false, type->OptionalInfo.type),
+ colorize ? Text("\x1b[m") : Text(""));
+ return Text$concat(generic_as_text(obj, colorize, type->OptionalInfo.type), colorize ? Text("\x1b[33m?\x1b[m") : Text("?"));
+}
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
diff --git a/builtins/optionals.h b/builtins/optionals.h
new file mode 100644
index 00000000..a0b9b0e0
--- /dev/null
+++ b/builtins/optionals.h
@@ -0,0 +1,25 @@
+#pragma once
+
+// Optional types
+
+#include <gc/cord.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "types.h"
+#include "util.h"
+
+#define Bool_t bool
+#define yes (Bool_t)true
+#define no (Bool_t)false
+
+extern const Bool_t NULL_BOOL;
+extern const Table_t NULL_TABLE;
+extern const Array_t NULL_ARRAY;
+extern const Int_t NULL_INT;
+extern const closure_t NULL_CLOSURE;
+extern const Text_t NULL_TEXT;
+
+Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo *type);
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/pointer.c b/builtins/pointer.c
index 0d89e8a6..9067ebd7 100644
--- a/builtins/pointer.c
+++ b/builtins/pointer.c
@@ -27,10 +27,6 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo *type
text = Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), typename, Text("\x1b[m"));
else
text = Text$concat(Text$from_str(ptr_info.sigil), typename);
-
- if (ptr_info.is_optional)
- text = Text$concat(text, Text("?"));
-
return text;
}
const void *ptr = *(const void**)x;
@@ -55,8 +51,6 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo *type
Text(".."),
Int32$as_text(&depth, false, &Int32$info),
colorize ? Text("\x1b[m") : Text(""));
- if (ptr_info.is_optional)
- text = Text$concat(text, colorize ? Text("\x1b[34;1m?\x1b[m") : Text("?"));
return text;
}
}
@@ -73,9 +67,6 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo *type
text = Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), Text("\x1b[m"), pointed);
else
text = Text$concat(Text$from_str(ptr_info.sigil), pointed);
-
- if (ptr_info.is_optional)
- text = Text$concat(text, Text("?"));
return text;
}
diff --git a/builtins/tomo.h b/builtins/tomo.h
index 29f71f71..4a52da7c 100644
--- a/builtins/tomo.h
+++ b/builtins/tomo.h
@@ -21,6 +21,7 @@
#include "macros.h"
#include "memory.h"
#include "nums.h"
+#include "optionals.h"
#include "path.h"
#include "pointer.h"
#include "range.h"
diff --git a/builtins/types.c b/builtins/types.c
index 6d9e2408..79f65f71 100644
--- a/builtins/types.c
+++ b/builtins/types.c
@@ -39,6 +39,7 @@ public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo *type)
{
(void)fn;
Text_t text = Text$from_str(type->FunctionInfo.type_str);
+ if (fn) text = Text$concat(text, Text(": ..."));
if (fn && colorize)
text = Text$concat(Text("\x1b[32;1m"), text, Text("\x1b[m"));
return text;
diff --git a/builtins/types.h b/builtins/types.h
index f06730a7..a6cc40c6 100644
--- a/builtins/types.h
+++ b/builtins/types.h
@@ -17,7 +17,8 @@ typedef Text_t (*text_fn_t)(const void*, bool, const struct TypeInfo*);
typedef struct TypeInfo {
int64_t size, align;
struct { // Anonymous tagged union for convenience
- enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, EmptyStruct } tag;
+ enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, ChannelInfo, TableInfo, FunctionInfo,
+ OptionalInfo, TypeInfoInfo, OpaqueInfo, EmptyStruct } tag;
union {
struct {
equal_fn_t equal;
@@ -27,7 +28,6 @@ typedef struct TypeInfo {
} CustomInfo;
struct {
const char *sigil;
- bool is_optional;
const struct TypeInfo *pointed;
} PointerInfo;
struct {
@@ -45,6 +45,9 @@ typedef struct TypeInfo {
struct {
const char *type_str;
} TypeInfoInfo;
+ struct {
+ const struct TypeInfo *type;
+ } OptionalInfo;
#pragma GCC diagnostic ignored "-Wpedantic"
struct {} OpaqueInfo;
struct {
@@ -54,8 +57,8 @@ typedef struct TypeInfo {
};
} TypeInfo;
-#define Pointer$info(sigil_expr, pointed_info, opt) &((TypeInfo){.size=sizeof(void*), .align=__alignof__(void*), \
- .tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info, .is_optional=opt}})
+#define Pointer$info(sigil_expr, pointed_info) &((TypeInfo){.size=sizeof(void*), .align=__alignof__(void*), \
+ .tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info}})
#define Array$info(item_info) &((TypeInfo){.size=sizeof(Array_t), .align=__alignof__(Array_t), \
.tag=ArrayInfo, .ArrayInfo.item=item_info})
#define Set$info(item_info) &((TypeInfo){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
@@ -70,6 +73,8 @@ typedef struct TypeInfo {
.tag=FunctionInfo, .FunctionInfo.type_str=typestr})
#define TypeInfo$info(typestr) &((TypeInfo){.size=sizeof(TypeInfo), .align=__alignof__(TypeInfo), \
.tag=TypeInfoInfo, .TypeInfoInfo.type_str=typestr})
+#define Optional$info(t) &((TypeInfo){.size=(t)->size, .align=(t)->align, \
+ .tag=OptionalInfo, .OptionalInfo.type=t})
extern const TypeInfo TypeInfo$info;
extern const TypeInfo Void$info;