Getting back to old typeinfo stuff from SSS
This commit is contained in:
parent
8ebf9bd3ad
commit
21a35cbc45
2
Makefile
2
Makefile
@ -25,7 +25,7 @@ O=-Og
|
||||
CFLAGS=$(CCONFIG) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS)
|
||||
LDLIBS=-lgc -lgccjit -lcord -lm -lunistring
|
||||
BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/builtins.o builtins/floats.o builtins/functions.o builtins/integers.o \
|
||||
builtins/memory.o builtins/string.o builtins/table.o builtins/types.o
|
||||
builtins/pointer.o builtins/memory.o builtins/string.o builtins/table.o builtins/types.o
|
||||
|
||||
all: nextlang libnext.so
|
||||
|
||||
|
@ -10,9 +10,15 @@
|
||||
#include "../files.h"
|
||||
#include "../util.h"
|
||||
#include "functions.h"
|
||||
#include "array.h"
|
||||
#include "table.h"
|
||||
#include "pointer.h"
|
||||
#include "string.h"
|
||||
|
||||
void fail(const char *fmt, ...)
|
||||
extern bool USE_COLOR;
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
public void fail(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -21,12 +27,75 @@ void fail(const char *fmt, ...)
|
||||
raise(SIGABRT);
|
||||
}
|
||||
|
||||
Str_t builtin_last_err()
|
||||
public uint32_t generic_hash(const void *obj, const TypeInfo *type)
|
||||
{
|
||||
const char *str = strerror(errno);
|
||||
char *copy = GC_MALLOC_ATOMIC(strlen(str)+1);
|
||||
strcpy(copy, str);
|
||||
return (Str_t){.data=copy, .length=strlen(str), .stride=1};
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__hash(obj, type);
|
||||
case ArrayInfo: return Array_hash(obj, type);
|
||||
case TableInfo: return Table_hash(obj, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.hash)
|
||||
goto hash_data;
|
||||
return type->CustomInfo.hash(obj, type);
|
||||
default: {
|
||||
hash_data:;
|
||||
uint32_t hash;
|
||||
halfsiphash((void*)obj, type->size, SSS_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int32_t generic_compare(const void *x, const void *y, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__compare(x, y, type);
|
||||
case ArrayInfo: return Array_compare(x, y, type);
|
||||
case TableInfo: return Table_compare(x, y, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.compare)
|
||||
goto compare_data;
|
||||
return type->CustomInfo.compare(x, y, type);
|
||||
default:
|
||||
compare_data:
|
||||
return (int32_t)memcmp((void*)x, (void*)y, type->size);
|
||||
}
|
||||
}
|
||||
|
||||
public bool generic_equal(const void *x, const void *y, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__equal(x, y, type);
|
||||
case ArrayInfo: return Array_equal(x, y, type);
|
||||
case TableInfo: return Table_equal(x, y, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.equal)
|
||||
goto use_generic_compare;
|
||||
return type->CustomInfo.equal(x, y, type);
|
||||
default:
|
||||
use_generic_compare:
|
||||
return (generic_compare(x, y, type) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
public CORD generic_cord(const void *obj, bool colorize, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: return Pointer__cord(obj, colorize, type);
|
||||
case ArrayInfo: return Array_cord(obj, colorize, type);
|
||||
case TableInfo: return Table_cord(obj, colorize, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.cord)
|
||||
builtin_fail("No cord function provided for type: %s!\n", type->name);
|
||||
return type->CustomInfo.cord(obj, colorize, type);
|
||||
default: errx(1, "Invalid type tag: %d", type->tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public CORD builtin_last_err()
|
||||
{
|
||||
return CORD_from_char_star(strerror(errno));
|
||||
}
|
||||
|
||||
static inline char *without_colors(const char *str)
|
||||
@ -48,33 +117,33 @@ static inline char *without_colors(const char *str)
|
||||
return buf;
|
||||
}
|
||||
|
||||
void __doctest(const char *label, CORD expr, const char *type, bool use_color, const char *expected, const char *filename, int start, int end)
|
||||
public void __doctest(CORD label, void *expr, TypeInfo *type, CORD expected, const char *filename, int start, int end)
|
||||
{
|
||||
static sss_file_t *file = NULL;
|
||||
static file_t *file = NULL;
|
||||
if (filename && (file == NULL || strcmp(file->filename, filename) != 0))
|
||||
file = sss_load_file(filename);
|
||||
file = load_file(filename);
|
||||
|
||||
if (filename && file)
|
||||
CORD_fprintf(stderr, use_color ? "\x1b[33;1m>>> \x1b[0m%.*s\x1b[m\n" : ">>> %.*s\n", (end - start), file->text + start);
|
||||
CORD_fprintf(stderr, USE_COLOR ? "\x1b[33;1m>>> \x1b[0m%.*s\x1b[m\n" : ">>> %.*s\n", (end - start), file->text + start);
|
||||
|
||||
if (expr) {
|
||||
const char *expr_str = CORD_to_const_char_star(expr);
|
||||
if (!use_color)
|
||||
expr_str = without_colors(expr_str);
|
||||
CORD expr_str = generic_cord(expr, USE_COLOR, type);
|
||||
CORD type_name = generic_cord(NULL, false, type);
|
||||
|
||||
CORD_fprintf(stderr, use_color ? "\x1b[2m%s\x1b[0m %s \x1b[2m: %s\x1b[m\n" : "%s %s : %s\n", label, expr_str, type);
|
||||
CORD_fprintf(stderr, USE_COLOR ? "\x1b[2m%r\x1b[0m %r \x1b[2m: %r\x1b[m\n" : "%r %r : %r\n", label, expr_str, type_name);
|
||||
if (expected) {
|
||||
const char *actual = use_color ? without_colors(expr_str) : expr_str;
|
||||
bool success = (strcmp(actual, expected) == 0);
|
||||
if (!success && strchr(expected, ':')) {
|
||||
actual = heap_strf("%s : %s", actual, type);
|
||||
success = (strcmp(actual, expected) == 0);
|
||||
CORD expr_plain = USE_COLOR ? generic_cord(expr, false, type) : expr_str;
|
||||
bool success = (CORD_cmp(expr_str, expected) == 0);
|
||||
if (!success && CORD_chr(expected, 0, ':')) {
|
||||
expr_plain = heap_strf("%s : %s", expr_plain, type_name);
|
||||
success = (CORD_cmp(CORD_catn(3, expr_plain, " : ", type_name), expected) == 0);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
if (filename && file)
|
||||
fprint_span(stderr, file, file->text+start, file->text+end, "\x1b[31;1m", 2, use_color);
|
||||
builtin_fail(use_color ? "\x1b[31;1mExpected: \x1b[32;7m%s\x1b[0m\n\x1b[31;1m But got: \x1b[31;7m%s\x1b[0m\n" : "Expected: %s\n But got: %s\n", expected, actual);
|
||||
fprint_span(stderr, file, file->text+start, file->text+end, "\x1b[31;1m", 2, USE_COLOR);
|
||||
builtin_fail(USE_COLOR ? "\x1b[31;1mExpected: \x1b[32;7m%s\x1b[0m\n\x1b[31;1m But got: \x1b[31;7m%s\x1b[0m\n" : "Expected: %s\n But got: %s\n",
|
||||
expected, expr_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
68
builtins/pointer.c
Normal file
68
builtins/pointer.c
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
#include <gc.h>
|
||||
#include <gc/cord.h>
|
||||
#include <stdalign.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/param.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "../util.h"
|
||||
#include "../SipHash/halfsiphash.h"
|
||||
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
typedef struct recursion_s {
|
||||
const void *ptr;
|
||||
struct recursion_s *next;
|
||||
} recursion_t;
|
||||
|
||||
public CORD Pointer__cord(const void *x, bool colorize, const TypeInfo *type) {
|
||||
auto ptr_info = type->PointerInfo;
|
||||
const void *ptr = *(const void**)x;
|
||||
if (!ptr)
|
||||
return colorize ? CORD_asprintf("\x1b[34;1m!%s\x1b[m", ptr_info.pointed->name) : CORD_cat(ptr_info.sigil, ptr_info.pointed->name);
|
||||
|
||||
// Check for recursive references, so if `x.foo = x`, then it prints as
|
||||
// `@Foo{foo=@..1}` instead of overflowing the stack:
|
||||
static recursion_t *recursion = NULL;
|
||||
int32_t depth = 0;
|
||||
for (recursion_t *r = recursion; r; r = r->next) {
|
||||
++depth;
|
||||
if (r->ptr == ptr)
|
||||
return CORD_asprintf(colorize ? "\x1b[34;1m%s..%d\x1b[m" : "%s..%d", ptr_info.sigil, depth);
|
||||
}
|
||||
|
||||
CORD pointed;
|
||||
{ // Stringify with this pointer flagged as a recursive one:
|
||||
recursion_t my_recursion = {.ptr=ptr, .next=recursion};
|
||||
recursion = &my_recursion;
|
||||
pointed = generic_cord(ptr, colorize, ptr_info.pointed);
|
||||
recursion = recursion->next;
|
||||
}
|
||||
return colorize ? CORD_asprintf("\x1b[34;1m%s%r\x1b[m", ptr_info.sigil, pointed) : CORD_cat(ptr_info.sigil, pointed);
|
||||
}
|
||||
|
||||
public int32_t Pointer__compare(const void *x, const void *y, const TypeInfo *type) {
|
||||
(void)type;
|
||||
const void *xp = *(const void**)x, *yp = *(const void**)y;
|
||||
return (xp > yp) - (xp < yp);
|
||||
}
|
||||
|
||||
public bool Pointer__equal(const void *x, const void *y, const TypeInfo *type) {
|
||||
(void)type;
|
||||
const void *xp = *(const void**)x, *yp = *(const void**)y;
|
||||
return xp == yp;
|
||||
}
|
||||
|
||||
public uint32_t Pointer__hash(const void *x, const TypeInfo *type) {
|
||||
(void)type;
|
||||
uint32_t hash;
|
||||
halfsiphash(x, sizeof(void*), SSS_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
16
builtins/pointer.h
Normal file
16
builtins/pointer.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <gc/cord.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
CORD Pointer__cord(const void *x, bool colorize, const TypeInfo *type);
|
||||
int32_t Pointer__compare(const void *x, const void *y, const TypeInfo *type);
|
||||
bool Pointer__equal(const void *x, const void *y, const TypeInfo *type);
|
||||
uint32_t Pointer__hash(const void *x, const TypeInfo *type);
|
||||
|
||||
#define POINTER_TYPE(_sigil, _pointed) (&(TypeInfo){\
|
||||
.size=sizeof(void*), .align=alignof(void*), .tag=PointerInfo, .PointerInfo.sigil=_sigil, .PointerInfo.pointed=_pointed})
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
@ -21,11 +21,6 @@
|
||||
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
typedef struct {
|
||||
enum { FIND_FAILURE, FIND_SUCCESS } status;
|
||||
int32_t index;
|
||||
} find_result_t;
|
||||
|
||||
public CORD Str__quoted(CORD str, bool colorize)
|
||||
{
|
||||
// Note: it's important to have unicode strings not get broken up with
|
||||
@ -131,8 +126,6 @@ public CORD Str__titlecased(CORD str)
|
||||
return (CORD)u8_totitle((const uint8_t*)str, len-1, uc_locale_language(), NULL, dest, &len);
|
||||
}
|
||||
|
||||
typedef enum { WHERE_ANYWHERE, WHERE_START, WHERE_END } where_e;
|
||||
|
||||
public bool Str__has(CORD str, CORD target, where_e where)
|
||||
{
|
||||
if (!target) return true;
|
||||
@ -257,29 +250,7 @@ public CORD Str__join(CORD glue, Str_Array_t pieces)
|
||||
return ret;
|
||||
}
|
||||
|
||||
public struct {
|
||||
TypeInfo type;
|
||||
CORD (*uppercased)(CORD s);
|
||||
CORD (*lowercased)(CORD s);
|
||||
CORD (*titlecased)(CORD s);
|
||||
bool (*has)(CORD s, CORD prefix, where_e where);
|
||||
bool (*ends_with)(CORD s, CORD suffix);
|
||||
CORD (*without)(CORD s, CORD target, where_e where);
|
||||
CORD (*without_suffix)(CORD s, CORD suffix);
|
||||
CORD (*trimmed)(CORD s, CORD trim_chars, where_e where);
|
||||
CORD (*slice)(CORD s, int64_t first, int64_t stride, int64_t length);
|
||||
char *(*c_string)(CORD str);
|
||||
CORD (*from_c_string)(char *str);
|
||||
find_result_t (*find)(CORD str, CORD pat);
|
||||
CORD (*replace)(CORD text, CORD pat, CORD replacement, int64_t limit);
|
||||
CORD (*quoted)(CORD text, bool colorize);
|
||||
Str_Array_t (*split)(CORD str, CORD split_chars);
|
||||
CORD (*join)(CORD glue, Str_Array_t pieces);
|
||||
bool (*equal)(CORD *x, CORD *y);
|
||||
int32_t (*compare)(CORD *x, CORD *y);
|
||||
int (*hash)(CORD *s, TypeInfo *type);
|
||||
CORD (*cord)(CORD *s, bool colorize, TypeInfo *type);
|
||||
} Str_type = {
|
||||
public Str_namespace_t Str_type = {
|
||||
.type={
|
||||
.name="Str",
|
||||
.size=sizeof(CORD),
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct {
|
||||
CORD *data;
|
||||
unsigned long int length:42;
|
||||
@ -10,5 +12,52 @@ typedef struct {
|
||||
short int stride:16;
|
||||
} Str_Array_t;
|
||||
|
||||
typedef enum { WHERE_ANYWHERE, WHERE_START, WHERE_END } where_e;
|
||||
|
||||
typedef struct {
|
||||
enum { FIND_FAILURE, FIND_SUCCESS } status;
|
||||
int32_t index;
|
||||
} find_result_t;
|
||||
|
||||
typedef struct {
|
||||
TypeInfo type;
|
||||
CORD (*uppercased)(CORD s);
|
||||
CORD (*lowercased)(CORD s);
|
||||
CORD (*titlecased)(CORD s);
|
||||
bool (*has)(CORD s, CORD prefix, where_e where);
|
||||
bool (*ends_with)(CORD s, CORD suffix);
|
||||
CORD (*without)(CORD s, CORD target, where_e where);
|
||||
CORD (*without_suffix)(CORD s, CORD suffix);
|
||||
CORD (*trimmed)(CORD s, CORD trim_chars, where_e where);
|
||||
CORD (*slice)(CORD s, int64_t first, int64_t stride, int64_t length);
|
||||
char *(*c_string)(CORD str);
|
||||
CORD (*from_c_string)(char *str);
|
||||
find_result_t (*find)(CORD str, CORD pat);
|
||||
CORD (*replace)(CORD text, CORD pat, CORD replacement, int64_t limit);
|
||||
CORD (*quoted)(CORD text, bool colorize);
|
||||
Str_Array_t (*split)(CORD str, CORD split_chars);
|
||||
CORD (*join)(CORD glue, Str_Array_t pieces);
|
||||
bool (*equal)(CORD *x, CORD *y);
|
||||
int32_t (*compare)(CORD *x, CORD *y);
|
||||
int (*hash)(CORD *s, TypeInfo *type);
|
||||
CORD (*cord)(CORD *s, bool colorize, TypeInfo *type);
|
||||
} Str_namespace_t;
|
||||
extern Str_namespace_t Str_type;
|
||||
|
||||
CORD Str__quoted(CORD str, bool colorize);
|
||||
int Str__compare(CORD *x, CORD *y);
|
||||
bool Str__equal(CORD *x, CORD *y);
|
||||
uint32_t Str__hash(CORD *cord);
|
||||
CORD Str__uppercased(CORD str);
|
||||
CORD Str__lowercased(CORD str);
|
||||
CORD Str__titlecased(CORD str);
|
||||
bool Str__has(CORD str, CORD target, where_e where);
|
||||
CORD Str__without(CORD str, CORD target, where_e where);
|
||||
CORD Str__trimmed(CORD str, CORD skip, where_e where);
|
||||
CORD Str__slice(CORD str, int64_t first, int64_t stride, int64_t length);
|
||||
find_result_t Str__find(CORD str, CORD pat);
|
||||
CORD Str__replace(CORD text, CORD pat, CORD replacement, int64_t limit);
|
||||
Str_Array_t Str__split(CORD str, CORD split);
|
||||
CORD Str__join(CORD glue, Str_Array_t pieces);
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
||||
|
@ -43,21 +43,6 @@
|
||||
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
extern CORD CString_cord(const char **s, bool colorize, const TypeInfo *type);
|
||||
extern uint32_t CString_hash(const char **s, const TypeInfo *type);
|
||||
extern uint32_t CString_compare(const char **x, const char **y, const TypeInfo *type);
|
||||
static TypeInfo CString_typeinfo = {
|
||||
.name="CString",
|
||||
.size=sizeof(char*),
|
||||
.align=alignof(char*),
|
||||
.tag=CustomInfo,
|
||||
.CustomInfo={
|
||||
.cord=(void*)CString_cord,
|
||||
.hash=(void*)CString_hash,
|
||||
.compare=(void*)CString_compare,
|
||||
},
|
||||
};
|
||||
|
||||
TypeInfo MemoryPointer_typeinfo = {
|
||||
.name="@Memory",
|
||||
.size=sizeof(void*),
|
||||
@ -69,12 +54,12 @@ TypeInfo MemoryPointer_typeinfo = {
|
||||
},
|
||||
};
|
||||
|
||||
TypeInfo CStringToVoidStarTable_type = {
|
||||
.name="{CString=>@Memory}",
|
||||
TypeInfo StrToVoidStarTable_type = {
|
||||
.name="{Str=>@Memory}",
|
||||
.size=sizeof(table_t),
|
||||
.align=alignof(table_t),
|
||||
.tag=TableInfo,
|
||||
.TableInfo={.key=&CString_typeinfo,.value=&MemoryPointer_typeinfo,
|
||||
.TableInfo={.key=&Str_type.type, .value=&MemoryPointer_typeinfo,
|
||||
.entry_size=16, .value_offset=8},
|
||||
};
|
||||
|
||||
@ -430,23 +415,39 @@ public int32_t Table_compare(const table_t *x, const table_t *y, const TypeInfo
|
||||
{
|
||||
assert(type->tag == TableInfo);
|
||||
auto table = type->TableInfo;
|
||||
struct {
|
||||
const char *name;
|
||||
const TypeInfo *type;
|
||||
} member_data[] = {{"key", table.key}, {"value", table.value}};
|
||||
TypeInfo entry_type = {
|
||||
.name="Entry",
|
||||
.size=ENTRY_SIZE,
|
||||
.align=MAX(table.key->align, table.value->align),
|
||||
.tag=StructInfo,
|
||||
.StructInfo={
|
||||
.members=(array_t){.data=member_data, .length=2, .stride=sizeof(member_data[0])},
|
||||
}
|
||||
};
|
||||
if (x->entries.length == 0)
|
||||
return 0;
|
||||
else if (x->entries.length != y->entries.length)
|
||||
return (x->entries.length > y->entries.length) - (x->entries.length < y->entries.length);
|
||||
|
||||
array_t x_entries = x->entries, y_entries = y->entries;
|
||||
Array_sort(&x_entries, &entry_type);
|
||||
Array_sort(&y_entries, &entry_type);
|
||||
return Array_compare(&x_entries, &y_entries, &entry_type);
|
||||
Array_sort(&x_entries, table.key);
|
||||
Array_sort(&y_entries, table.key);
|
||||
for (int64_t i = 0; i < x_entries.length; i++) {
|
||||
void *x_key = x_entries.data + x_entries.stride * i;
|
||||
void *y_key = y_entries.data + y_entries.stride * i;
|
||||
int32_t diff = generic_compare(x_key, y_key, table.key);
|
||||
if (diff != 0) return diff;
|
||||
void *x_value = x_key + table.value_offset;
|
||||
void *y_value = y_key + table.value_offset;
|
||||
diff = generic_compare(x_value, y_value, table.value);
|
||||
if (diff != 0) return diff;
|
||||
}
|
||||
|
||||
if (!x->default_value != !y->default_value) {
|
||||
return (!x->default_value) - (!y->default_value);
|
||||
} else if (x->default_value && y->default_value) {
|
||||
int32_t diff = generic_compare(x->default_value, y->default_value, table.value);
|
||||
if (diff != 0) return diff;
|
||||
}
|
||||
|
||||
if (!x->fallback != !y->fallback) {
|
||||
return (!x->fallback) - (!y->fallback);
|
||||
} else if (x->fallback && y->fallback) {
|
||||
return generic_compare(x->fallback, y->fallback, type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint32_t Table_hash(const table_t *t, const TypeInfo *type)
|
||||
@ -504,7 +505,7 @@ public CORD Table_cord(const table_t *t, bool colorize, const TypeInfo *type)
|
||||
}
|
||||
|
||||
if (t->default_value) {
|
||||
c = CORD_cat(c, "; default=");
|
||||
c = CORD_cat(c, t->fallback ? "; default=" : "; default=");
|
||||
c = CORD_cat(c, generic_cord(t->default_value, colorize, table.value));
|
||||
}
|
||||
|
||||
@ -525,29 +526,29 @@ public table_t Table_from_entries(array_t entries, const TypeInfo *type)
|
||||
|
||||
void *Table_str_get(const table_t *t, const char *key)
|
||||
{
|
||||
void **ret = Table_get(t, &key, &CStringToVoidStarTable_type);
|
||||
void **ret = Table_get(t, &key, &StrToVoidStarTable_type);
|
||||
return ret ? *ret : NULL;
|
||||
}
|
||||
|
||||
void *Table_str_get_raw(const table_t *t, const char *key)
|
||||
{
|
||||
void **ret = Table_get_raw(t, &key, &CStringToVoidStarTable_type);
|
||||
void **ret = Table_get_raw(t, &key, &StrToVoidStarTable_type);
|
||||
return ret ? *ret : NULL;
|
||||
}
|
||||
|
||||
void *Table_str_reserve(table_t *t, const char *key, const void *value)
|
||||
{
|
||||
return Table_reserve(t, &key, &value, &CStringToVoidStarTable_type);
|
||||
return Table_reserve(t, &key, &value, &StrToVoidStarTable_type);
|
||||
}
|
||||
|
||||
void Table_str_set(table_t *t, const char *key, const void *value)
|
||||
{
|
||||
Table_set(t, &key, &value, &CStringToVoidStarTable_type);
|
||||
Table_set(t, &key, &value, &StrToVoidStarTable_type);
|
||||
}
|
||||
|
||||
void Table_str_remove(table_t *t, const char *key)
|
||||
{
|
||||
return Table_remove(t, &key, &CStringToVoidStarTable_type);
|
||||
return Table_remove(t, &key, &StrToVoidStarTable_type);
|
||||
}
|
||||
|
||||
void *Table_str_entry(const table_t *t, int64_t n)
|
||||
|
295
builtins/types.c
295
builtins/types.c
@ -8,306 +8,13 @@
|
||||
|
||||
#include "array.h"
|
||||
#include "table.h"
|
||||
#include "pointer.h"
|
||||
#include "types.h"
|
||||
#include "../util.h"
|
||||
#include "../SipHash/halfsiphash.h"
|
||||
|
||||
extern const void *SSS_HASH_VECTOR;
|
||||
|
||||
public uint32_t generic_hash(const void *obj, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case ArrayInfo: return Array_hash(obj, type);
|
||||
case TableInfo: return Table_hash(obj, type);
|
||||
case StructInfo: {
|
||||
auto info = type->StructInfo;
|
||||
if (info.members.length == 0)
|
||||
return 0;
|
||||
|
||||
uint32_t hash_values[info.members.length] = {};
|
||||
int64_t offset = 0;
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
typedef struct {const char *name; const TypeInfo *type;} struct_member_t;
|
||||
struct_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (member->type->align > 1 && (offset % member->type->align))
|
||||
offset += member->type->align - (offset % member->type->align);
|
||||
hash_values[i] = generic_hash(obj + offset, member->type);
|
||||
offset += member->type->size;
|
||||
}
|
||||
uint32_t hash;
|
||||
halfsiphash(hash_values, sizeof(uint32_t)*info.members.length, SSS_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
case EnumInfo: {
|
||||
auto info = type->EnumInfo;
|
||||
int32_t tag = *(int32_t*)obj;
|
||||
int64_t offset = 4;
|
||||
typedef struct { int64_t tag; const char *name; const TypeInfo *type;} tu_member_t;
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
offset = MAX(offset, member->type->align);
|
||||
}
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (member->tag != tag) continue;
|
||||
struct {
|
||||
int64_t tag;
|
||||
uint32_t value_hash;
|
||||
} data = {tag, generic_hash(obj + offset, member->type)};
|
||||
uint32_t hash;
|
||||
halfsiphash(&data, sizeof(data), SSS_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
uint32_t hash;
|
||||
halfsiphash(&tag, sizeof(tag), SSS_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.hash)
|
||||
goto hash_data;
|
||||
return type->CustomInfo.hash(obj, type);
|
||||
case PointerInfo:
|
||||
default: {
|
||||
hash_data:;
|
||||
uint32_t hash;
|
||||
halfsiphash((void*)obj, type->size, SSS_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int32_t generic_compare(const void *x, const void *y, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case ArrayInfo: return Array_compare(x, y, type);
|
||||
case TableInfo: return Table_compare(x, y, type);
|
||||
case StructInfo: {
|
||||
auto info = type->StructInfo;
|
||||
typedef struct {const char *name; const TypeInfo *type;} struct_member_t;
|
||||
auto members = (ARRAY_OF(struct_member_t))&info.members;
|
||||
int64_t offset = 0;
|
||||
foreach (members, member, last) {
|
||||
if (member->type->align > 1 && (offset % member->type->align))
|
||||
offset += member->type->align - (offset % member->type->align);
|
||||
int32_t cmp = generic_compare(x + offset, y + offset, member->type);
|
||||
if (cmp != 0) return cmp;
|
||||
offset += member->type->size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case EnumInfo: {
|
||||
auto info = type->EnumInfo;
|
||||
int32_t xtag = *(int32_t*)x,
|
||||
ytag = *(int32_t*)y;
|
||||
|
||||
if (xtag != ytag)
|
||||
return xtag - ytag;
|
||||
|
||||
int64_t offset = 4;
|
||||
typedef struct { int64_t tag; const char *name; const TypeInfo *type;} tu_member_t;
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
offset = MAX(offset, member->type->align);
|
||||
}
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (member->tag != xtag) continue;
|
||||
return generic_compare(x + offset, y + offset, member->type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.compare)
|
||||
goto compare_data;
|
||||
return type->CustomInfo.compare(x, y, type);
|
||||
case PointerInfo:
|
||||
default:
|
||||
compare_data:
|
||||
return (int32_t)memcmp((void*)x, (void*)y, type->size);
|
||||
}
|
||||
}
|
||||
|
||||
public bool generic_equal(const void *x, const void *y, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case ArrayInfo: return Array_equal(x, y, type);
|
||||
case TableInfo: return Table_equal(x, y, type);
|
||||
case StructInfo: {
|
||||
auto info = type->StructInfo;
|
||||
typedef struct {const char *name; const TypeInfo *type;} struct_member_t;
|
||||
auto members = (ARRAY_OF(struct_member_t))&info.members;
|
||||
int64_t offset = 0;
|
||||
foreach (members, member, last) {
|
||||
if (member->type->align > 1 && (offset % member->type->align))
|
||||
offset += member->type->align - (offset % member->type->align);
|
||||
bool equal = generic_equal(x + offset, y + offset, member->type);
|
||||
if (!equal) return false;
|
||||
offset += member->type->size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case EnumInfo: {
|
||||
auto info = type->EnumInfo;
|
||||
int32_t xtag = *(int32_t*)x,
|
||||
ytag = *(int32_t*)y;
|
||||
|
||||
if (xtag != ytag)
|
||||
return false;
|
||||
|
||||
int64_t offset = 4;
|
||||
typedef struct { int64_t tag; const char *name; const TypeInfo *type;} tu_member_t;
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
offset = MAX(offset, member->type->align);
|
||||
}
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (member->tag != xtag) continue;
|
||||
return generic_equal(x + offset, y + offset, member->type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.equal)
|
||||
goto use_generic_compare;
|
||||
return type->CustomInfo.equal(x, y, type);
|
||||
case PointerInfo:
|
||||
default:
|
||||
use_generic_compare:
|
||||
return (generic_compare(x, y, type) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
public CORD generic_cord(const void *obj, bool colorize, const TypeInfo *type)
|
||||
{
|
||||
switch (type->tag) {
|
||||
case PointerInfo: {
|
||||
auto ptr_info = type->PointerInfo;
|
||||
static TypeInfo ptr_type = {.name="@Memory", .size=sizeof(void*), .align=alignof(void*)};
|
||||
static TypeInfo int_type = {.name="Int", .size=sizeof(int64_t), .align=alignof(int64_t)};
|
||||
static TypeInfo ptr_to_int_type = {
|
||||
.name="{@Memory=>Int}",
|
||||
.size=sizeof(table_t),
|
||||
.align=alignof(table_t),
|
||||
.tag=TableInfo,
|
||||
.TableInfo={.key=&ptr_type, .value=&int_type, .entry_size=16, .value_offset=8},
|
||||
};
|
||||
|
||||
static int64_t zero = 0;
|
||||
static table_t recursion = {.default_value=&zero};
|
||||
static table_t *current_recursion = NULL;
|
||||
|
||||
CORD c;
|
||||
bool first_ptr_call = (current_recursion == NULL);
|
||||
if (first_ptr_call && ptr_info.cyclic) {
|
||||
current_recursion = &recursion;
|
||||
}
|
||||
|
||||
if (ptr_info.cyclic) {
|
||||
int64_t *found = Table_reserve(current_recursion, obj, NULL, &ptr_to_int_type);
|
||||
if (*found) {
|
||||
CORD_sprintf(&c, colorize ? "\x1b[34;1m%s%s#%ld\x1b[m" : "%s%s#%ld",
|
||||
ptr_info.sigil, ptr_info.pointed ? ptr_info.pointed->name : "", *found);
|
||||
goto done;
|
||||
} else {
|
||||
*found = Table_length(current_recursion);
|
||||
}
|
||||
}
|
||||
|
||||
void *ptr = *(void**)obj;
|
||||
if (ptr == NULL) {
|
||||
CORD_sprintf(&c, colorize ? "\x1b[34;1m!%s\x1b[m" : "!%s", ptr_info.pointed ? ptr_info.pointed->name : "");
|
||||
} else {
|
||||
CORD_sprintf(&c, colorize ? "\x1b[34;1m%s\x1b[m%r" : "%s%r",
|
||||
ptr_info.sigil, ptr_info.pointed ? generic_cord(ptr, colorize, ptr_info.pointed) : "???");
|
||||
}
|
||||
|
||||
done:;
|
||||
if (first_ptr_call && ptr_info.cyclic) {
|
||||
recursion = (table_t){.default_value=&zero};
|
||||
current_recursion = NULL;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
case StructInfo: {
|
||||
auto info = type->StructInfo;
|
||||
CORD c = "{";
|
||||
int64_t offset = 0;
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
if (i > 0) c = CORD_cat(c, ", ");
|
||||
typedef struct {const char *name; const TypeInfo *type;} struct_member_t;
|
||||
struct_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (member->type->align > 1 && (offset % member->type->align))
|
||||
offset += member->type->align - (offset % member->type->align);
|
||||
|
||||
// Print the field name only if it's not an anonymous field ("_%ld" format)
|
||||
char *end;
|
||||
if (member->name[0] != '_' || strtol(member->name+1, &end, 10) != i+1 || *end) {
|
||||
c = CORD_cat(c, member->name);
|
||||
c = CORD_cat(c, "=");
|
||||
}
|
||||
|
||||
c = CORD_cat(c, generic_cord(obj + offset, colorize, member->type));
|
||||
offset += member->type->size;
|
||||
}
|
||||
c = CORD_cat(c, "}");
|
||||
if (strncmp(type->name, "struct(", strlen("struct(")) != 0)
|
||||
CORD_sprintf(&c, colorize ? "\x1b[1m%s\x1b[m%r" : "%s%r", type->name, c);
|
||||
return c;
|
||||
}
|
||||
case EnumInfo: {
|
||||
auto info = type->EnumInfo;
|
||||
int32_t tag = *(int32_t*)obj;
|
||||
int64_t offset = 4;
|
||||
typedef struct { int64_t tag; const char *name; const TypeInfo *type;} tu_member_t;
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
offset = MAX(offset, member->type->align);
|
||||
}
|
||||
for (int64_t i = 0; i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (member->tag == tag) {
|
||||
CORD c;
|
||||
CORD_sprintf(&c, colorize ? "\x1b[36m%s\x1b[m" : "%s", member->name);
|
||||
if (member->type && member->type->size > 0)
|
||||
c = CORD_cat(c, generic_cord(obj + offset, colorize, member->type));
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
CORD c = colorize ? "\x1b[36m" : "";
|
||||
int32_t tag_remainder = tag;
|
||||
for (int64_t i = 0; tag_remainder && i < info.members.length; i++) {
|
||||
tu_member_t *member = info.members.data + i*info.members.stride;
|
||||
if (tag_remainder & member->tag) {
|
||||
if (tag_remainder != tag)
|
||||
c = CORD_cat(c, "+");
|
||||
c = CORD_cat(c, member->name);
|
||||
tag_remainder &= ~member->tag;
|
||||
}
|
||||
}
|
||||
if (tag_remainder) {
|
||||
if (tag_remainder != tag)
|
||||
c = CORD_cat(c, "+");
|
||||
c = CORD_cat(c, "???");
|
||||
}
|
||||
|
||||
if (colorize)
|
||||
c = CORD_cat(c, "\x1b[m");
|
||||
|
||||
return c;
|
||||
}
|
||||
case ArrayInfo: return Array_cord(obj, colorize, type);
|
||||
case TableInfo: return Table_cord(obj, colorize, type);
|
||||
case CustomInfo:
|
||||
if (!type->CustomInfo.cord)
|
||||
builtin_fail("No cord function provided for type: %s!\n", type->name);
|
||||
return type->CustomInfo.cord(obj, colorize, type);
|
||||
default: errx(1, "Invalid type tag: %d", type->tag);
|
||||
}
|
||||
}
|
||||
|
||||
public CORD Type__cord(void *type_namespace, bool colorize, const TypeInfo *type)
|
||||
{
|
||||
(void)type_namespace;
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "string.h"
|
||||
|
||||
struct TypeInfo;
|
||||
|
||||
@ -17,7 +16,7 @@ typedef struct TypeInfo {
|
||||
const char *name;
|
||||
int64_t size, align;
|
||||
struct { // Anonymous tagged union for convenience
|
||||
enum { CustomInfo, PointerInfo, ArrayInfo, TableInfo, StructInfo, EnumInfo } tag;
|
||||
enum { CustomInfo, PointerInfo, ArrayInfo, TableInfo } tag;
|
||||
union {
|
||||
struct {
|
||||
equal_fn_t equal;
|
||||
@ -28,7 +27,6 @@ typedef struct TypeInfo {
|
||||
struct {
|
||||
const char *sigil;
|
||||
struct TypeInfo *pointed;
|
||||
bool cyclic;
|
||||
} PointerInfo;
|
||||
struct {
|
||||
struct TypeInfo *item;
|
||||
@ -37,12 +35,6 @@ typedef struct TypeInfo {
|
||||
struct TypeInfo *key, *value;
|
||||
int64_t entry_size, value_offset;
|
||||
} TableInfo;
|
||||
struct {
|
||||
array_t members; // [{name, type}]
|
||||
} StructInfo;
|
||||
struct {
|
||||
array_t members; // [{tag, name, type}]
|
||||
} EnumInfo;
|
||||
};
|
||||
};
|
||||
} TypeInfo;
|
||||
|
@ -1,138 +0,0 @@
|
||||
#include <err.h>
|
||||
#include <gc/cord.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../util.h"
|
||||
#include "../builtins/datatypes.h"
|
||||
|
||||
typedef const struct cord_info_s cord_info_t;
|
||||
struct cord_info_s {
|
||||
union {
|
||||
struct {
|
||||
char sigil;
|
||||
CORD (*func)(void *x, bool use_color, cord_info_t *info);
|
||||
cord_info_t *info;
|
||||
} pointer;
|
||||
int8_t precision;
|
||||
struct {
|
||||
CORD (*func)(void *x, bool use_color, cord_info_t *info);
|
||||
cord_info_t *info;
|
||||
} array;
|
||||
struct {
|
||||
CORD (*key_func)(void *x, bool use_color, cord_info_t *info);
|
||||
cord_info_t *key_info;
|
||||
size_t value_offset;
|
||||
CORD (*value_func)(void *x, bool use_color, cord_info_t *info);
|
||||
cord_info_t *value_info;
|
||||
} table;
|
||||
};
|
||||
};
|
||||
#define INFO(type, ...) (&(cord_info_t){.type={__VA_ARGS__}})
|
||||
|
||||
// x := @[Str]
|
||||
// Pointer__as_str(&x, color, INFO(pointer, '@', Array__as_str, INFO(array, Str__quoted, NULL)))
|
||||
|
||||
// x := {Int=>Bool}
|
||||
// Table__as_str(&x, color, INFO(table, Int64__as_str, NULL, Bool__as_str, NULL))
|
||||
|
||||
// x := [[Foo]]
|
||||
// Array__as_str(&x, color, INFO(array, Array__as_str, INFO(array, Foo__as_str, NULL)))
|
||||
|
||||
CORD Bool__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Bool";
|
||||
return *(bool*)x ? "yes" : "no";
|
||||
}
|
||||
|
||||
CORD Int__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Int";
|
||||
return CORD_asprintf("%ld", *(Int_t)x);
|
||||
}
|
||||
|
||||
CORD Int32__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Int32";
|
||||
return CORD_asprintf("%d", *(Int32_t)x);
|
||||
}
|
||||
|
||||
CORD Int16__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Int16";
|
||||
return CORD_asprintf("%d", *(Int16_t)x);
|
||||
}
|
||||
|
||||
CORD Int8__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Int8";
|
||||
return CORD_asprintf("%d", *(Int8_t)x);
|
||||
}
|
||||
|
||||
CORD Num__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Num";
|
||||
return CORD_asprintf("%g", *(Num_t)x);
|
||||
}
|
||||
|
||||
CORD Num32__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Num32";
|
||||
return CORD_asprintf("%g", *(Num32_t)x);
|
||||
}
|
||||
|
||||
CORD Str__as_str(void *x, bool color, cord_info_t *info) {
|
||||
if (!x) return "Str";
|
||||
return Str__quoted(*(CORD*)x, color);
|
||||
}
|
||||
|
||||
CORD Pointer__as_str(void *x, bool color, cord_info_t *info)
|
||||
{
|
||||
static const sigils[] = {['@']="@", ['?']="?", ['&']="&", ['!']="!"};
|
||||
if (!x)
|
||||
return CORD_cat(sigils[info->pointer.sigil], info->pointer.func(NULL, color, info->pointer.info));
|
||||
void *ptr = *(void**)x;
|
||||
CORD pointed = info->pointer.func(ptr, color, info->pointer.info);
|
||||
return CORD_cat(ptr ? sigils[info->pointer.sigil] : "!", pointed);
|
||||
}
|
||||
|
||||
CORD Array__as_str(void *x, bool color, cord_info_t *info)
|
||||
{
|
||||
if (!x)
|
||||
return CORD_asprintf("[%r]", info->array.func(NULL, color, info->array.info));
|
||||
CORD cord = "[";
|
||||
array_t *arr = x;
|
||||
for (int64_t i = 0; i < arr->length; i++) {
|
||||
if (i > 0) cord = CORD_cat(cord, ", ");
|
||||
cord = CORD_cat(cord, info->array.func(arr->data + i*arr->stride, color, info->array.info));
|
||||
}
|
||||
return CORD_cat(cord, "]");
|
||||
}
|
||||
|
||||
CORD Table__as_str(void *x, bool color, cord_info_t *info)
|
||||
{
|
||||
if (!x) {
|
||||
return CORD_asprintf(
|
||||
"{%r=>%r}",
|
||||
info->table.key_func(NULL, color, info->table.key_info),
|
||||
info->table.value_func(NULL, color, info->table.value_info));
|
||||
}
|
||||
CORD cord = "{";
|
||||
table_t *table = x;
|
||||
array_t entries = table->entries;
|
||||
for (int64_t i = 0; i < entries.length; i++) {
|
||||
if (i > 0) cord = CORD_cat(cord, ", ");
|
||||
void *key = entries.data + i*entries.stride;
|
||||
cord = CORD_cat(cord, info->table.key_func(key, color, info->table.key_info));
|
||||
cord = CORD_cat(cord, "=");
|
||||
cord = CORD_cat(cord, info->table.value_func(key + info->table.value_offset, color, info->table.value_info));
|
||||
}
|
||||
if (table->fallback) {
|
||||
cord = CORD_cat(cord, "; fallback=");
|
||||
cord = CORD_cat(cord, Table__as_str(table->fallback, color, info));
|
||||
if (table->default_value) cord = CORD_cat(cord, ", ");
|
||||
} else if (table->default_value) {
|
||||
if (table->default_value) cord = CORD_cat(cord, "; ");
|
||||
}
|
||||
if (table->default_value) {
|
||||
cord = CORD_cat(cord, "default=");
|
||||
cord = CORD_cat(cord, info->table.value_func(table->default_value, color, info->table.value_info));
|
||||
}
|
||||
return CORD_cat(cord, "}");
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|
Loading…
Reference in New Issue
Block a user