Initial WIP first past

This commit is contained in:
Bruce Hill 2024-09-02 18:47:39 -04:00
parent f0f8f21870
commit 61e482f6f3
38 changed files with 1896 additions and 736 deletions

6
ast.c
View File

@ -35,9 +35,9 @@ static CORD optional_tagged_type(const char *tag, type_ast_t *ast);
CORD xml_escape(CORD text)
{
text = Text$replace(text, "&", "&", I(-1));
text = Text$replace(text, "<", "&lt;", I(-1));
text = Text$replace(text, ">", "&gt;", I(-1));
text = CORD_replace(text, "&", "&amp;");
text = CORD_replace(text, "<", "&lt;");
text = CORD_replace(text, ">", "&gt;");
return text;
}

View File

@ -12,12 +12,14 @@
#include "array.h"
#include "functions.h"
#include "halfsiphash.h"
#include "integers.h"
#include "table.h"
#include "text.h"
#include "types.h"
#include "util.h"
#include "siphash.c"
static inline int64_t get_padded_item_size(const TypeInfo *info)
{
int64_t size = info->ArrayInfo.item->size;
@ -532,67 +534,38 @@ public bool Array$equal(const array_t *x, const array_t *y, const TypeInfo *type
return (Array$compare(x, y, type) == 0);
}
public CORD Array$as_text(const array_t *arr, bool colorize, const TypeInfo *type)
public Text_t Array$as_text(const array_t *arr, bool colorize, const TypeInfo *type)
{
if (!arr)
return CORD_all("[", generic_as_text(NULL, false, type->ArrayInfo.item), "]");
return Text$concat(Text$from_str("["), generic_as_text(NULL, false, type->ArrayInfo.item), Text$from_str("]"));
const TypeInfo *item_type = type->ArrayInfo.item;
CORD c = "[";
Text_t text = Text$from_str("[");
for (int64_t i = 0; i < arr->length; i++) {
if (i > 0)
c = CORD_cat(c, ", ");
CORD item_cord = generic_as_text(arr->data + i*arr->stride, colorize, item_type);
c = CORD_cat(c, item_cord);
text = Text$concat(text, Text$from_str(", "));
Text_t item_text = generic_as_text(arr->data + i*arr->stride, colorize, item_type);
text = Text$concat(text, item_text);
}
c = CORD_cat(c, "]");
return c;
text = Text$concat(text, Text$from_str("]"));
return text;
}
public uint32_t Array$hash(const array_t *arr, const TypeInfo *type)
public uint64_t Array$hash(const array_t *arr, const TypeInfo *type)
{
// Array hash is calculated as a rolling, compacting hash of the length of the array, followed by
// the hashes of its items (or the items themselves if they're small plain data)
// In other words, it reads in a chunk of items or item hashes, then when it fills up the chunk,
// hashes it down to a single item to start the next chunk. This repeats until the end, when it
// hashes the last chunk down to a uint32_t.
const TypeInfo *item = type->ArrayInfo.item;
if (item->tag == PointerInfo || (item->tag == CustomInfo && item->CustomInfo.hash == NULL)) { // Raw data hash
uint8_t hash_batch[4 + 8*item->size];
memset(hash_batch, 0, sizeof(hash_batch));
uint8_t *p = hash_batch, *end = hash_batch + sizeof(hash_batch);
int64_t length = arr->length;
*p = (uint32_t)length;
p += sizeof(uint32_t);
for (int64_t i = 0; i < arr->length; i++) {
if (p >= end) {
uint32_t chunk_hash;
halfsiphash(&hash_batch, sizeof(hash_batch), TOMO_HASH_KEY, (uint8_t*)&chunk_hash, sizeof(chunk_hash));
p = hash_batch;
*(uint32_t*)p = chunk_hash;
p += sizeof(uint32_t);
}
memcpy((p += item->size), arr->data + i*arr->stride, item->size);
}
uint32_t hash;
halfsiphash(&hash_batch, ((int64_t)p) - ((int64_t)hash_batch), TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
return hash;
siphash sh;
siphashinit(&sh, sizeof(uint64_t[arr->length]), (uint64_t*)TOMO_HASH_KEY);
if (item->tag == PointerInfo || (item->tag == CustomInfo && item->CustomInfo.hash == NULL && 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 {
uint32_t hash_batch[16] = {(uint32_t)arr->length};
uint32_t *p = &hash_batch[1], *end = hash_batch + sizeof(hash_batch)/sizeof(hash_batch[0]);
for (int64_t i = 0; i < arr->length; i++) {
if (p >= end) {
uint64_t chunk_hash;
halfsiphash(&hash_batch, sizeof(hash_batch), TOMO_HASH_KEY, (uint8_t*)&chunk_hash, sizeof(chunk_hash));
p = hash_batch;
*(p++) = chunk_hash;
}
*(p++) = generic_hash(arr->data + i*arr->stride, item);
uint64_t item_hash = generic_hash(arr->data + i*arr->stride, item);
siphashadd64bits(&sh, item_hash);
}
uint32_t hash;
halfsiphash(&hash_batch, ((int64_t)p) - ((int64_t)hash_batch), TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
return hash;
}
return siphashfinish_last_part(&sh, 0);
}
static void siftdown(array_t *heap, int64_t startpos, int64_t pos, closure_t comparison, int64_t padded_item_size)

View File

@ -16,7 +16,7 @@
const array_t arr = arr_expr; int64_t index = index_expr; \
int64_t off = index + (index < 0) * (arr.length + 1) - 1; \
if (__builtin_expect(off < 0 || off >= arr.length, 0)) \
fail_source(filename, start, end, "Invalid array index: %r (array has length %ld)\n", Int64$as_text(&index, no, NULL), arr.length); \
fail_source(filename, start, end, "Invalid array index: %s (array has length %ld)\n", Text$as_c_string(Int64$as_text(&index, no, NULL)), arr.length); \
(item_type*)(arr.data + arr.stride * off);})
#define Array_get_unchecked(type, x, i) *({ const array_t arr = x; int64_t index = i; \
int64_t off = index + (index < 0) * (arr.length + 1) - 1; \
@ -25,7 +25,7 @@
array_t *arr = arr_expr; int64_t index = index_expr; \
int64_t off = index + (index < 0) * (arr->length + 1) - 1; \
if (__builtin_expect(off < 0 || off >= arr->length, 0)) \
fail_source(filename, start, end, "Invalid array index: %r (array has length %ld)\n", Int64$as_text(&index, no, NULL), arr->length); \
fail_source(filename, start, end, "Invalid array index: %s (array has length %ld)\n", Text$as_c_string(Int64$as_text(&index, no, NULL)), arr->length); \
if (arr->data_refcount > 0) \
Array$compact(arr, padded_item_size); \
(item_type*)(arr->data + arr->stride * off); })
@ -87,10 +87,10 @@ array_t Array$to(array_t array, Int_t last);
array_t Array$by(array_t array, Int_t stride, int64_t padded_item_size);
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);
uint32_t Array$hash(const array_t *arr, const TypeInfo *type);
uint64_t Array$hash(const array_t *arr, const TypeInfo *type);
int32_t Array$compare(const array_t *x, const array_t *y, const TypeInfo *type);
bool Array$equal(const array_t *x, const array_t *y, const TypeInfo *type);
CORD Array$as_text(const array_t *arr, bool colorize, const TypeInfo *type);
Text_t Array$as_text(const array_t *arr, bool colorize, const TypeInfo *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); })

View File

@ -13,25 +13,28 @@
#include "types.h"
#include "util.h"
public CORD Bool$as_text(const bool *b, bool colorize, const TypeInfo *type)
public Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo *type)
{
(void)type;
if (!b) return "Bool";
if (!b) return Text$from_str("Bool");
if (colorize)
return *b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m";
return *b ? Text$from_str("\x1b[35myes\x1b[m") : Text$from_str("\x1b[35mno\x1b[m");
else
return *b ? "yes" : "no";
return *b ? Text$from_str("yes") : Text$from_str("no");
}
public Bool_t Bool$from_text(CORD text, bool *success)
public Bool_t Bool$from_text(Text_t text, bool *success)
{
CORD lower = Text$lower(text);
if (CORD_cmp(lower, "yes") == 0 || CORD_cmp(lower, "on") == 0
|| CORD_cmp(lower, "true") == 0 || CORD_cmp(lower, "1") == 0) {
if (Text$equal_ignoring_case(text, Text$from_str("yes"))
|| Text$equal_ignoring_case(text, Text$from_str("on"))
|| Text$equal_ignoring_case(text, Text$from_str("true"))
|| Text$equal_ignoring_case(text, Text$from_str("1"))) {
if (success) *success = yes;
return yes;
} else if (CORD_cmp(lower, "no") == 0 || CORD_cmp(lower, "off") == 0
|| CORD_cmp(lower, "false") == 0 || CORD_cmp(lower, "0") == 0) {
} else if (Text$equal_ignoring_case(text, Text$from_str("no"))
|| Text$equal_ignoring_case(text, Text$from_str("off"))
|| Text$equal_ignoring_case(text, Text$from_str("false"))
|| Text$equal_ignoring_case(text, Text$from_str("0"))) {
if (success) *success = yes;
return no;
} else {

View File

@ -12,8 +12,8 @@
#define yes (Bool_t)true
#define no (Bool_t)false
CORD Bool$as_text(const bool *b, bool colorize, const TypeInfo *type);
bool Bool$from_text(CORD text, bool *success);
Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo *type);
bool Bool$from_text(Text_t text, bool *success);
Bool_t Bool$random(double p);
extern const TypeInfo $Bool;

View File

@ -13,12 +13,12 @@
#include "types.h"
#include "util.h"
public CORD CString$as_text(const void *c_string, bool colorize, const TypeInfo *info)
public Text_t CString$as_text(const void *c_string, bool colorize, const TypeInfo *info)
{
(void)info;
if (!c_string) return "CString";
CORD text = CORD_from_char_star(*(char**)c_string);
return CORD_all(colorize ? "\x1b[34mCString\x1b[m(" : "CString(", Text$quoted(text, colorize), ")");
if (!c_string) return Text$from_str("CString");
Text_t text = Text$from_str(*(char**)c_string);
return Text$concat(Text$from_str(colorize ? "\x1b[34mCString\x1b[m(" : "CString("), Text$quoted(text, colorize), Text$from_str(")"));
}
public int CString$compare(const char **x, const char **y)

View File

@ -8,10 +8,10 @@
#include "types.h"
CORD CString$as_text(const void *str, bool colorize, const TypeInfo *info);
Text_t CString$as_text(const void *str, bool colorize, const TypeInfo *info);
int CString$compare(const char **x, const char **y);
bool CString$equal(const char **x, const char **y);
uint32_t CString$hash(const char **str);
uint64_t CString$hash(const char **str);
extern const TypeInfo $CString;

View File

@ -15,6 +15,7 @@
#include "functions.h"
#include "halfsiphash.h"
#include "integers.h"
#include "text.h"
#include "types.h"
#include "util.h"
#include "where.h"
@ -120,15 +121,21 @@ bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *typ
return (*x == *y);
}
CORD Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type)
Text_t Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type)
{
const TypeInfo *item_type = type->ChannelInfo.item;
if (!channel) {
CORD typename = generic_as_text(NULL, false, item_type);
return colorize ? CORD_asprintf("\x1b[34;1m|:%s|\x1b[m", typename) : CORD_all("|:", typename, "|");
Text_t typename = generic_as_text(NULL, false, item_type);
return Text$concat(Text$from_str(colorize ? "\x1b[34;1m|:" : "|:"), typename, Text$from_str(colorize ? "|\x1b[m" : "|"));
}
CORD typename = generic_as_text(NULL, false, item_type);
return CORD_asprintf(colorize ? "\x1b[34;1m|:%s|<%p>\x1b[m" : "|:%s|<%p>", typename, *channel);
Text_t typename = generic_as_text(NULL, false, item_type);
return Text$concat(
Text$from_str(colorize ? "\x1b[34;1m|:" : "|:"),
typename,
Text$from_str("|<"),
Int64$hex((int64_t)(void*)*channel, I_small(0), true, true),
Text$from_str(colorize ? ">\x1b[m" : ">")
);
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -22,9 +22,9 @@ void Channel$peek(channel_t *channel, void *out, Where_t where, int64_t item_siz
#define Channel$peek_value(channel, where, t) ({ t _val; Channel$peek(channel, &_val, where, sizeof(t)); _val; })
void Channel$clear(channel_t *channel);
array_t Channel$view(channel_t *channel);
uint32_t Channel$hash(const channel_t **channel, const TypeInfo *type);
uint64_t Channel$hash(const channel_t **channel, const TypeInfo *type);
int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type);
bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type);
CORD Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type);
Text_t Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -71,4 +71,19 @@ typedef struct {
int64_t max_size;
} channel_t;
enum text_type { TEXT_SHORT_ASCII, TEXT_ASCII, TEXT_SHORT_GRAPHEMES, TEXT_GRAPHEMES, TEXT_SUBTEXT };
typedef struct Text_s {
int64_t length; // Number of grapheme clusters
uint64_t hash:61;
uint8_t tag:3;
union {
char short_ascii[8];
const char *ascii;
int32_t short_graphemes[2];
int32_t *graphemes;
struct Text_s *subtexts;
};
} Text_t;
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -2,7 +2,6 @@
#include <errno.h>
#include <execinfo.h>
#include <gc.h>
#include <gc/cord.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@ -16,7 +15,6 @@
#include "channel.h"
#include "files.h"
#include "functions.h"
#include "halfsiphash.h"
#include "integers.h"
#include "pointer.h"
#include "string.h"
@ -25,7 +23,9 @@
#include "types.h"
#include "util.h"
public uint8_t TOMO_HASH_KEY[8] = {0};
#include "siphash.c"
public uint8_t TOMO_HASH_KEY[16] = {0};
public void tomo_init(void)
{
@ -37,6 +37,9 @@ public void tomo_init(void)
srand(seed);
srand48(seed);
Int$init_random(seed);
if (register_printf_specifier('k', printf_text, printf_text_size))
errx(1, "Couldn't set printf specifier");
}
static void print_stack_trace(FILE *out)
@ -60,13 +63,13 @@ static void print_stack_trace(FILE *out)
fprintf(out, "\x1b[m");
}
public void fail(CORD fmt, ...)
public void fail(const char *fmt, ...)
{
if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr);
else fputs("==================== ERROR ====================\n\n", stderr);
va_list args;
va_start(args, fmt);
CORD_vfprintf(stderr, fmt, args);
vfprintf(stderr, fmt, args);
if (USE_COLOR) fputs("\x1b[m", stderr);
fputs("\n\n", stderr);
va_end(args);
@ -75,14 +78,14 @@ public void fail(CORD fmt, ...)
raise(SIGABRT);
}
public void fail_source(const char *filename, int64_t start, int64_t end, CORD fmt, ...)
public void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...)
{
if (USE_COLOR) fputs("\n\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr);
else fputs("\n==================== ERROR ====================\n\n", stderr);
va_list args;
va_start(args, fmt);
CORD_vfprintf(stderr, fmt, args);
vfprintf(stderr, fmt, args);
va_end(args);
file_t *file = filename ? load_file(filename) : NULL;
@ -98,11 +101,10 @@ public void fail_source(const char *filename, int64_t start, int64_t end, CORD f
raise(SIGABRT);
}
public uint32_t generic_hash(const void *obj, const TypeInfo *type)
public uint64_t generic_hash(const void *obj, const TypeInfo *type)
{
switch (type->tag) {
case PointerInfo: case FunctionInfo: return Pointer$hash(obj, type);
case TextInfo: return Text$hash(obj);
case TextInfo: return Text$hash((void*)obj);
case ArrayInfo: return Array$hash(obj, type);
case ChannelInfo: return Channel$hash((const channel_t**)obj, type);
case TableInfo: return Table$hash(obj, type);
@ -113,9 +115,7 @@ public uint32_t generic_hash(const void *obj, const TypeInfo *type)
return type->CustomInfo.hash(obj, type);
default: {
hash_data:;
uint32_t hash;
halfsiphash((void*)obj, type->size, TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
return hash;
return siphash24((void*)obj, type->size, (uint64_t*)TOMO_HASH_KEY);
}
}
}
@ -158,7 +158,7 @@ public bool generic_equal(const void *x, const void *y, const TypeInfo *type)
}
}
public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type)
public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo *type)
{
switch (type->tag) {
case PointerInfo: return Pointer$as_text(obj, colorize, type);
@ -168,19 +168,21 @@ public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type
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 EmptyStruct: return colorize ? CORD_all("\x1b[0;1m", type->EmptyStruct.name, "\x1b[m()") : CORD_all(type->EmptyStruct.name, "()");
case EmptyStruct: return colorize ?
Text$concat(Text$from_str("\x1b[0;1m"), Text$from_str(type->EmptyStruct.name), Text$from_str("\x1b[m()"))
: Text$concat(Text$from_str(type->EmptyStruct.name), Text$from_str("()"));
case CustomInfo:
if (!type->CustomInfo.as_text)
fail("No cord function provided for type!\n");
fail("No text function provided for type!\n");
return type->CustomInfo.as_text(obj, colorize, type);
default: errx(1, "Invalid type tag: %d", type->tag);
}
}
public CORD builtin_last_err()
public Text_t builtin_last_err()
{
return CORD_from_char_star(strerror(errno));
return Text$from_str(strerror(errno));
}
static int TEST_DEPTH = 0;
@ -193,12 +195,12 @@ public void start_test(const char *filename, int64_t start, int64_t end)
if (filename && file) {
for (int i = 0; i < 3*TEST_DEPTH; i++) fputc(' ', stderr);
CORD_fprintf(stderr, USE_COLOR ? "\x1b[33;1m>> \x1b[0m%.*s\x1b[m\n" : ">> %.*s\n", (end - start), file->text + start);
fprintf(stderr, USE_COLOR ? "\x1b[33;1m>> \x1b[0m%.*s\x1b[m\n" : ">> %.*s\n", (end - start), file->text + start);
}
++TEST_DEPTH;
}
public void end_test(void *expr, const TypeInfo *type, CORD expected, const char *filename, int64_t start, int64_t end)
public void end_test(void *expr, const TypeInfo *type, const char *expected, const char *filename, int64_t start, int64_t end)
{
(void)filename;
(void)start;
@ -206,25 +208,29 @@ public void end_test(void *expr, const TypeInfo *type, CORD expected, const char
--TEST_DEPTH;
if (!expr) return;
CORD expr_cord = generic_as_text(expr, USE_COLOR, type);
CORD type_name = generic_as_text(NULL, false, type);
Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
Text_t type_name = generic_as_text(NULL, false, type);
for (int i = 0; i < 3*TEST_DEPTH; i++) fputc(' ', stderr);
CORD_fprintf(stderr, USE_COLOR ? "\x1b[2m=\x1b[0m %r \x1b[2m: %r\x1b[m\n" : "= %r : %r\n", expr_cord, type_name);
if (expected) {
CORD expr_plain = USE_COLOR ? generic_as_text(expr, false, type) : expr_cord;
bool success = Text$equal(&expr_plain, &expected);
if (!success && CORD_chr(expected, 0, ':')) {
CORD with_type = CORD_catn(3, expr_plain, " : ", type_name);
success = Text$equal(&with_type, &expected);
fprintf(stderr, USE_COLOR ? "\x1b[2m=\x1b[0m %k \x1b[2m: %k\x1b[m\n" : "= %k : %k\n", &expr_text, &type_name);
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);
if (!success) {
Int_t colon = Text$find(expected_text, Text$from_str(":"), I_small(0), NULL);
if (colon.small != I_small(0).small) {
Text_t with_type = Text$concat(expr_plain, Text$from_str(" : "), type_name);
success = Text$equal(&with_type, &expected_text);
}
}
if (!success) {
fprintf(stderr,
USE_COLOR
? "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\nExpected: \x1b[1;32m%s\x1b[0m\n\x1b[1m But got:\x1b[m %s\n\n"
: "\n==================== TEST FAILED ====================\nExpected: %s\n\n But got: %s\n\n",
CORD_to_const_char_star(expected), CORD_to_const_char_star(expr_cord));
? "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\nExpected: \x1b[1;32m%s\x1b[0m\n\x1b[1m But got:\x1b[m %k\n\n"
: "\n==================== TEST FAILED ====================\nExpected: %s\n\n But got: %k\n\n",
expected, &expr_text);
print_stack_trace(stderr);
fflush(stderr);
@ -233,37 +239,29 @@ public void end_test(void *expr, const TypeInfo *type, CORD expected, const char
}
}
public void say(CORD text, bool newline)
public void say(Text_t text, bool newline)
{
uint8_t buf[512] = {0};
size_t buf_len = sizeof(buf)-1;
const char *str = CORD_to_const_char_star(text);
uint8_t *normalized = u8_normalize(UNINORM_NFD, (uint8_t*)str, strlen(str), buf, &buf_len);
if (normalized) {
write(STDOUT_FILENO, normalized, buf_len);
if (newline)
write(STDOUT_FILENO, "\n", 1);
if (normalized != buf)
free(normalized);
}
Text$print(stdout, text);
if (newline)
fputc('\n', stdout);
}
public bool pop_flag(char **argv, int *i, const char *flag, CORD *result)
public bool pop_flag(char **argv, int *i, const char *flag, Text_t *result)
{
if (argv[*i][0] != '-' || argv[*i][1] != '-') {
return false;
} else if (streq(argv[*i] + 2, flag)) {
*result = CORD_EMPTY;
*result = (Text_t){.length=0};
argv[*i] = NULL;
*i += 1;
return true;
} else if (strncmp(argv[*i] + 2, "no-", 3) == 0 && streq(argv[*i] + 5, flag)) {
*result = "no";
*result = Text$from_str("no");
argv[*i] = NULL;
*i += 1;
return true;
} else if (strncmp(argv[*i] + 2, flag, strlen(flag)) == 0 && argv[*i][2 + strlen(flag)] == '=') {
*result = CORD_from_char_star(argv[*i] + 2 + strlen(flag) + 1);
*result = Text$from_str(argv[*i] + 2 + strlen(flag) + 1);
argv[*i] = NULL;
*i += 1;
return true;

View File

@ -9,25 +9,25 @@
#include "datatypes.h"
#include "types.h"
extern uint8_t TOMO_HASH_KEY[8];
extern uint8_t TOMO_HASH_KEY[16];
void tomo_init(void);
void fail(CORD fmt, ...);
void fail_source(const char *filename, int64_t start, int64_t end, CORD fmt, ...);
CORD builtin_last_err();
void fail(const char *fmt, ...);
void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...);
Text_t builtin_last_err();
void start_test(const char *filename, int64_t start, int64_t end);
void end_test(void *expr, const TypeInfo *type, CORD expected, const char *filename, int64_t start, int64_t end);
void end_test(void *expr, const TypeInfo *type, const char *expected, const char *filename, int64_t start, int64_t end);
#define test(expr, type, expected, filename, start, end) {\
start_test(filename, start, end); \
end_test(expr, type, expected, filename, start, end); }
void say(CORD text, bool newline);
void say(Text_t text, bool newline);
uint32_t generic_hash(const void *obj, const TypeInfo *type);
uint64_t generic_hash(const void *obj, const TypeInfo *type);
int32_t generic_compare(const void *x, const void *y, const TypeInfo *type);
bool generic_equal(const void *x, const void *y, const TypeInfo *type);
CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type);
Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo *type);
closure_t spawn(closure_t fn);
bool pop_flag(char **argv, int *i, const char *flag, CORD *result);
bool pop_flag(char **argv, int *i, const char *flag, Text_t *result);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -1,4 +1,5 @@
// Integer type infos and methods
#include <ctype.h>
#include <gc.h>
#include <gc/cord.h>
#include <gmp.h>
@ -11,7 +12,8 @@
#include "integers.h"
#include "text.h"
#include "types.h"
#include "SipHash/halfsiphash.h"
#include "siphash.c"
static gmp_randstate_t Int_rng = {};
@ -21,15 +23,17 @@ public void Int$init_random(long seed)
gmp_randseed_ui(Int_rng, (unsigned long)seed);
}
public CORD Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type) {
public Text_t Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type) {
(void)type;
if (!i) return "Int";
if (!i) return Text$from_str("Int");
if (__builtin_expect(i->small & 1, 1)) {
return CORD_asprintf(colorize ? "\x1b[35m%ld\x1b[33;2m\x1b[m" : "%ld", (i->small)>>2);
return Text$format(colorize ? "\x1b[35m%ld\x1b[m" : "%ld", (i->small)>>2);
} else {
char *str = mpz_get_str(NULL, 10, *i->big);
return CORD_asprintf(colorize ? "\x1b[35m%s\x1b[33;2m\x1b[m" : "%s", str);
Text_t text = Text$from_str(str);
if (colorize) text = Text$concat(Text$from_str("\x1b[35m"), text, Text$from_str("\x1b[m"));
return text;
}
}
@ -55,62 +59,86 @@ public 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 uint32_t Int$hash(const Int_t *x, const TypeInfo *type) {
public uint64_t Int$hash(const Int_t *x, const TypeInfo *type) {
(void)type;
uint32_t hash;
if (__builtin_expect(x->small & 1, 1)) {
halfsiphash(&x->small, sizeof(x->small), TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
int64_t i = (x->small>>2);
return siphash24((void*)&i, sizeof(i), (uint64_t*)TOMO_HASH_KEY);
} else {
char *str = mpz_get_str(NULL, 16, *x->big);
halfsiphash(str, strlen(str), TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
return siphash24((void*)str, strlen(str), (uint64_t*)TOMO_HASH_KEY);
}
return hash;
}
public CORD Int$format(Int_t i, Int_t digits_int)
public Text_t Int$format(Int_t i, Int_t digits_int)
{
int64_t digits = Int_to_Int64(digits_int, false);
if (__builtin_expect(i.small & 1, 1)) {
return CORD_asprintf("%0.*ld", digits, (i.small)>>2);
return Text$format("%0.*ld", digits, (i.small)>>2);
} else {
CORD str = mpz_get_str(NULL, 10, *i.big);
char *str = mpz_get_str(NULL, 10, *i.big);
bool negative = (str[0] == '-');
if (digits > (int64_t)CORD_len(str)) {
if (negative)
str = CORD_all("-", CORD_chars('0', digits - CORD_len(str)), CORD_substr(str, 1, ~0));
else
str = CORD_all(CORD_chars('0', digits - CORD_len(str)), str);
int64_t needed_zeroes = digits - (int64_t)strlen(str);
if (needed_zeroes <= 0)
return Text$from_str(str);
char *zeroes = GC_MALLOC_ATOMIC(needed_zeroes);
memset(zeroes, '0', needed_zeroes);
if (negative)
return Text$concat(Text$from_str("-"), Text$from_str(zeroes), Text$from_str(str + 1));
else
return Text$concat(Text$from_str(zeroes), Text$from_str(str));
}
}
public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
if (Int$compare(&i, (Int_t[1]){I_small(0)}, &$Int) < 0)
return Text$concat(Text$from_str("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix));
int64_t digits = Int_to_Int64(digits_int, false);
if (__builtin_expect(i.small & 1, 1)) {
const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx");
return Text$format(hex_fmt, digits, (i.small)>>2);
} else {
char *str = mpz_get_str(NULL, 16, *i.big);
if (uppercase) {
for (char *c = str; *c; c++)
*c = (char)toupper(*c);
}
return str;
int64_t needed_zeroes = digits - (int64_t)strlen(str);
if (needed_zeroes <= 0)
return prefix ? Text$concat(Text$from_str("0x"), Text$from_str(str)) : Text$from_str(str);
char *zeroes = GC_MALLOC_ATOMIC(needed_zeroes);
memset(zeroes, '0', needed_zeroes);
if (prefix)
return Text$concat(Text$from_str("0x"), Text$from_str(zeroes), Text$from_str(str));
else
return Text$concat(Text$from_str(zeroes), Text$from_str(str));
}
}
public CORD Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
int64_t digits = Int_to_Int64(digits_int, false);
const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx");
if (__builtin_expect(i.small & 1, 1)) {
return CORD_asprintf(hex_fmt, digits, (i.small)>>2);
} else {
CORD str = mpz_get_str(NULL, 16, *i.big);
if (uppercase) str = Text$upper(str);
if (digits > (int64_t)CORD_len(str))
str = CORD_cat(CORD_chars('0', digits - CORD_len(str)), str);
if (prefix) str = CORD_cat("0x", str);
return str;
}
}
public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) {
Int_t zero = I_small(0);
if (Int$compare(&i, &zero, &$Int) < 0)
return Text$concat(Text$from_str("-"), Int$octal(Int$negative(i), digits_int, prefix));
public CORD Int$octal(Int_t i, Int_t digits_int, bool prefix) {
int64_t digits = Int_to_Int64(digits_int, false);
const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo";
if (__builtin_expect(i.small & 1, 1)) {
return CORD_asprintf(octal_fmt, (int)digits, (uint64_t)(i.small >> 2));
const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo";
return Text$format(octal_fmt, digits, (i.small)>>2);
} else {
CORD str = mpz_get_str(NULL, 8, *i.big);
if (digits > (int64_t)CORD_len(str))
str = CORD_cat(CORD_chars('0', digits - CORD_len(str)), str);
if (prefix) str = CORD_cat("0o", str);
return str;
char *str = mpz_get_str(NULL, 8, *i.big);
int64_t needed_zeroes = digits - (int64_t)strlen(str);
if (needed_zeroes <= 0)
return prefix ? Text$concat(Text$from_str("0o"), Text$from_str(str)) : Text$from_str(str);
char *zeroes = GC_MALLOC_ATOMIC(needed_zeroes);
memset(zeroes, '0', needed_zeroes);
if (prefix)
return Text$concat(Text$from_str("0o"), Text$from_str(zeroes), Text$from_str(str));
else
return Text$concat(Text$from_str(zeroes), Text$from_str(str));
}
}
@ -290,9 +318,11 @@ public Int_t Int$sqrt(Int_t i)
public Int_t Int$random(Int_t min, Int_t max) {
int32_t cmp = Int$compare(&min, &max, &$Int);
if (cmp > 0)
fail("Random minimum value (%r) is larger than the maximum value (%r)",
Int$as_text(&min, false, &$Int), Int$as_text(&max, false, &$Int));
if (cmp > 0) {
Text_t min_text = Int$as_text(&min, false, &$Int), max_text = Int$as_text(&max, false, &$Int);
fail("Random minimum value (%k) is larger than the maximum value (%k)",
&min_text, &max_text);
}
if (cmp == 0) return min;
mpz_t range_size;
@ -315,8 +345,8 @@ public Range_t Int$to(Int_t from, Int_t to) {
return (Range_t){from, to, Int$compare(&to, &from, &$Int) >= 0 ? (Int_t){.small=(1<<2)|1} : (Int_t){.small=(-1>>2)|1}};
}
public Int_t Int$from_text(CORD text, bool *success) {
const char *str = CORD_to_const_char_star(text);
public Int_t Int$from_text(Text_t text, bool *success) {
const char *str = Text$as_c_string(text);
mpz_t i;
int result;
if (strncmp(str, "0x", 2) == 0) {
@ -355,7 +385,7 @@ public Int_t Int$prev_prime(Int_t x)
mpz_t p;
mpz_init_set_int(p, x);
if (mpz_prevprime(p, p) == 0)
fail("There is no prime number before %r", Int$as_text(&x, false, &$Int));
fail("There is no prime number before %k", (Text_t[1]){Int$as_text(&x, false, &$Int)});
return Int$from_mpz(p);
}
@ -373,13 +403,11 @@ public const TypeInfo $Int = {
#define DEFINE_INT_TYPE(c_type, KindOfInt, fmt, min_val, max_val)\
public CORD KindOfInt ## $as_text(const c_type *i, bool colorize, const TypeInfo *type) { \
public Text_t KindOfInt ## $as_text(const c_type *i, bool colorize, const TypeInfo *type) { \
(void)type; \
if (!i) return #KindOfInt; \
CORD c; \
if (colorize) CORD_sprintf(&c, "\x1b[35m%"fmt"\x1b[33;2m\x1b[m", *i); \
else CORD_sprintf(&c, "%"fmt, *i); \
return c; \
if (!i) return Text$from_str(#KindOfInt); \
Int_t as_int = KindOfInt##_to_Int(*i); \
return Int$as_text(&as_int, colorize, type); \
} \
public int32_t KindOfInt ## $compare(const c_type *x, const c_type *y, const TypeInfo *type) { \
(void)type; \
@ -389,19 +417,17 @@ public const TypeInfo $Int = {
(void)type; \
return *x == *y; \
} \
public CORD KindOfInt ## $format(c_type i, Int_t digits_int) { \
int64_t digits = Int_to_Int64(digits_int, false); \
return CORD_asprintf("%0*ld", (int)digits, (int64_t)i); \
public Text_t KindOfInt ## $format(c_type i, Int_t digits_int) { \
Int_t as_int = KindOfInt##_to_Int(i); \
return Int$format(as_int, digits_int); \
} \
public CORD KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \
int64_t digits = Int_to_Int64(digits_int, false); \
const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx"); \
return CORD_asprintf(hex_fmt, (int)digits, (uint64_t)i); \
public Text_t KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \
Int_t as_int = KindOfInt##_to_Int(i); \
return Int$hex(as_int, digits_int, uppercase, prefix); \
} \
public CORD KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \
int64_t digits = Int_to_Int64(digits_int, false); \
const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo"; \
return CORD_asprintf(octal_fmt, (int)digits, (uint64_t)i); \
public Text_t KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \
Int_t as_int = KindOfInt##_to_Int(i); \
return Int$octal(as_int, digits_int, prefix); \
} \
public array_t KindOfInt ## $bits(c_type x) { \
array_t bit_array = (array_t){.data=GC_MALLOC_ATOMIC(sizeof(bool[8*sizeof(c_type)])), .atomic=1, .stride=sizeof(bool), .length=8*sizeof(c_type)}; \
@ -432,8 +458,8 @@ public const TypeInfo $Int = {
public Range_t KindOfInt ## $to(c_type from, c_type to) { \
return (Range_t){Int64_to_Int(from), Int64_to_Int(to), to >= from ? (Int_t){.small=(1<<2)&1} : (Int_t){.small=(1<<2)&1}}; \
} \
public c_type KindOfInt ## $from_text(CORD text, CORD *the_rest) { \
const char *str = CORD_to_const_char_star(text); \
public c_type KindOfInt ## $from_text(Text_t text, Text_t *the_rest) { \
const char *str = Text$as_c_string(text); \
long i; \
char *end_ptr = NULL; \
if (strncmp(str, "0x", 2) == 0) { \
@ -445,7 +471,7 @@ public const TypeInfo $Int = {
} else { \
i = strtol(str, &end_ptr, 10); \
} \
if (the_rest) *the_rest = CORD_from_char_star(end_ptr); \
if (the_rest) *the_rest = Text$from_str(end_ptr); \
if (i < min_val) i = min_val; \
else if (i > max_val) i = min_val; \
return (c_type)i; \

View File

@ -24,16 +24,16 @@
#define I8(x) ((int8_t)x)
#define DEFINE_INT_TYPE(c_type, type_name) \
CORD type_name ## $as_text(const c_type *i, bool colorize, const TypeInfo *type); \
Text_t type_name ## $as_text(const c_type *i, bool colorize, const TypeInfo *type); \
int32_t type_name ## $compare(const c_type *x, const c_type *y, const TypeInfo *type); \
bool type_name ## $equal(const c_type *x, const c_type *y, const TypeInfo *type); \
CORD type_name ## $format(c_type i, Int_t digits); \
CORD type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \
CORD type_name ## $octal(c_type i, Int_t digits, bool prefix); \
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); \
array_t type_name ## $bits(c_type x); \
c_type type_name ## $random(c_type min, c_type max); \
Range_t type_name ## $to(c_type from, c_type to); \
c_type type_name ## $from_text(CORD text, CORD *the_rest); \
c_type type_name ## $from_text(Text_t text, Text_t *the_rest); \
static inline c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \
return x < min ? min : (x > max ? max : x); \
} \
@ -70,19 +70,19 @@ DEFINE_INT_TYPE(int8_t, Int8);
#define Int16$abs(...) I16(abs(__VA_ARGS__))
#define Int8$abs(...) I8(abs(__VA_ARGS__))
CORD Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type);
uint32_t Int$hash(const Int_t *x, const TypeInfo *type);
Text_t Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type);
uint64_t Int$hash(const Int_t *x, const TypeInfo *type);
int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo *type);
int32_t Int$compare_value(const Int_t x, const Int_t y);
bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo *type);
bool Int$equal_value(const Int_t x, const Int_t y);
CORD Int$format(Int_t i, Int_t digits);
CORD Int$hex(Int_t i, Int_t digits, bool uppercase, bool prefix);
CORD Int$octal(Int_t i, Int_t digits, bool prefix);
Text_t Int$format(Int_t i, Int_t digits);
Text_t Int$hex(Int_t i, Int_t digits, bool uppercase, bool prefix);
Text_t Int$octal(Int_t i, Int_t digits, bool prefix);
void Int$init_random(long seed);
Int_t Int$random(Int_t min, Int_t max);
Range_t Int$to(Int_t from, Int_t to);
Int_t Int$from_text(CORD text, bool *success);
Int_t Int$from_text(Text_t text, bool *success);
Int_t Int$abs(Int_t x);
Int_t Int$power(Int_t base, Int_t exponent);
Int_t Int$sqrt(Int_t i);

View File

@ -1,6 +1,5 @@
// Type info and methods for "Memory" opaque type
#include <gc.h>
#include <gc/cord.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@ -8,17 +7,16 @@
#include <sys/param.h>
#include <err.h>
#include "util.h"
#include "halfsiphash.h"
#include "memory.h"
#include "text.h"
#include "types.h"
#include "util.h"
public CORD Memory__as_text(const void *p, bool colorize, const TypeInfo *type) {
public Text_t Memory__as_text(const void *p, bool colorize, const TypeInfo *type) {
(void)type;
if (!p) return "Memory";
CORD cord;
CORD_sprintf(&cord, colorize ? "\x1b[0;34;1mMemory<%p>\x1b[m" : "Memory<%p>", p);
return cord;
if (!p) return Text$from_str("Memory");
return Text$format(colorize ? "\x1b[0;34;1mMemory<%p>\x1b[m" : "Memory<%p>", p);
}
public const TypeInfo $Memory = {

View File

@ -9,6 +9,6 @@
#include "types.h"
extern const TypeInfo $Memory;
CORD Memory$as_text(const void *p, bool colorize, const TypeInfo *type);
Text_t Memory$as_text(const void *p, bool colorize, const TypeInfo *type);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -11,15 +11,13 @@
#include "array.h"
#include "nums.h"
#include "string.h"
#include "text.h"
#include "types.h"
public CORD Num$as_text(const double *f, bool colorize, const TypeInfo *type) {
public Text_t Num$as_text(const double *f, bool colorize, const TypeInfo *type) {
(void)type;
if (!f) return "Num";
CORD c;
if (colorize) CORD_sprintf(&c, "\x1b[35m%.16g\x1b[33;2m\x1b[m", *f);
else CORD_sprintf(&c, "%.16g", *f);
return c;
if (!f) return Text$from_str("Num");
return Text$format(colorize ? "\x1b[35m%.16g\x1b[33;2m\x1b[m" : "%.16g", *f);
}
public int32_t Num$compare(const double *x, const double *y, const TypeInfo *type) {
@ -47,12 +45,12 @@ public bool Num$near(double a, double b, double ratio, double absolute) {
return (diff < epsilon);
}
public CORD Num$format(double f, Int_t precision) {
return CORD_asprintf("%.*f", (int)Int_to_Int64(precision, false), f);
public Text_t Num$format(double f, Int_t precision) {
return Text$format("%.*f", (int)Int_to_Int64(precision, false), f);
}
public CORD Num$scientific(double f, Int_t precision) {
return CORD_asprintf("%.*e", (int)Int_to_Int64(precision, false), f);
public Text_t Num$scientific(double f, Int_t precision) {
return Text$format("%.*e", (int)Int_to_Int64(precision, false), f);
}
public double Num$mod(double num, double modulus) {
@ -68,16 +66,16 @@ public double Num$mix(double amount, double x, double y) {
return (1.0-amount)*x + amount*y;
}
public double Num$from_text(CORD text, CORD *the_rest) {
const char *str = CORD_to_const_char_star(text);
public double Num$from_text(Text_t text, Text_t *the_rest) {
const char *str = Text$as_c_string(text);
char *end = NULL;
double d = strtod(str, &end);
if (the_rest) *the_rest = CORD_from_char_star(end);
if (the_rest) *the_rest = Text$from_str(end);
return d;
}
public double Num$nan(CORD tag) {
return nan(CORD_to_const_char_star(tag));
public double Num$nan(Text_t tag) {
return nan(Text$as_c_string(tag));
}
public bool Num$isinf(double n) { return !!isinf(n); }
@ -95,13 +93,10 @@ public const TypeInfo $Num = {
},
};
public CORD Num32$as_text(const float *f, bool colorize, const TypeInfo *type) {
public Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo *type) {
(void)type;
if (!f) return "Num32";
CORD c;
if (colorize) CORD_sprintf(&c, "\x1b[35m%.8g_f32\x1b[m", *f);
else CORD_sprintf(&c, "%.8g_f32", *f);
return c;
if (!f) return Text$from_str("Num32");
return Text$format(colorize ? "\x1b[35m%.8g_f32\x1b[33;2m\x1b[m" : "%.8g_f32", *f);
}
public int32_t Num32$compare(const float *x, const float *y, const TypeInfo *type) {
@ -129,12 +124,12 @@ public bool Num32$near(float a, float b, float ratio, float absolute) {
return (diff < epsilon);
}
public CORD Num32$format(float f, Int_t precision) {
return CORD_asprintf("%.*f", (int)Int_to_Int64(precision, false), f);
public Text_t Num32$format(float f, Int_t precision) {
return Text$format("%.*f", (int)Int_to_Int64(precision, false), f);
}
public CORD Num32$scientific(float f, Int_t precision) {
return CORD_asprintf("%.*e", (int)Int_to_Int64(precision, false), f);
public Text_t Num32$scientific(float f, Int_t precision) {
return Text$format("%.*e", (int)Int_to_Int64(precision, false), f);
}
public float Num32$mod(float num, float modulus) {
@ -150,16 +145,16 @@ public float Num32$mix(float amount, float x, float y) {
return (1.0-amount)*x + amount*y;
}
public float Num32$from_text(CORD text, CORD *the_rest) {
const char *str = CORD_to_const_char_star(text);
public float Num32$from_text(Text_t text, Text_t *the_rest) {
const char *str = Text$as_c_string(text);
char *end = NULL;
double d = strtod(str, &end);
if (the_rest) *the_rest = CORD_from_char_star(end);
if (the_rest) *the_rest = Text$from_str(end);
return (float)d;
}
public float Num32$nan(CORD tag) {
return nanf(CORD_to_const_char_star(tag));
public float Num32$nan(Text_t tag) {
return nanf(Text$as_c_string(tag));
}
public bool Num32$isinf(float n) { return isinf(n); }

View File

@ -14,39 +14,39 @@
#define N32(n) ((float)n)
#define N64(n) ((double)n)
CORD Num$as_text(const double *f, bool colorize, const TypeInfo *type);
Text_t Num$as_text(const double *f, bool colorize, const TypeInfo *type);
int32_t Num$compare(const double *x, const double *y, const TypeInfo *type);
bool Num$equal(const double *x, const double *y, const TypeInfo *type);
bool Num$near(double a, double b, double ratio, double absolute);
CORD Num$format(double f, Int_t precision);
CORD Num$scientific(double f, Int_t precision);
Text_t Num$format(double f, Int_t precision);
Text_t Num$scientific(double f, Int_t precision);
double Num$mod(double num, double modulus);
bool Num$isinf(double n);
bool Num$finite(double n);
bool Num$isnan(double n);
double Num$nan(CORD tag);
double Num$nan(Text_t tag);
double Num$random(void);
double Num$mix(double amount, double x, double y);
double Num$from_text(CORD text, CORD *the_rest);
double Num$from_text(Text_t text, Text_t *the_rest);
static inline double Num$clamped(double x, double low, double high) {
return (x <= low) ? low : (x >= high ? high : x);
}
extern const TypeInfo $Num;
CORD Num32$as_text(const float *f, bool colorize, const TypeInfo *type);
Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo *type);
int32_t Num32$compare(const float *x, const float *y, const TypeInfo *type);
bool Num32$equal(const float *x, const float *y, const TypeInfo *type);
bool Num32$near(float a, float b, float ratio, float absolute);
CORD Num32$format(float f, Int_t precision);
CORD Num32$scientific(float f, Int_t precision);
Text_t Num32$format(float f, Int_t precision);
Text_t Num32$scientific(float f, Int_t precision);
float Num32$mod(float num, float modulus);
bool Num32$isinf(float n);
bool Num32$finite(float n);
bool Num32$isnan(float n);
float Num32$random(void);
float Num32$mix(float amount, float x, float y);
float Num32$from_text(CORD text, CORD *the_rest);
float Num32$nan(CORD tag);
float Num32$from_text(Text_t text, Text_t *the_rest);
float Num32$nan(Text_t tag);
static inline float Num32$clamped(float x, float low, float high) {
return (x <= low) ? low : (x >= high ? high : x);
}

View File

@ -8,27 +8,39 @@
#include <stdlib.h>
#include <sys/param.h>
#include "util.h"
#include "functions.h"
#include "halfsiphash.h"
#include "text.h"
#include "types.h"
#include "util.h"
typedef struct recursion_s {
const void *ptr;
struct recursion_s *next;
} recursion_t;
public CORD Pointer$as_text(const void *x, bool colorize, const TypeInfo *type) {
public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo *type) {
auto ptr_info = type->PointerInfo;
if (!x) {
CORD typename = generic_as_text(NULL, false, ptr_info.pointed);
CORD c = colorize ? CORD_asprintf("\x1b[34;1m%s%s\x1b[m", ptr_info.sigil, typename) : CORD_cat(ptr_info.sigil, typename);
return ptr_info.is_optional ? CORD_cat(c, "?") : c;
Text_t typename = generic_as_text(NULL, false, ptr_info.pointed);
Text_t text;
if (colorize)
text = Text$concat(Text$from_str("\x1b[34;1m"), Text$from_str(ptr_info.sigil), typename, Text$from_str("\x1b[m"));
else
text = Text$concat(Text$from_str(ptr_info.sigil), typename);
if (ptr_info.is_optional)
text = Text$concat(text, Text$from_str("?"));
return text;
}
const void *ptr = *(const void**)x;
if (!ptr) {
CORD typename = generic_as_text(NULL, false, ptr_info.pointed);
return colorize ? CORD_asprintf("\x1b[34;1m!%s\x1b[m", typename) : CORD_cat("!", typename);
Text_t typename = generic_as_text(NULL, false, ptr_info.pointed);
if (colorize)
return Text$concat(Text$from_str("\x1b[34;1m!"), typename, Text$from_str("\x1b[m"));
else
return Text$concat(Text$from_str("!"), typename);
}
// Check for recursive references, so if `x.foo = x`, then it prints as
@ -38,22 +50,34 @@ public CORD Pointer$as_text(const void *x, bool colorize, const TypeInfo *type)
for (recursion_t *r = recursion; r; r = r->next) {
++depth;
if (r->ptr == ptr) {
CORD c = CORD_asprintf(colorize ? "\x1b[34;1m%s..%d\x1b[m" : "%s..%d", ptr_info.sigil, depth);
if (ptr_info.is_optional) c = CORD_cat(c, colorize ? "\x1b[34;1m?\x1b[m" : "?");
return c;
Text_t text = Text$concat(
Text$from_str(colorize ? "\x1b[34;1m" : ""),
Text$from_str(ptr_info.sigil),
Text$from_str(".."),
Int32$as_text(&depth, false, &$Int32),
Text$from_str(colorize ? "\x1b[m" : ""));
if (ptr_info.is_optional)
text = Text$concat(text, Text$from_str(colorize ? "\x1b[34;1m?\x1b[m" : "?"));
return text;
}
}
CORD pointed;
Text_t pointed;
{ // Stringify with this pointer flagged as a recursive one:
recursion_t my_recursion = {.ptr=ptr, .next=recursion};
recursion = &my_recursion;
pointed = generic_as_text(ptr, colorize, ptr_info.pointed);
recursion = recursion->next;
}
CORD c = colorize ? CORD_asprintf("\x1b[34;1m%s\x1b[m%r", ptr_info.sigil, pointed) : CORD_cat(ptr_info.sigil, pointed);
if (ptr_info.is_optional) c = CORD_cat(c, colorize ? "\x1b[34;1m?\x1b[m" : "?");
return c;
Text_t text;
if (colorize)
text = Text$concat(Text$from_str("\x1b[34;1m"), Text$from_str(ptr_info.sigil), Text$from_str("\x1b[m"), pointed);
else
text = Text$concat(Text$from_str(ptr_info.sigil), pointed);
if (ptr_info.is_optional)
text = Text$concat(text, Text$from_str("?"));
return text;
}
public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo *type) {
@ -68,11 +92,4 @@ public bool Pointer$equal(const void *x, const void *y, const TypeInfo *type) {
return xp == yp;
}
public uint32_t Pointer$hash(const void *x, const TypeInfo *type) {
(void)type;
uint32_t hash;
halfsiphash(x, sizeof(void*), TOMO_HASH_KEY, (uint8_t*)&hash, sizeof(hash));
return hash;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -8,10 +8,9 @@
#include "types.h"
CORD Pointer$as_text(const void *x, bool colorize, const TypeInfo *type);
Text_t Pointer$as_text(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 Null(t) (t*)NULL
#define POINTER_TYPE(_sigil, _pointed) (&(TypeInfo){\

View File

@ -4,15 +4,15 @@
#include <err.h>
#include <gmp.h>
#include <gc.h>
#include <gc/cord.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/param.h>
#include "types.h"
#include "integers.h"
#include "text.h"
#include "types.h"
#include "util.h"
@ -32,15 +32,15 @@ static bool Range$equal(const Range_t *x, const Range_t *y, const TypeInfo *type
return Int$equal(&x->first, &y->first, &$Int) && Int$equal(&x->last, &y->last, &$Int) && Int$equal(&x->step, &y->step, &$Int);
}
static CORD Range$as_text(const Range_t *r, bool use_color, const TypeInfo *type)
static Text_t Range$as_text(const Range_t *r, bool use_color, const TypeInfo *type)
{
(void)type;
if (!r) return "Range";
if (!r) return Text$from_str("Range");
return CORD_asprintf(use_color ? "\x1b[0;1mRange\x1b[m(first=%r, last=%r, step=%r)"
: "Range(first=%r, last=%r, step=%r)",
Int$as_text(&r->first, use_color, &$Int), Int$as_text(&r->last, use_color, &$Int),
Int$as_text(&r->step, use_color, &$Int));
return Text$format(use_color ? "\x1b[0;1mRange\x1b[m(first=%r, last=%r, step=%r)"
: "Range(first=%r, last=%r, step=%r)",
Int$as_text(&r->first, use_color, &$Int), Int$as_text(&r->last, use_color, &$Int),
Int$as_text(&r->step, use_color, &$Int));
}
public Range_t Range$reversed(Range_t r)

View File

@ -16,14 +16,15 @@
#include <string.h>
#include <sys/param.h>
#include "util.h"
#include "array.h"
#include "c_string.h"
#include "datatypes.h"
#include "halfsiphash.h"
#include "memory.h"
#include "table.h"
#include "text.h"
#include "types.h"
#include "util.h"
// #define DEBUG_TABLES
@ -51,11 +52,11 @@ static const TypeInfo MemoryPointer = {
},
};
const TypeInfo StrToVoidStarTable = {
const TypeInfo CStrToVoidStarTable = {
.size=sizeof(table_t),
.align=__alignof__(table_t),
.tag=TableInfo,
.TableInfo={.key=&$Text, .value=&MemoryPointer},
.TableInfo={.key=&$CString, .value=&MemoryPointer},
};
static inline size_t entry_size(const TypeInfo *info)
@ -450,36 +451,43 @@ public uint32_t Table$hash(const table_t *t, const TypeInfo *type)
return hash;
}
public CORD Table$as_text(const table_t *t, bool colorize, const TypeInfo *type)
public Text_t Table$as_text(const table_t *t, bool colorize, const TypeInfo *type)
{
assert(type->tag == TableInfo);
auto table = type->TableInfo;
if (!t) {
if (table.value != &$Void)
return CORD_all("{", generic_as_text(NULL, false, table.key), ":", generic_as_text(NULL, false, table.value), "}");
return Text$concat(
Text$from_str("{"),
generic_as_text(NULL, false, table.key),
Text$from_str(":"),
generic_as_text(NULL, false, table.value),
Text$from_str("}"));
else
return CORD_all("{", generic_as_text(NULL, false, table.key), "}");
return Text$concat(
Text$from_str("{"),
generic_as_text(NULL, false, table.key),
Text$from_str("}"));
}
int64_t val_off = value_offset(type);
CORD c = "{";
Text_t text = Text$from_str("{");
for (int64_t i = 0, length = Table$length(*t); i < length; i++) {
if (i > 0)
c = CORD_cat(c, ", ");
text = Text$concat(text, Text$from_str(", "));
void *entry = GET_ENTRY(*t, i);
c = CORD_cat(c, generic_as_text(entry, colorize, table.key));
text = Text$concat(text, generic_as_text(entry, colorize, table.key));
if (table.value != &$Void)
c = CORD_all(c, ":", generic_as_text(entry + val_off, colorize, table.value));
text = Text$concat(text, Text$from_str(":"), generic_as_text(entry + val_off, colorize, table.value));
}
if (t->fallback) {
c = CORD_cat(c, "; fallback=");
c = CORD_cat(c, Table$as_text(t->fallback, colorize, type));
text = Text$concat(text, Text$from_str("; fallback="), Table$as_text(t->fallback, colorize, type));
}
c = CORD_cat(c, "}");
return c;
text = Text$concat(text, Text$from_str("}"));
return text;
}
public table_t Table$from_entries(array_t entries, const TypeInfo *type)
@ -592,29 +600,29 @@ public bool Table$is_superset_of(table_t a, table_t b, bool strict, const TypeIn
public void *Table$str_get(table_t t, const char *key)
{
void **ret = Table$get(t, &key, &StrToVoidStarTable);
void **ret = Table$get(t, &key, &CStrToVoidStarTable);
return ret ? *ret : NULL;
}
public void *Table$str_get_raw(table_t t, const char *key)
{
void **ret = Table$get_raw(t, &key, &StrToVoidStarTable);
void **ret = Table$get_raw(t, &key, &CStrToVoidStarTable);
return ret ? *ret : NULL;
}
public void *Table$str_reserve(table_t *t, const char *key, const void *value)
{
return Table$reserve(t, &key, &value, &StrToVoidStarTable);
return Table$reserve(t, &key, &value, &CStrToVoidStarTable);
}
public void Table$str_set(table_t *t, const char *key, const void *value)
{
Table$set(t, &key, &value, &StrToVoidStarTable);
Table$set(t, &key, &value, &CStrToVoidStarTable);
}
public void Table$str_remove(table_t *t, const char *key)
{
return Table$remove(t, &key, &StrToVoidStarTable);
return Table$remove(t, &key, &CStrToVoidStarTable);
}
public void *Table$str_entry(table_t t, int64_t n)

View File

@ -74,7 +74,7 @@ void Table$mark_copy_on_write(table_t *t);
int32_t Table$compare(const table_t *x, const table_t *y, const TypeInfo *type);
bool Table$equal(const table_t *x, const table_t *y, const TypeInfo *type);
uint32_t Table$hash(const table_t *t, const TypeInfo *type);
CORD Table$as_text(const table_t *t, bool colorize, const TypeInfo *type);
Text_t Table$as_text(const table_t *t, bool colorize, const TypeInfo *type);
void *Table$str_entry(table_t t, int64_t n);
void *Table$str_get(table_t t, const char *key);
@ -85,6 +85,6 @@ void Table$str_remove(table_t *t, const char *key);
#define Table$length(t) ((t).entries.length)
extern const TypeInfo StrToVoidStarTable;
extern const TypeInfo CStrToVoidStarTable;
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
#pragma once
// Type info and methods for Text datatype, which uses the Boehm "cord" library
// and libunistr
// Type info and methods for Text datatype, which uses a struct inspired by
// Raku's string representation and libunistr
#include <gc/cord.h>
#include <stdbool.h>
#include <printf.h>
#include <stdint.h>
#include "datatypes.h"
@ -12,36 +12,57 @@
#include "types.h"
#include "where.h"
#define Text_t CORD
typedef struct {
enum { FIND_FAILURE, FIND_SUCCESS } status;
int32_t index;
} find_result_t;
CORD Text$as_text(const void *str, bool colorize, const TypeInfo *info);
CORD Text$quoted(CORD str, bool colorize);
int Text$compare(const CORD *x, const CORD *y);
bool Text$equal(const CORD *x, const CORD *y);
uint32_t Text$hash(const CORD *cord);
CORD Text$upper(CORD str);
CORD Text$lower(CORD str);
CORD Text$title(CORD str);
bool Text$has(CORD str, CORD target, Where_t where);
CORD Text$without(CORD str, CORD target, Where_t where);
CORD Text$trimmed(CORD str, CORD skip, Where_t where);
find_result_t Text$find(CORD str, CORD pat);
CORD Text$replace(CORD text, CORD pat, CORD replacement, Int_t limit);
array_t Text$split(CORD str, CORD split);
CORD Text$join(CORD glue, array_t pieces);
array_t Text$clusters(CORD text);
array_t Text$codepoints(CORD text);
array_t Text$bytes(CORD text);
Int_t Text$num_clusters(CORD text);
Int_t Text$num_codepoints(CORD text);
Int_t Text$num_bytes(CORD text);
array_t Text$character_names(CORD text);
CORD Text$read_line(CORD prompt);
// CORD Text$as_text(const void *str, bool colorize, const TypeInfo *info);
// CORD Text$quoted(CORD str, bool colorize);
// // int Text$compare(const CORD *x, const CORD *y);
// // bool Text$equal(const CORD *x, const CORD *y);
// // uint32_t Text$hash(const CORD *cord);
// // CORD Text$upper(CORD str);
// // CORD Text$lower(CORD str);
// // CORD Text$title(CORD str);
// bool Text$has(CORD str, CORD target, Where_t where);
// CORD Text$without(CORD str, CORD target, Where_t where);
// CORD Text$trimmed(CORD str, CORD skip, Where_t where);
// find_result_t Text$find(CORD str, CORD pat);
// CORD Text$replace(CORD text, CORD pat, CORD replacement, Int_t limit);
// array_t Text$split(CORD str, CORD split);
// CORD Text$join(CORD glue, array_t pieces);
// array_t Text$clusters(CORD text);
// array_t Text$codepoints(CORD text);
// array_t Text$bytes(CORD text);
// Int_t Text$num_clusters(CORD text);
// Int_t Text$num_codepoints(CORD text);
// Int_t Text$num_bytes(CORD text);
// array_t Text$character_names(CORD text);
// CORD Text$read_line(CORD prompt);
int printf_text(FILE *stream, const struct printf_info *info, const void *const args[]);
int printf_text_size(const struct printf_info *info, size_t n, int argtypes[n], int sizes[n]);
int Text$print(FILE *stream, Text_t t);
void Text$visualize(Text_t t);
Text_t Text$_concat(int n, Text_t items[n]);
#define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__})/sizeof(Text_t), (Text_t[]){__VA_ARGS__})
Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int);
Text_t Text$from_str(const char *str);
uint64_t Text$hash(Text_t *text);
int32_t Text$compare(const Text_t *a, const Text_t *b);
bool Text$equal(const Text_t *a, const Text_t *b);
bool Text$equal_ignoring_case(Text_t a, Text_t b);
Text_t Text$upper(Text_t text);
Text_t Text$lower(Text_t text);
Text_t Text$title(Text_t text);
Text_t Text$as_text(const void *text, bool colorize, const TypeInfo *info);
Text_t Text$quoted(Text_t str, bool colorize);
Text_t Text$replace(Text_t str, Text_t pat, Text_t replacement);
Int_t Text$find(Text_t text, Text_t pattern, Int_t i, int64_t *match_length);
const char *Text$as_c_string(Text_t text);
public Text_t Text$format(const char *fmt, ...);
extern const TypeInfo $Text;

View File

@ -3,7 +3,6 @@
#include <ctype.h>
#include <err.h>
#include <gc.h>
#include <gc/cord.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
@ -14,6 +13,7 @@
#include "array.h"
#include "functions.h"
#include "halfsiphash.h"
#include "text.h"
#include "types.h"
#include "util.h"
@ -39,13 +39,13 @@ public void Thread$detach(pthread_t *thread)
pthread_detach(*thread);
}
CORD Thread$as_text(const pthread_t **thread, bool colorize, const TypeInfo *type)
Text_t Thread$as_text(const pthread_t **thread, bool colorize, const TypeInfo *type)
{
(void)type;
if (!thread) {
return colorize ? "\x1b[34;1mThread\x1b[m" : "Thread";
return Text$from_str(colorize ? "\x1b[34;1mThread\x1b[m" : "Thread");
}
return CORD_asprintf(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *thread);
return Text$format(colorize ? "\x1b[34;1mThread(%p)\x1b[m" : "Thread(%p)", *thread);
}
public const TypeInfo Thread = {

View File

@ -14,7 +14,7 @@ pthread_t *Thread$new(closure_t fn);
void Thread$cancel(pthread_t *thread);
void Thread$join(pthread_t *thread);
void Thread$detach(pthread_t *thread);
CORD Thread$as_text(const pthread_t **thread, bool colorize, const TypeInfo *type);
Text_t Thread$as_text(const pthread_t **thread, bool colorize, const TypeInfo *type);
extern TypeInfo Thread;

View File

@ -9,17 +9,20 @@
#include "array.h"
#include "pointer.h"
#include "table.h"
#include "text.h"
#include "types.h"
public CORD Type$as_text(const void *typeinfo, bool colorize, const TypeInfo *type)
public Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo *type)
{
if (!typeinfo) return "TypeInfo";
if (!typeinfo) return Text$from_str("TypeInfo");
if (!colorize)
return type->TypeInfoInfo.type_str;
CORD c;
CORD_sprintf(&c, "\x1b[36;1m%s\x1b[m", type->TypeInfoInfo.type_str);
return c;
if (colorize)
return Text$concat(
Text$from_str("\x1b[36;1m"),
Text$from_str(type->TypeInfoInfo.type_str),
Text$from_str("\x1b[m"));
else
return Text$from_str(type->TypeInfoInfo.type_str);
}
public const TypeInfo $TypeInfo = {
@ -32,13 +35,13 @@ public const TypeInfo $TypeInfo = {
public const TypeInfo $Void = {.size=0, .align=0, .tag=EmptyStruct};
public const TypeInfo $Abort = {.size=0, .align=0, .tag=EmptyStruct};
public CORD Func$as_text(const void *fn, bool colorize, const TypeInfo *type)
public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo *type)
{
(void)fn;
CORD c = type->FunctionInfo.type_str;
Text_t text = Text$from_str(type->FunctionInfo.type_str);
if (fn && colorize)
CORD_sprintf(&c, "\x1b[32;1m%r\x1b[m", c);
return c;
text = Text$concat(Text$from_str("\x1b[32;1m"), text, Text$from_str("\x1b[m"));
return text;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -2,7 +2,6 @@
// Type information and methods for TypeInfos (i.e. runtime representations of types)
#include <gc/cord.h>
#include <stdbool.h>
#include <stdint.h>
@ -13,7 +12,7 @@ struct TypeInfo;
typedef uint32_t (*hash_fn_t)(const void*, const struct TypeInfo*);
typedef int32_t (*compare_fn_t)(const void*, const void*, const struct TypeInfo*);
typedef bool (*equal_fn_t)(const void*, const void*, const struct TypeInfo*);
typedef CORD (*str_fn_t)(const void*, bool, const struct TypeInfo*);
typedef Text_t (*text_fn_t)(const void*, bool, const struct TypeInfo*);
typedef struct TypeInfo {
int64_t size, align;
@ -24,7 +23,7 @@ typedef struct TypeInfo {
equal_fn_t equal;
compare_fn_t compare;
hash_fn_t hash;
str_fn_t as_text;
text_fn_t as_text;
} CustomInfo;
struct {
const char *sigil;
@ -76,7 +75,7 @@ extern const TypeInfo $Void;
extern const TypeInfo $Abort;
#define Void_t void
CORD Type$as_text(const void *typeinfo, bool colorize, const TypeInfo *type);
CORD Func$as_text(const void *fn, bool colorize, const TypeInfo *type);
Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo *type);
Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo *type);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
#include "text.h"
#include "util.h"
public bool USE_COLOR;
@ -67,4 +68,54 @@ public CORD CORD_asprintf(CORD fmt, ...)
return c;
}
public CORD CORD_quoted(CORD str)
{
CORD quoted = "\"";
CORD_pos i;
CORD_FOR(i, str) {
char c = CORD_pos_fetch(i);
switch (c) {
case '\a': quoted = CORD_cat(quoted, "\\a"); break;
case '\b': quoted = CORD_cat(quoted, "\\b"); break;
case '\x1b': quoted = CORD_cat(quoted, "\\e"); break;
case '\f': quoted = CORD_cat(quoted, "\\f"); break;
case '\n': quoted = CORD_cat(quoted, "\\n"); break;
case '\r': quoted = CORD_cat(quoted, "\\r"); break;
case '\t': quoted = CORD_cat(quoted, "\\t"); break;
case '\v': quoted = CORD_cat(quoted, "\\v"); break;
case '"': quoted = CORD_cat(quoted, "\\\""); break;
case '\\': quoted = CORD_cat(quoted, "\\\\"); break;
case '\x00' ... '\x06': case '\x0E' ... '\x1A':
case '\x1C' ... '\x1F': case '\x7F' ... '\x7F':
CORD_sprintf(&quoted, "%r\\x%02X", quoted, c);
break;
default: quoted = CORD_cat_char(quoted, c); break;
}
}
quoted = CORD_cat_char(quoted, '"');
return quoted;
}
public CORD CORD_replace(CORD c, CORD to_replace, CORD replacement)
{
size_t len = CORD_len(c);
size_t replaced_len = CORD_len(to_replace);
size_t pos = 0;
CORD ret = CORD_EMPTY;
while (pos < len) {
size_t found = CORD_str(c, pos, to_replace);
if (found == CORD_NOT_FOUND) {
if (pos < len-1)
ret = CORD_cat(ret, CORD_substr(c, pos, len));
return ret;
}
if (found > pos)
ret = CORD_cat(ret, CORD_substr(c, pos, found-pos));
ret = CORD_cat(ret, replacement);
pos = found + replaced_len;
}
return ret;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -31,6 +31,8 @@ extern bool USE_COLOR;
char *heap_strf(const char *fmt, ...);
CORD CORD_asprintf(CORD fmt, ...);
CORD CORD_quoted(CORD str);
CORD CORD_replace(CORD c, CORD to_replace, CORD replacement);
#define CORD_appendf(cord, fmt, ...) CORD_sprintf(cord, "%r" fmt, *(cord) __VA_OPT__(,) __VA_ARGS__)
#define CORD_all(...) CORD_catn(sizeof((CORD[]){__VA_ARGS__})/sizeof(CORD), __VA_ARGS__)

View File

@ -1,27 +1,27 @@
// A type called "Where" that is an enum for "Anywhere", "Start", or "End"
// Mainly used for text methods
#include <gc/cord.h>
#include <stdbool.h>
#include <stdint.h>
#include "text.h"
#include "types.h"
#include "where.h"
#include "util.h"
#include "where.h"
static CORD Where$as_text(Where_t *obj, bool use_color)
static Text_t Where$as_text(Where_t *obj, bool use_color)
{
if (!obj)
return "Where";
return Text$from_str("Where");
switch (obj->tag) {
case $tag$Where$Anywhere:
return use_color ? "\x1b[36;1mWhere.Anywhere\x1b[m" : "Where.Anywhere";
return Text$from_str(use_color ? "\x1b[36;1mWhere.Anywhere\x1b[m" : "Where.Anywhere");
case $tag$Where$Start:
return use_color ? "\x1b[36;1mWhere.Start\x1b[m" : "Where.Start";
return Text$from_str(use_color ? "\x1b[36;1mWhere.Start\x1b[m" : "Where.Start");
case $tag$Where$End:
return use_color ? "\x1b[36;1mWhere.End\x1b[m" : "Where.End";
return Text$from_str(use_color ? "\x1b[36;1mWhere.End\x1b[m" : "Where.End");
default:
return CORD_EMPTY;
return (Text_t){.length=0};
}
}

View File

@ -224,7 +224,7 @@ static CORD compile_lvalue(env_t *env, ast_t *ast)
return CORD_all("Array_lvalue(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
", ", CORD_asprintf("%ld", padded_type_size(item_type)),
", ", Text$quoted(ast->file->filename, false), ", ", heap_strf("%ld", ast->start - ast->file->text),
", ", CORD_quoted(ast->file->filename), ", ", heap_strf("%ld", ast->start - ast->file->text),
", ", heap_strf("%ld", ast->end - ast->file->text), ")");
}
} else {
@ -320,7 +320,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (!expr_t)
code_err(test->expr, "I couldn't figure out the type of this expression");
CORD output = NULL;
CORD output = CORD_EMPTY;
if (test->output) {
const uint8_t *raw = (const uint8_t*)CORD_to_const_char_star(test->output);
uint8_t buf[128] = {0};
@ -328,6 +328,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
uint8_t *norm = u8_normalize(UNINORM_NFD, (uint8_t*)raw, strlen((char*)raw)+1, buf, &norm_len);
assert(norm[norm_len-1] == 0);
output = CORD_from_char_star((char*)norm);
CORD_printf("OUTPUT: %r\n", output);
if (norm && norm != buf) free(norm);
}
@ -337,8 +338,8 @@ CORD compile_statement(env_t *env, ast_t *ast)
assert(compile_statement(env, test->expr) == CORD_EMPTY);
return CORD_asprintf(
"test(NULL, NULL, %r, %r, %ld, %ld);",
compile(env, WrapAST(test->expr, TextLiteral, .cord=output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(output),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else {
@ -355,8 +356,8 @@ CORD compile_statement(env_t *env, ast_t *ast)
compile_declaration(t, var),
var, val_code, var,
compile_type_info(env, get_type(env, decl->value)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(output),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
}
@ -382,8 +383,8 @@ CORD compile_statement(env_t *env, ast_t *ast)
compile_assignment(env, assign->targets->ast, value),
compile(env, assign->targets->ast),
compile_type_info(env, lhs_t),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(test->output),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else {
@ -415,8 +416,8 @@ CORD compile_statement(env_t *env, ast_t *ast)
CORD_appendf(&code, "&$1; }), %r, %r, %r, %ld, %ld);",
compile_type_info(env, get_type(env, assign->targets->ast)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(test->output),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
return code;
@ -427,25 +428,25 @@ CORD compile_statement(env_t *env, ast_t *ast)
compile_statement(env, test->expr),
compile_lvalue(env, Match(test->expr, UpdateAssign)->lhs),
compile_type_info(env, get_type(env, Match(test->expr, UpdateAssign)->lhs)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(test->output),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) {
return CORD_asprintf(
"test(({ %r; NULL; }), NULL, NULL, %r, %ld, %ld);",
compile_statement(env, test->expr),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else {
return CORD_asprintf(
"test(%r, %r, %r, %r, %ld, %ld);",
test->expr->tag == Var ? CORD_all("&", compile(env, test->expr))
: CORD_all("(", compile_type(expr_t), "[1]){", compile(env, test->expr), "}"),
: CORD_all("(", compile_type(expr_t), "[1]){", compile(env, test->expr), "}"),
compile_type_info(env, expr_t),
compile(env, WrapAST(test->expr, TextLiteral, .cord=output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
CORD_quoted(output),
CORD_quoted(test->expr->file->filename),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
}
@ -629,7 +630,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
auto def = Match(ast, LangDef);
CORD_appendf(&env->code->typeinfos, "public const TypeInfo %r%s = {%zu, %zu, {.tag=TextInfo, .TextInfo={%r}}};\n",
namespace_prefix(env->libname, env->namespace), def->name, sizeof(CORD), __alignof__(CORD),
Text$quoted(def->name, false));
CORD_quoted(def->name));
compile_namespace(env, def->name, def->namespace);
return CORD_EMPTY;
}
@ -703,7 +704,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
"}\n");
env->code->funcs = CORD_cat(env->code->funcs, wrapper);
} else if (fndef->cache && fndef->cache->tag == Int) {
int64_t cache_size = Int64$from_text(Match(fndef->cache, Int)->str, NULL);
int64_t cache_size = Int64$from_text(Text$from_str(Match(fndef->cache, Int)->str), NULL);
const char *arg_type_name = heap_strf("%s$args", Match(fndef->name, Var)->name);
ast_t *args_def = FakeAST(StructDef, .name=arg_type_name, .fields=fndef->args);
prebind_statement(env, args_def);
@ -1314,7 +1315,7 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
}
int64_t target_bits = (int64_t)Match(target, IntType)->bits;
Int_t int_val = Int$from_text(Match(ast, Int)->str, NULL);
Int_t int_val = Int$from_text(Text$from_str(Match(ast, Int)->str), NULL);
mpz_t i;
mpz_init_set_int(i, int_val);
@ -1354,7 +1355,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t
if (spec_arg->type->tag == IntType && call_arg->value->tag == Int) {
value = compile_int_to_type(env, call_arg->value, spec_arg->type);
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
Int_t int_val = Int$from_text(Match(call_arg->value, Int)->str, NULL);
Int_t int_val = Int$from_text(Text$from_str(Match(call_arg->value, Int)->str), NULL);
double n = Int_to_Num(int_val);
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
? "N64(%.20g)" : "N32(%.10g)", n);
@ -1382,7 +1383,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t
if (spec_arg->type->tag == IntType && call_arg->value->tag == Int) {
value = compile_int_to_type(env, call_arg->value, spec_arg->type);
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
Int_t int_val = Int$from_text(Match(call_arg->value, Int)->str, NULL);
Int_t int_val = Int$from_text(Text$from_str(Match(call_arg->value, Int)->str), NULL);
double n = Int_to_Num(int_val);
value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
? "N64(%.20g)" : "N32(%.10g)", n);
@ -1513,7 +1514,7 @@ CORD compile(env_t *env, ast_t *ast)
}
case Int: {
const char *str = Match(ast, Int)->str;
Int_t int_val = Int$from_text(str, NULL);
Int_t int_val = Int$from_text(Text$from_str(str), NULL);
mpz_t i;
mpz_init_set_int(i, int_val);
@ -1780,8 +1781,8 @@ CORD compile(env_t *env, ast_t *ast)
case TextLiteral: {
CORD literal = Match(ast, TextLiteral)->cord;
if (literal == CORD_EMPTY)
return "(CORD)CORD_EMPTY";
CORD code = "(CORD)\"";
return "((Text_t){.length=0})";
CORD code = "Text$from_str(\"";
CORD_pos i;
CORD_FOR(i, literal) {
char c = CORD_pos_fetch(i);
@ -1803,7 +1804,7 @@ CORD compile(env_t *env, ast_t *ast)
}
}
}
return CORD_cat_char(code, '"');
return CORD_cat(code, "\")");
}
case TextJoin: {
const char *lang = Match(ast, TextJoin)->lang;
@ -1812,7 +1813,7 @@ CORD compile(env_t *env, ast_t *ast)
code_err(ast, "%s is not a valid text language name", lang);
ast_list_t *chunks = Match(ast, TextJoin)->children;
if (!chunks) {
return "(CORD)CORD_EMPTY";
return "((Text_t){.length=0})";
} else if (!chunks->next && chunks->ast->tag == TextLiteral) {
return compile(env, chunks->ast);
} else {
@ -1839,7 +1840,7 @@ CORD compile(env_t *env, ast_t *ast)
if (chunk->next) code = CORD_cat(code, ", ");
}
if (chunks->next)
return CORD_all("CORD_all(", code, ")");
return CORD_all("Text$concat(", code, ")");
else
return code;
}
@ -2447,7 +2448,8 @@ CORD compile(env_t *env, ast_t *ast)
file_t *f = ast->file;
return CORD_all("Table$get_value_or_fail(", self, ", ", compile_type(table->key_type), ", ", compile_type(table->value_type), ", ",
compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(env, self_value_t), ", ",
Text$quoted(f->filename, false), ", ", CORD_asprintf("%ld", (int64_t)(ast->start - f->text)), ", ",
CORD_quoted(f->filename), ", ",
CORD_asprintf("%ld", (int64_t)(ast->start - f->text)), ", ",
CORD_asprintf("%ld", (int64_t)(ast->end - f->text)),
")");
}
@ -2630,8 +2632,9 @@ CORD compile(env_t *env, ast_t *ast)
} else {
empty = FakeAST(
InlineCCode,
CORD_asprintf("fail_source(%r, %ld, %ld, \"This collection was empty!\");\n",
Text$quoted(ast->file->filename, false), (long)(reduction->iter->start - reduction->iter->file->text),
CORD_asprintf("fail_source(%s, %ld, %ld, \"This collection was empty!\");\n",
CORD_quoted(ast->file->filename),
(long)(reduction->iter->start - reduction->iter->file->text),
(long)(reduction->iter->end - reduction->iter->file->text)));
}
ast_t *item = FakeAST(Var, "$iter_value");
@ -2785,7 +2788,8 @@ CORD compile(env_t *env, ast_t *ast)
else
return CORD_all("Array_get(", compile_type(item_type), ", ", arr, ", ",
compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)), ", ",
Text$quoted(f->filename, false), ", ", CORD_asprintf("%ld", (int64_t)(indexing->index->start - f->text)), ", ",
CORD_quoted(f->filename), ", ",
CORD_asprintf("%ld", (int64_t)(indexing->index->start - f->text)), ", ",
CORD_asprintf("%ld", (int64_t)(indexing->index->end - f->text)),
")");
} else {
@ -2935,15 +2939,15 @@ CORD compile_type_info(env_t *env, type_t *t)
CORD sigil = ptr->is_stack ? "&" : "@";
if (ptr->is_readonly) sigil = CORD_cat(sigil, "%");
return CORD_asprintf("$PointerInfo(%r, %r, %s)",
Text$quoted(sigil, false),
CORD_quoted(sigil),
compile_type_info(env, ptr->pointed),
ptr->is_optional ? "yes" : "no");
}
case FunctionType: {
return CORD_asprintf("$FunctionInfo(%r)", Text$quoted(type_to_cord(t), false));
return CORD_asprintf("$FunctionInfo(%r)", CORD_quoted(type_to_cord(t)));
}
case ClosureType: {
return CORD_asprintf("$ClosureInfo(%r)", Text$quoted(type_to_cord(t), false));
return CORD_asprintf("$ClosureInfo(%r)", CORD_quoted(type_to_cord(t)));
}
case TypeInfoType: return "&$TypeInfo";
case MemoryType: return "&$Memory";
@ -2968,7 +2972,7 @@ CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
usage = CORD_cat(usage, " ");
type_t *t = get_arg_type(main_env, arg);
CORD flag = Text$replace(arg->name, "_", "-", I(-1));
CORD flag = CORD_replace(arg->name, "_", "-");
if (arg->default_val) {
if (t->tag == BoolType)
usage = CORD_all(usage, "[--", flag, "]");
@ -2983,7 +2987,7 @@ CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
usage = CORD_all(usage, "<", flag, ">");
}
}
CORD code = CORD_all("CORD usage = CORD_all(\"Usage: \", argv[0], ", usage ? Text$quoted(usage, false) : "CORD_EMPTY", ");\n",
CORD code = CORD_all("CORD usage = CORD_all(\"Usage: \", argv[0], ", usage ? CORD_quoted(usage) : "CORD_EMPTY", ");\n",
"#define USAGE_ERR(...) errx(1, CORD_to_const_char_star(CORD_all(__VA_ARGS__)))\n"
"#define IS_FLAG(str, flag) (strncmp(str, flag, strlen(flag) == 0 && (str[strlen(flag)] == 0 || str[strlen(flag)] == '=')) == 0)\n");
@ -3006,7 +3010,7 @@ CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
"if (strncmp(argv[i], \"--\", 2) != 0) {\n++i;\ncontinue;\n}\n");
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
type_t *t = get_arg_type(main_env, arg);
CORD flag = Text$replace(arg->name, "_", "-", I(-1));
CORD flag = CORD_replace(arg->name, "_", "-");
switch (t->tag) {
case BoolType: {
code = CORD_all(code, "else if (pop_flag(argv, &i, \"", flag, "\", &flag)) {\n"

View File

@ -15,6 +15,7 @@
#include "ast.h"
#include "builtins/integers.h"
#include "builtins/text.h"
#include "builtins/table.h"
#include "builtins/util.h"
@ -1894,7 +1895,7 @@ ast_t *parse_enum_def(parse_ctx_t *ctx, const char *pos) {
spaces(&pos);
if (match(&pos, "=")) {
ast_t *val = expect(ctx, tag_start, &pos, parse_int, "I expected an integer literal after this '='");
Int_t i = Int$from_text(Match(val, Int)->str, NULL);
Int_t i = Int$from_text(Text$from_str(Match(val, Int)->str), NULL);
// TODO check for overflow
next_value = (i.small >> 2);
}

18
repl.c
View File

@ -208,7 +208,7 @@ static double ast_to_num(env_t *env, ast_t *ast)
}
}
static CORD obj_to_text(type_t *t, const void *obj, bool use_color)
static Text_t obj_to_text(type_t *t, const void *obj, bool use_color)
{
const TypeInfo *info = type_to_type_info(t);
return generic_as_text(obj, use_color, info);
@ -272,8 +272,8 @@ void run(env_t *env, ast_t *ast)
} else {
void *value = GC_MALLOC(size);
eval(env, doctest->expr, value);
CORD c = obj_to_text(t, value, true);
printf("= %s \x1b[2m: %T\x1b[m\n", CORD_to_const_char_star(c), t);
Text_t text = obj_to_text(t, value, true);
printf("= %k \x1b[2m: %T\x1b[m\n", &text, t);
fflush(stdout);
}
break;
@ -353,11 +353,11 @@ void eval(env_t *env, ast_t *ast, void *dest)
case Int: {
if (!dest) return;
switch (Match(ast, Int)->bits) {
case 0: *(Int_t*)dest = Int$from_text(Match(ast, Int)->str, NULL); break;
case 64: *(int64_t*)dest = Int64$from_text(Match(ast, Int)->str, NULL); break;
case 32: *(int32_t*)dest = Int32$from_text(Match(ast, Int)->str, NULL); break;
case 16: *(int16_t*)dest = Int16$from_text(Match(ast, Int)->str, NULL); break;
case 8: *(int8_t*)dest = Int8$from_text(Match(ast, Int)->str, NULL); break;
case 0: *(Int_t*)dest = Int$from_text(Text$from_str(Match(ast, Int)->str), NULL); break;
case 64: *(int64_t*)dest = Int64$from_text(Text$from_str(Match(ast, Int)->str), NULL); break;
case 32: *(int32_t*)dest = Int32$from_text(Text$from_str(Match(ast, Int)->str), NULL); break;
case 16: *(int16_t*)dest = Int16$from_text(Text$from_str(Match(ast, Int)->str), NULL); break;
case 8: *(int8_t*)dest = Int8$from_text(Text$from_str(Match(ast, Int)->str), NULL); break;
default: errx(1, "Invalid int bits: %ld", Match(ast, Int)->bits);
}
break;
@ -386,7 +386,7 @@ void eval(env_t *env, ast_t *ast, void *dest)
size_t chunk_size = type_size(chunk_t);
char buf[chunk_size];
eval(env, chunk->ast, buf);
ret = CORD_cat(ret, obj_to_text(chunk_t, buf, false));
ret = CORD_cat(ret, Text$as_c_string(obj_to_text(chunk_t, buf, false)));
}
}
if (dest) *(CORD*)dest = ret;

View File

@ -166,7 +166,7 @@ void compile_struct_def(env_t *env, ast_t *ast)
} else {
// If there are no fields, we can use an EmptyStruct typeinfo, which generates less code:
CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=EmptyStruct, .EmptyStruct.name=%r}};\n",
full_name, type_size(t), type_align(t), Text$quoted(def->name, false));
full_name, type_size(t), type_align(t), Text$quoted(Text$from_str(def->name), false));
env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo);
}

2
tomo.c
View File

@ -84,6 +84,8 @@ int main(int argc, char *argv[])
errx(1, "Couldn't set printf specifier");
if (register_printf_specifier('W', printf_ast, printf_pointer_size))
errx(1, "Couldn't set printf specifier");
if (register_printf_specifier('k', printf_text, printf_text_size))
errx(1, "Couldn't set printf specifier");
setenv("TOMO_IMPORT_PATH", "~/.local/src/tomo:.", 0);
setenv("TOMO_LIB_PATH", "~/.local/lib/tomo:.", 0);

View File

@ -9,11 +9,12 @@
#include <sys/stat.h>
#include "ast.h"
#include "builtins/text.h"
#include "builtins/util.h"
#include "environment.h"
#include "parse.h"
#include "typecheck.h"
#include "types.h"
#include "builtins/util.h"
type_t *parse_type_ast(env_t *env, type_ast_t *ast)
{
@ -1367,7 +1368,7 @@ bool is_constant(env_t *env, ast_t *ast)
case Int: {
auto info = Match(ast, Int);
if (info->bits == IBITS_UNSPECIFIED) {
Int_t int_val = Int$from_text(info->str, NULL);
Int_t int_val = Int$from_text(Text$from_str(info->str), NULL);
mpz_t i;
mpz_init_set_int(i, int_val);
return (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0);