aboutsummaryrefslogtreecommitdiff
path: root/stdlib/optionals.c
blob: b6ca8dfb5f3304d61a3e92dd231f213822e544bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// Optional types

#include <pthread.h>

#include "bools.h"
#include "datatypes.h"
#include "integers.h"
#include "metamethods.h"
#include "threads.h"
#include "text.h"
#include "util.h"

public const Array_t NULL_ARRAY = {.length=-1};
public const OptionalBool_t NULL_BOOL = 2;
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};

public PUREFUNC 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 *((OptionalBool_t*)obj) == NULL_BOOL;
    else if (non_optional_type == &Num$info)
        return isnan(*((Num_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 == &Thread)
        return *(pthread_t**)obj == NULL;

    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 = non_optional_type->size;
            if (offset % non_optional_type->align)
                offset += non_optional_type->align - (offset % non_optional_type->align);
            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);
        }
    }
}

#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