From cb336b312e7012dc05fe7d8ac1c0e924dbc6c840 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 24 Dec 2025 19:04:37 -0500 Subject: Shuffle dependencies around so header files aren't needed after tomo has been compiled --- src/compile/integers.c | 15 ++- src/compile/loops.c | 8 +- src/compile/statements.c | 4 +- src/environment.c | 5 - src/environment.h | 2 +- src/modules.c | 2 +- src/parse/errors.h | 2 +- src/parse/suffixes.c | 2 +- src/parse/types.c | 2 +- src/print.c | 235 ++++++++++++++++++++++++++++++++++++++++++++ src/print.h | 165 +++++++++++++++++++++++++++++++ src/stdlib/bigint.c | 57 +++++------ src/stdlib/bigint.h | 14 +-- src/stdlib/bytes.c | 3 +- src/stdlib/c_strings.c | 4 +- src/stdlib/cli.c | 2 +- src/stdlib/datatypes.h | 3 +- src/stdlib/enums.c | 1 + src/stdlib/fail.c | 38 +++++++ src/stdlib/fail.h | 9 ++ src/stdlib/files.c | 2 +- src/stdlib/int64.c | 16 +++ src/stdlib/int64.h | 2 + src/stdlib/intX.c.h | 84 +++++++++++++++- src/stdlib/intX.h | 56 +++-------- src/stdlib/lists.c | 1 + src/stdlib/memory.c | 2 +- src/stdlib/metamethods.c | 15 +-- src/stdlib/numX.c.h | 38 +++++++ src/stdlib/numX.h | 33 +------ src/stdlib/paths.c | 2 +- src/stdlib/paths.h | 3 +- src/stdlib/print.c | 251 ----------------------------------------------- src/stdlib/print.h | 165 ------------------------------- src/stdlib/stacktrace.c | 2 +- src/stdlib/stdlib.c | 9 +- src/stdlib/stdlib.h | 44 --------- src/stdlib/tables.c | 3 +- src/stdlib/text.h | 3 +- src/stdlib/tomo.h | 3 +- src/tomo.c | 2 +- src/util.h | 22 +++++ 42 files changed, 703 insertions(+), 628 deletions(-) create mode 100644 src/print.c create mode 100644 src/print.h create mode 100644 src/stdlib/fail.c create mode 100644 src/stdlib/fail.h delete mode 100644 src/stdlib/print.c delete mode 100644 src/stdlib/print.h (limited to 'src') diff --git a/src/compile/integers.c b/src/compile/integers.c index 5f99afbd..0e89f3dd 100644 --- a/src/compile/integers.c +++ b/src/compile/integers.c @@ -7,9 +7,9 @@ #include "../stdlib/datatypes.h" #include "../stdlib/integers.h" #include "../stdlib/text.h" -#include "../util.h" #include "../typecheck.h" #include "../types.h" +#include "../util.h" #include "compilation.h" public @@ -35,7 +35,11 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { if (int_val.small == 0) code_err(ast, "Failed to parse this integer"); mpz_t i; - mpz_init_set_int(i, int_val); + if likely (int_val.small & 1L) { + mpz_init_set_si(i, int_val.small >> 2L); + } else { + mpz_init_set(i, int_val.big); + } char *c_literal; if (strncmp(literal, "0x", 2) == 0 || strncmp(literal, "0X", 2) == 0 || strncmp(literal, "0b", 2) == 0) { @@ -86,7 +90,12 @@ Text_t compile_int(ast_t *ast) { OptionalInt_t int_val = Int$from_str(str); if (int_val.small == 0) code_err(ast, "Failed to parse this integer"); mpz_t i; - mpz_init_set_int(i, int_val); + if likely (int_val.small & 1L) { + mpz_init_set_si(i, int_val.small >> 2L); + } else { + mpz_init_set(i, int_val.big); + } + if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) { return Texts("I_small(", str, ")"); } else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) { diff --git a/src/compile/loops.c b/src/compile/loops.c index 3ccf0416..d818bbe4 100644 --- a/src/compile/loops.c +++ b/src/compile/loops.c @@ -8,8 +8,8 @@ #include "../stdlib/datatypes.h" #include "../stdlib/integers.h" #include "../stdlib/text.h" -#include "../util.h" #include "../typecheck.h" +#include "../util.h" #include "compilation.h" public @@ -236,7 +236,11 @@ Text_t compile_for_loop(env_t *env, ast_t *ast) { Int_t int_val = Int$from_str(str); if (int_val.small == 0) code_err(for_->iter, "Failed to parse this integer"); mpz_t i; - mpz_init_set_int(i, int_val); + if likely (int_val.small & 1L) { + mpz_init_set_si(i, int_val.small >> 2L); + } else { + mpz_init_set(i, int_val.big); + } if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) n = Text$from_str(mpz_get_str(NULL, 10, i)); else goto big_n; diff --git a/src/compile/statements.c b/src/compile/statements.c index 7a2f1947..e1b20021 100644 --- a/src/compile/statements.c +++ b/src/compile/statements.c @@ -7,13 +7,13 @@ #include "../environment.h" #include "../modules.h" #include "../naming.h" +#include "../print.h" #include "../stdlib/datatypes.h" #include "../stdlib/paths.h" -#include "../stdlib/print.h" #include "../stdlib/tables.h" #include "../stdlib/text.h" -#include "../util.h" #include "../typecheck.h" +#include "../util.h" #include "compilation.h" typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *); diff --git a/src/environment.c b/src/environment.c index cdf02884..a53823aa 100644 --- a/src/environment.c +++ b/src/environment.c @@ -132,11 +132,6 @@ env_t *global_env(bool source_mapping) { {"parse", "Int$parse", "func(text:Text, base:Int?=none, remainder:&Text?=none -> Int?)"}, // {"plus", "Int$plus", "func(x,y:Int -> Int)"}, // {"power", "Int$power", "func(base:Int,exponent:Int -> Int)"}, // -#if __GNU_MP_VERSION >= 6 -#if __GNU_MP_VERSION_MINOR >= 3 - {"prev_prime", "Int$prev_prime", "func(x:Int -> Int?)"}, // -#endif -#endif {"right_shifted", "Int$right_shifted", "func(x,y:Int -> Int)"}, // {"sqrt", "Int$sqrt", "func(x:Int -> Int?)"}, // {"times", "Int$times", "func(x,y:Int -> Int)"}, // diff --git a/src/environment.h b/src/environment.h index ba036f2e..bdfbbc2c 100644 --- a/src/environment.h +++ b/src/environment.h @@ -2,8 +2,8 @@ #pragma once +#include "print.h" // IWYU pragma: export #include "stdlib/datatypes.h" -#include "stdlib/print.h" // IWYU pragma: export #include "stdlib/stdlib.h" // IWYU pragma: export #include "types.h" diff --git a/src/modules.c b/src/modules.c index 54b461f9..2c60574f 100644 --- a/src/modules.c +++ b/src/modules.c @@ -7,10 +7,10 @@ #include "config.h" #include "modules.h" +#include "print.h" #include "stdlib/memory.h" #include "stdlib/paths.h" #include "stdlib/pointers.h" -#include "stdlib/print.h" #include "stdlib/simpleparse.h" #include "stdlib/tables.h" #include "stdlib/text.h" diff --git a/src/parse/errors.h b/src/parse/errors.h index 55610439..94977439 100644 --- a/src/parse/errors.h +++ b/src/parse/errors.h @@ -5,8 +5,8 @@ #include // IWYU pragma: export #include // IWYU pragma: export +#include "../print.h" // IWYU pragma: export #include "../stdlib/files.h" // IWYU pragma: export -#include "../stdlib/print.h" // IWYU pragma: export #include "../stdlib/stacktrace.h" // IWYU pragma: export #include "../stdlib/stdlib.h" // IWYU pragma: export #include "context.h" // IWYU pragma: export diff --git a/src/parse/suffixes.c b/src/parse/suffixes.c index 71844642..0815bd0e 100644 --- a/src/parse/suffixes.c +++ b/src/parse/suffixes.c @@ -3,7 +3,7 @@ #include #include "../ast.h" -#include "../stdlib/print.h" +#include "../print.h" #include "../util.h" #include "context.h" #include "errors.h" diff --git a/src/parse/types.c b/src/parse/types.c index 2da0b5ff..1efa0b6e 100644 --- a/src/parse/types.c +++ b/src/parse/types.c @@ -8,8 +8,8 @@ #include #include "../ast.h" +#include "../print.h" #include "../stdlib/datatypes.h" -#include "../stdlib/print.h" #include "../stdlib/text.h" #include "context.h" #include "errors.h" diff --git a/src/print.c b/src/print.c new file mode 100644 index 00000000..c065dbb2 --- /dev/null +++ b/src/print.c @@ -0,0 +1,235 @@ +// This file defines some of the helper functions used for printing values + +#include +#include +#include +#include + +#include "print.h" +#include "stdlib/fpconv.h" +#include "util.h" + +public +int _print_uint(FILE *f, uint64_t n) { + char buf[21] = {[20] = 0}; // Big enough for UINT64_MAX + '\0' + char *p = &buf[19]; + + do { + *(p--) = '0' + (n % 10); + n /= 10; + } while (n > 0); + + return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); +} + +public +int _print_hex(FILE *f, hex_format_t hex) { + int printed = 0; + if (!hex.no_prefix) printed += fputs("0x", f); + if (hex.digits > 0) { + hex.digits -= (hex.n == 0); // Don't need a leading zero for a zero + for (uint64_t n = hex.n; n > 0 && hex.digits > 0; n /= 16) { + hex.digits -= 1; + } + for (; hex.digits > 0; hex.digits -= 1) { + printed += fputc('0', f); + } + } + char buf[9] = {[8] = '\0'}; // Enough space for FFFFFFFF + '\0' + char *p = &buf[7]; + do { + uint8_t digit = hex.n % 16; + if (digit <= 9) *(p--) = '0' + digit; + else if (hex.uppercase) *(p--) = 'A' + digit - 10; + else *(p--) = 'a' + digit - 10; + hex.n /= 16; + } while (hex.n > 0); + printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[7] - p), f); + return printed; +} + +public +int _print_oct(FILE *f, oct_format_t oct) { + int printed = 0; + if (!oct.no_prefix) printed += fputs("0o", f); + if (oct.digits > 0) { + oct.digits -= (oct.n == 0); // Don't need a leading zero for a zero + for (uint64_t n = oct.n; n > 0 && oct.digits > 0; n /= 8) + oct.digits -= 1; + for (; oct.digits > 0; oct.digits -= 1) + printed += fputc('0', f); + } + char buf[12] = {[11] = '\0'}; // Enough space for octal UINT64_MAX + '\0' + char *p = &buf[10]; + do { + *(p--) = '0' + (oct.n % 8); + oct.n /= 8; + } while (oct.n > 0); + printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[10] - p), f); + return printed; +} + +public +int _print_double(FILE *f, double n) { + static char buf[24]; + int len = fpconv_dtoa(n, buf); + return (int)fwrite(buf, sizeof(char), (size_t)len, f); +} + +public +int _print_hex_double(FILE *f, hex_double_t hex) { + if (hex.d != hex.d) return fputs("NAN", f); + else if (hex.d == 1.0 / 0.0) return fputs("INF", f); + else if (hex.d == -1.0 / 0.0) return fputs("-INF", f); + else if (hex.d == 0.0) return fputs("0.0", f); + + union { + double d; + uint64_t u; + } bits = {.d = hex.d}; + + int sign = (bits.u >> 63) & 1ull; + int exp = (int)((bits.u >> 52) & 0x7FF) - 1023ull; + uint64_t frac = bits.u & 0xFFFFFFFFFFFFFull; + + char buf[25]; + char *p = buf; + + if (sign) *p++ = '-'; + *p++ = '0'; + *p++ = 'x'; + + uint64_t mantissa = (1ull << 52) | frac; // implicit 1 + int mantissa_shift = 52; + + while ((mantissa & 0xF) == 0 && mantissa_shift > 0) { + mantissa >>= 4; + mantissa_shift -= 4; + } + + uint64_t int_part = mantissa >> mantissa_shift; + *p++ = "0123456789abcdef"[int_part]; + + *p++ = '.'; + + while (mantissa_shift > 0) { + mantissa_shift -= 4; + uint64_t digit = (mantissa >> mantissa_shift) & 0xF; + *p++ = "0123456789abcdef"[digit]; + } + + *p++ = 'p'; + + if (exp >= 0) { + *p++ = '+'; + } else { + *p++ = '-'; + exp = -exp; + } + + char expbuf[6]; + int ei = 5; + expbuf[ei--] = '\0'; + do { + expbuf[ei--] = '0' + (exp % 10); + exp /= 10; + } while (exp && ei >= 0); + + ei++; + while (expbuf[ei]) + *p++ = expbuf[ei++]; + + *p = '\0'; + return fwrite(buf, sizeof(char), (size_t)(p - buf), f); +} + +public +int _print_char(FILE *f, char c) { +#define ESC(e) "'\\" e "'" + const char *named[256] = { + ['\''] = ESC("'"), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"), + ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")}; + const char *name = named[(uint8_t)c]; + if (name != NULL) return fputs(name, f); + else if (isprint(c)) return fputc('\'', f) + fputc(c, f) + fputc('\'', f); + else + return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits = 2, .no_prefix = true, .uppercase = true)) + + fputs("'", f)); +#undef ESC +} + +public +int _print_quoted(FILE *f, quoted_t quoted) { +#define ESC(e) "\\" e + const char *named[256] = { + ['"'] = ESC("\""), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"), + ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")}; + int printed = fputc('"', f); + for (const char *p = quoted.str; *p; p++) { + const char *name = named[(uint8_t)*p]; + if (name != NULL) { + printed += fputs(name, f); + } else if (isprint(*p) || (uint8_t)*p > 0x7F) { + printed += fputc(*p, f); + } else { + printed += + fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits = 2, .no_prefix = true, .uppercase = true)); + } + } + printed += fputc('"', f); +#undef ESC + return printed; +} + +#if defined(__GLIBC__) && defined(_GNU_SOURCE) +// GLIBC has fopencookie() +static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) { + gc_stream_t *stream = (gc_stream_t *)cookie; + if (stream->position + size + 1 > *stream->size) + *stream->buffer = + GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL))); + memcpy(&(*stream->buffer)[stream->position], buf, size); + stream->position += size; + (*stream->buffer)[stream->position] = '\0'; + return (ssize_t)size; +} + +public +FILE *gc_memory_stream(char **buf, size_t *size) { + gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); + stream->size = size; + stream->buffer = buf; + *stream->size = 16; + *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); + (*stream->buffer)[0] = '\0'; + stream->position = 0; + cookie_io_functions_t functions = {.write = _gc_stream_write}; + return fopencookie(stream, "w", functions); +} +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +// BSDs have funopen() and fwopen() +static int _gc_stream_write(void *cookie, const char *buf, int size) { + gc_stream_t *stream = (gc_stream_t *)cookie; + if (stream->position + size + 1 > *stream->size) + *stream->buffer = + GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL))); + memcpy(&(*stream->buffer)[stream->position], buf, size); + stream->position += size; + (*stream->buffer)[stream->position] = '\0'; + return size; +} + +public +FILE *gc_memory_stream(char **buf, size_t *size) { + gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); + stream->size = size; + stream->buffer = buf; + *stream->size = 16; + *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); + (*stream->buffer)[0] = '\0'; + stream->position = 0; + return fwopen(stream, _gc_stream_write); +} +#else +#error "This platform doesn't support fopencookie() or funopen()!" +#endif diff --git a/src/print.h b/src/print.h new file mode 100644 index 00000000..1b9645fa --- /dev/null +++ b/src/print.h @@ -0,0 +1,165 @@ +// This file defines some functions to make it easy to do formatted text +// without using printf style specifiers: +// +// print(...) - print text +// fprint(file, ...) - print text to file +// print_err(...) - print an error message and exit with EXIT_FAILURE +// String(...) - return an allocated string + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stdlib/bigint.h" // IWYU pragma: export +#include "stdlib/datatypes.h" // IWYU pragma: export +#include "stdlib/integers.h" // IWYU pragma: export +#include "stdlib/mapmacro.h" +#include "stdlib/paths.h" // IWYU pragma: export +#include "stdlib/text.h" // IWYU pragma: export + +// GCC lets you define macro-like functions which are always inlined and never +// compiled using this combination of flags. See: https://gcc.gnu.org/onlinedocs/gcc/Inline.html +#ifndef PRINT_FN +#ifdef __TINYC__ +#define PRINT_FN static inline __attribute__((gnu_inline, always_inline)) int +#else +#define PRINT_FN extern inline __attribute__((gnu_inline, always_inline)) int +#endif +#endif + +typedef struct { + uint64_t n; + bool no_prefix; + bool uppercase; + int digits; +} hex_format_t; +#define hex(x, ...) ((hex_format_t){.n = x, __VA_ARGS__}) + +typedef struct { + double d; +} hex_double_t; +#define hex_double(x, ...) ((hex_double_t){.d = x, __VA_ARGS__}) + +typedef struct { + uint64_t n; + bool no_prefix; + int digits; +} oct_format_t; +#define oct(x, ...) ((oct_format_t){.n = x, __VA_ARGS__}) + +typedef struct { + const char *str; +} quoted_t; +#define quoted(s) ((quoted_t){s}) + +typedef struct { + const char *str; + size_t length; +} string_slice_t; +#define string_slice(...) ((string_slice_t){__VA_ARGS__}) + +typedef struct { + char c; + int length; +} repeated_char_t; +#define repeated_char(ch, len) ((repeated_char_t){.c = ch, .length = len}) + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#define FMT64 "ll" +#else +#define FMT64 "l" +#endif + +int _print_uint(FILE *f, uint64_t x); +int _print_double(FILE *f, double x); +int _print_hex(FILE *f, hex_format_t hex); +int _print_hex_double(FILE *f, hex_double_t hex); +int _print_oct(FILE *f, oct_format_t oct); +PRINT_FN _print_float(FILE *f, float x) { return _print_double(f, (double)x); } +PRINT_FN _print_pointer(FILE *f, void *p) { return _print_hex(f, hex((uint64_t)p)); } +PRINT_FN _print_bool(FILE *f, bool b) { return fputs(b ? "yes" : "no", f); } +PRINT_FN _print_str(FILE *f, const char *s) { return fputs(s ? s : "(null)", f); } +int _print_char(FILE *f, char c); +int _print_quoted(FILE *f, quoted_t quoted); +PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) { + return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f); +} +PRINT_FN _print_repeated_char(FILE *f, repeated_char_t repeated) { + int len = 0; + for (int n = 0; n < repeated.length; n++) + len += fputc(repeated.c, f); + return len; +} + +#ifndef _fprint1 +#define _fprint1(f, x) \ + _Generic((x), \ + char *: _print_str, \ + const char *: _print_str, \ + char: _print_char, \ + bool: _print_bool, \ + int64_t: Int64$print, \ + int32_t: Int64$print, \ + int16_t: Int64$print, \ + int8_t: Int64$print, \ + uint64_t: _print_uint, \ + uint32_t: _print_uint, \ + uint16_t: _print_uint, \ + uint8_t: _print_uint, \ + float: _print_float, \ + double: _print_double, \ + hex_format_t: _print_hex, \ + hex_double_t: _print_hex_double, \ + oct_format_t: _print_oct, \ + quoted_t: _print_quoted, \ + string_slice_t: _print_string_slice, \ + repeated_char_t: _print_repeated_char, \ + Text_t: Text$print, \ + Path_t: Path$print, \ + Int_t: Int$print, \ + void *: _print_pointer)(f, x) +#endif + +typedef struct { + char **buffer; + size_t *size; + size_t position; +} gc_stream_t; + +FILE *gc_memory_stream(char **buf, size_t *size); + +#define _print(x) _n += _fprint1(_printing, x) +#define _fprint(f, ...) \ + ({ \ + FILE *_printing = f; \ + int _n = 0; \ + MAP_LIST(_print, __VA_ARGS__); \ + _n; \ + }) +#define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n") +#define print(...) fprint(stdout, __VA_ARGS__) +#define fprint_inline(f, ...) _fprint(f, __VA_ARGS__) +#define print_inline(...) fprint_inline(stdout, __VA_ARGS__) +#define String(...) \ + ({ \ + char *_buf = NULL; \ + size_t _size = 0; \ + FILE *_stream = gc_memory_stream(&_buf, &_size); \ + assert(_stream); \ + _fprint(_stream, __VA_ARGS__); \ + fflush(_stream); \ + _buf; \ + }) +#define print_err(...) \ + ({ \ + fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); \ + exit(EXIT_FAILURE); \ + }) diff --git a/src/stdlib/bigint.c b/src/stdlib/bigint.c index 84da1468..4a5b2565 100644 --- a/src/stdlib/bigint.c +++ b/src/stdlib/bigint.c @@ -10,19 +10,28 @@ #include #include +#include "../print.h" +#include "../util.h" #include "datatypes.h" #include "integers.h" #include "optionals.h" -#include "print.h" #include "siphash.h" #include "text.h" #include "types.h" +#define mpz_init_set_int(mpz, i) \ + do { \ + if likely ((i).small & 1L) mpz_init_set_si(mpz, (i).small >> 2L); \ + else mpz_init_set(mpz, (i).big); \ + } while (0) + #define Int$from_mpz(mpz) \ (mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 \ ? ((Int_t){.small = (mpz_get_si(mpz) << 2L) | 1L}) \ : ((Int_t){.big = memcpy(GC_MALLOC(sizeof(__mpz_struct)), mpz, sizeof(__mpz_struct))})) +#define Int_mpz(i) (__mpz_struct *)((i).big) + #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" @@ -50,9 +59,9 @@ PUREFUNC Int_t Int$from_int64(int64_t i) { public int Int$print(FILE *f, Int_t i) { if (likely(i.small & 1L)) { - return _print_int(f, (int64_t)((i.small) >> 2L)); + return Int64$print(f, (int64_t)((i.small) >> 2L)); } else { - return gmp_fprintf(f, "%Zd", i.big); + return gmp_fprintf(f, "%Zd", Int_mpz(i)); } } @@ -79,7 +88,7 @@ Text_t Int$value_as_text(Int_t i) { if (likely(i.small & 1L)) { return _int64_to_text(i.small >> 2L); } else { - char *str = mpz_get_str(NULL, 10, i.big); + char *str = mpz_get_str(NULL, 10, Int_mpz(i)); return Text$from_str(str); } } @@ -101,9 +110,9 @@ static bool Int$is_none(const void *i, const TypeInfo_t *info) { public PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) { if (likely(x.small & y.small & 1L)) return (x.small > y.small) - (x.small < y.small); - else if (x.small & 1) return -mpz_cmp_si(y.big, x.small); - else if (y.small & 1) return mpz_cmp_si(x.big, y.small); - else return x.big == y.big ? 0 : mpz_cmp(x.big, y.big); + else if (x.small & 1) return -mpz_cmp_si(Int_mpz(y), x.small); + else if (y.small & 1) return mpz_cmp_si(Int_mpz(x), y.small); + else return x.big == y.big ? 0 : mpz_cmp(Int_mpz(x), Int_mpz(y)); } public @@ -115,7 +124,7 @@ PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *inf public PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) { if (likely((x.small | y.small) & 1L)) return x.small == y.small; - else return x.big == y.big ? 0 : (mpz_cmp(x.big, y.big) == 0); + else return x.big == y.big ? 0 : (mpz_cmp(Int_mpz(x), Int_mpz(y)) == 0); } public @@ -141,7 +150,7 @@ PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t *info) { if (likely(x->small & 1L)) { return siphash24((void *)x, sizeof(Int_t)); } else { - char *str = mpz_get_str(NULL, 16, x->big); + char *str = mpz_get_str(NULL, 16, Int_mpz(*x)); return siphash24((void *)str, strlen(str)); } } @@ -155,7 +164,7 @@ Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { return Text$from_str(String( hex(u64, .no_prefix = !prefix, .digits = Int32$from_int(digits_int, false), .uppercase = uppercase))); } else { - char *str = mpz_get_str(NULL, 16, i.big); + char *str = mpz_get_str(NULL, 16, Int_mpz(i)); if (uppercase) { for (char *c = str; *c; c++) *c = (char)toupper(*c); @@ -180,7 +189,7 @@ Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) { return Text$from_str(String(oct(u64, .no_prefix = !prefix, .digits = Int32$from_int(digits_int, false)))); } else { int64_t digits = Int64$from_int(digits_int, false); - char *str = mpz_get_str(NULL, 8, i.big); + char *str = mpz_get_str(NULL, 8, Int_mpz(i)); int64_t needed_zeroes = digits - (int64_t)strlen(str); if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0o"), Text$from_str(str)) : Text$from_str(str); @@ -199,7 +208,7 @@ Int_t Int$slow_plus(Int_t x, Int_t y) { if (y.small < 0L) mpz_sub_ui(result, result, (uint64_t)(-(y.small >> 2L))); else mpz_add_ui(result, result, (uint64_t)(y.small >> 2L)); } else { - mpz_add(result, result, y.big); + mpz_add(result, result, Int_mpz(y)); } return Int$from_mpz(result); } @@ -212,7 +221,7 @@ Int_t Int$slow_minus(Int_t x, Int_t y) { if (y.small < 0L) mpz_add_ui(result, result, (uint64_t)(-(y.small >> 2L))); else mpz_sub_ui(result, result, (uint64_t)(y.small >> 2L)); } else { - mpz_sub(result, result, y.big); + mpz_sub(result, result, Int_mpz(y)); } return Int$from_mpz(result); } @@ -222,7 +231,7 @@ Int_t Int$slow_times(Int_t x, Int_t y) { mpz_t result; mpz_init_set_int(result, x); if (y.small & 1L) mpz_mul_si(result, result, y.small >> 2L); - else mpz_mul(result, result, y.big); + else mpz_mul(result, result, Int_mpz(y)); return Int$from_mpz(result); } @@ -235,7 +244,7 @@ Int_t Int$slow_divided_by(Int_t dividend, Int_t divisor) { mpz_init_set_int(remainder, divisor); mpz_tdiv_qr(quotient, remainder, quotient, remainder); if (mpz_sgn(remainder) < 0) { - bool d_positive = likely(divisor.small & 1L) ? divisor.small > 0x1L : mpz_sgn(divisor.big) > 0; + bool d_positive = likely(divisor.small & 1L) ? divisor.small > 0x1L : mpz_sgn(Int_mpz(divisor)) > 0; if (d_positive) mpz_sub_ui(quotient, quotient, 1); else mpz_add_ui(quotient, quotient, 1); } @@ -357,9 +366,9 @@ Int_t Int$gcd(Int_t x, Int_t y) { mpz_t result; mpz_init(result); - if (x.small & 0x1L) mpz_gcd_ui(result, y.big, (uint64_t)labs(x.small >> 2L)); - else if (y.small & 0x1L) mpz_gcd_ui(result, x.big, (uint64_t)labs(y.small >> 2L)); - else mpz_gcd(result, x.big, y.big); + if (x.small & 0x1L) mpz_gcd_ui(result, Int_mpz(y), (uint64_t)labs(x.small >> 2L)); + else if (y.small & 0x1L) mpz_gcd_ui(result, Int_mpz(x), (uint64_t)labs(y.small >> 2L)); + else mpz_gcd(result, Int_mpz(x), Int_mpz(y)); return Int$from_mpz(result); } @@ -535,18 +544,6 @@ Int_t Int$next_prime(Int_t x) { return Int$from_mpz(p); } -#if __GNU_MP_VERSION >= 6 -#if __GNU_MP_VERSION_MINOR >= 3 -public -OptionalInt_t Int$prev_prime(Int_t x) { - mpz_t p; - mpz_init_set_int(p, x); - if (unlikely(mpz_prevprime(p, p) == 0)) return NONE_INT; - return Int$from_mpz(p); -} -#endif -#endif - public Int_t Int$choose(Int_t n, Int_t k) { if unlikely (Int$compare_value(n, I_small(0)) < 0) fail("Negative inputs are not supported for choose()"); diff --git a/src/stdlib/bigint.h b/src/stdlib/bigint.h index 387d47f5..d5bad85f 100644 --- a/src/stdlib/bigint.h +++ b/src/stdlib/bigint.h @@ -1,6 +1,6 @@ // Big integer type (`Int` in Tomo) +#pragma once -#include #include #include @@ -10,6 +10,7 @@ Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *type); Text_t Int$value_as_text(Int_t i); +int Int$print(FILE *f, Int_t i); PUREFUNC uint64_t Int$hash(const void *x, const TypeInfo_t *type); PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *type); PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y); @@ -32,12 +33,6 @@ bool Int$get_bit(Int_t x, Int_t bit_index); #define BIGGEST_SMALL_INT 0x3fffffff #define SMALLEST_SMALL_INT -0x40000000 -#define mpz_init_set_int(mpz, i) \ - do { \ - if likely ((i).small & 1L) mpz_init_set_si(mpz, (i).small >> 2L); \ - else mpz_init_set(mpz, (i).big); \ - } while (0) - #define I_small(i) ((Int_t){.small = (int64_t)((uint64_t)(i) << 2L) | 1L}) #define I(i) _Generic(i, int8_t: I_small(i), int16_t: I_small(i), default: Int$from_int64(i)) #define I_is_zero(i) ((i).small == 1L) @@ -57,11 +52,6 @@ Int_t Int$slow_negative(Int_t x); Int_t Int$slow_negated(Int_t x); bool Int$is_prime(Int_t x, Int_t reps); Int_t Int$next_prime(Int_t x); -#if __GNU_MP_VERSION >= 6 -#if __GNU_MP_VERSION_MINOR >= 3 -OptionalInt_t Int$prev_prime(Int_t x); -#endif -#endif Int_t Int$choose(Int_t n, Int_t k); Int_t Int$factorial(Int_t n); diff --git a/src/stdlib/bytes.c b/src/stdlib/bytes.c index a1e953a0..23a7ced8 100644 --- a/src/stdlib/bytes.c +++ b/src/stdlib/bytes.c @@ -1,10 +1,11 @@ // The logic for unsigned bytes +#include #include #include +#include "../util.h" #include "bytes.h" #include "integers.h" -#include "stdlib.h" #include "text.h" #include "util.h" diff --git a/src/stdlib/c_strings.c b/src/stdlib/c_strings.c index cbe46b68..d581c220 100644 --- a/src/stdlib/c_strings.c +++ b/src/stdlib/c_strings.c @@ -7,6 +7,7 @@ #include #include +#include "fail.h" #include "integers.h" #include "siphash.h" #include "stdlib.h" @@ -60,7 +61,8 @@ static void CString$deserialize(FILE *in, void *out, List_t *pointers, const Typ int64_t len = -1; Int64$deserialize(in, &len, pointers, &Int64$info); char *str = GC_MALLOC_ATOMIC((size_t)len + 1); - if (fread(str, sizeof(char), (size_t)len, in) != (size_t)len) fail("Not enough data in stream to deserialize"); + if (fread(str, sizeof(char), (size_t)len, in) != (size_t)len) + fail_text(Text("Not enough data in stream to deserialize")); str[len + 1] = '\0'; *(const char **)out = str; } diff --git a/src/stdlib/cli.c b/src/stdlib/cli.c index e30f7ced..d424f316 100644 --- a/src/stdlib/cli.c +++ b/src/stdlib/cli.c @@ -11,6 +11,7 @@ #include #include "../config.h" +#include "../print.h" #include "bools.h" #include "bytes.h" #include "c_strings.h" @@ -20,7 +21,6 @@ #include "nums.h" #include "optionals.h" #include "paths.h" -#include "print.h" #include "stdlib.h" #include "tables.h" #include "text.h" diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index 3cd99f38..90a116e6 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -2,7 +2,6 @@ #pragma once -#include #include #include @@ -30,7 +29,7 @@ typedef union { int64_t small; - __mpz_struct *big; + void *big; } Int_t; #define OptionalInt_t Int_t diff --git a/src/stdlib/enums.c b/src/stdlib/enums.c index 9cc16c5d..a0aa55be 100644 --- a/src/stdlib/enums.c +++ b/src/stdlib/enums.c @@ -1,6 +1,7 @@ // Metamethods for enums #include +#include #include "integers.h" #include "metamethods.h" diff --git a/src/stdlib/fail.c b/src/stdlib/fail.c new file mode 100644 index 00000000..704624d3 --- /dev/null +++ b/src/stdlib/fail.c @@ -0,0 +1,38 @@ +// Failure functions +#include +#include +#include // IWYU pragma: export + +#include "../util.h" +#include "fail.h" +#include "files.h" +#include "stacktrace.h" +#include "stdlib.h" +#include "text.h" +#include "util.h" + +public +_Noreturn void fail_text(Text_t message) { fail(message); } + +public +Text_t builtin_last_err() { return Text$from_str(strerror(errno)); } + +_Noreturn void fail_source(const char *filename, int start, int end, Text_t message) { + tomo_cleanup(); + fflush(stdout); + if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); + else fputs("==================== ERROR ====================\n\n", stderr); + print_stacktrace(stderr, 1); + fputs("\n", stderr); + if (USE_COLOR) fputs("\x1b[31;1m", stderr); + Text$print(stderr, message); + file_t *_file = (filename) ? load_file(filename) : NULL; + if ((filename) && _file) { + fputs("\n", stderr); + highlight_error(_file, _file->text + (start), _file->text + (end), "\x1b[31;1m", 1, USE_COLOR); + } + if (USE_COLOR) fputs("\x1b[m", stderr); + fflush(stderr); + raise(SIGABRT); + exit(1); +} diff --git a/src/stdlib/fail.h b/src/stdlib/fail.h new file mode 100644 index 00000000..165b8db8 --- /dev/null +++ b/src/stdlib/fail.h @@ -0,0 +1,9 @@ +// Failure functions + +#pragma once + +#include "datatypes.h" + +_Noreturn void fail_text(Text_t message); +_Noreturn void fail_source(const char *filename, int start, int end, Text_t message); +Text_t builtin_last_err(); diff --git a/src/stdlib/files.c b/src/stdlib/files.c index 7d56fcfc..78c1bc94 100644 --- a/src/stdlib/files.c +++ b/src/stdlib/files.c @@ -12,8 +12,8 @@ #include #include +#include "../print.h" #include "files.h" -#include "print.h" #include "util.h" static const int tabstop = 4; diff --git a/src/stdlib/int64.c b/src/stdlib/int64.c index 754ac619..131d77ab 100644 --- a/src/stdlib/int64.c +++ b/src/stdlib/int64.c @@ -1,3 +1,19 @@ #define INTX_C_H__INT_BITS 64 #include "intX.c.h" #undef INTX_C_H__INT_BITS + +public +int Int64$print(FILE *f, int64_t n) { + char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0' + char *p = &buf[19]; + bool negative = n < 0; + + do { + *(p--) = '0' + (n % 10); + n /= 10; + } while (n > 0); + + if (negative) *(p--) = '-'; + + return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); +} diff --git a/src/stdlib/int64.h b/src/stdlib/int64.h index dc47fa95..99df60a8 100644 --- a/src/stdlib/int64.h +++ b/src/stdlib/int64.h @@ -2,3 +2,5 @@ #define I64(i) (int64_t)(i) #include "intX.h" // IWYU pragma: export #define NONE_INT64 ((OptionalInt64_t){.has_value = false}) + +int Int64$print(FILE *f, int64_t n); diff --git a/src/stdlib/intX.c.h b/src/stdlib/intX.c.h index 03322e5b..cba25bae 100644 --- a/src/stdlib/intX.c.h +++ b/src/stdlib/intX.c.h @@ -6,12 +6,15 @@ // #include +#include #include #include #include #include +#include "../util.h" #include "datatypes.h" +#include "fail.h" #include "integers.h" #include "text.h" #include "types.h" @@ -55,12 +58,12 @@ public void NAMESPACED(serialize)(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) { (void)info, (void)pointers; #if INTX_C_H__INT_BITS < 32 - if (fwrite(obj, sizeof(INT_T), 1, out) != sizeof(INT_T)) fail("Failed to write whole integer"); + if (fwrite(obj, sizeof(INT_T), 1, out) != sizeof(INT_T)) fail_text(Text("Failed to write whole integer")); #else INT_T i = *(INT_T *)obj; UINT_T z = (UINT_T)((i << 1L) ^ (i >> (INTX_C_H__INT_BITS - 1L))); // Zigzag encode while (z >= 0x80L) { - if (fputc((uint8_t)(z | 0x80L), out) == EOF) fail("Failed to write full integer"); + if (fputc((uint8_t)(z | 0x80L), out) == EOF) fail_text(Text("Failed to write full integer")); z >>= 7L; } fputc((uint8_t)z, out); @@ -71,12 +74,12 @@ public void NAMESPACED(deserialize)(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) { (void)info, (void)pointers; #if INTX_C_H__INT_BITS < 32 - if (fread(outval, sizeof(INT_T), 1, in) != sizeof(INT_T)) fail("Failed to read full integer"); + if (fread(outval, sizeof(INT_T), 1, in) != sizeof(INT_T)) fail_text(Text("Failed to read full integer")); #else UINT_T z = 0; for (size_t shift = 0;; shift += 7) { int i = fgetc(in); - if (i == EOF) fail("Failed to read whole integer"); + if (i == EOF) fail_text(Text("Failed to read whole integer")); uint8_t byte = (uint8_t)i; z |= ((UINT_T)(byte & 0x7F)) << shift; if ((byte & 0x80) == 0) break; @@ -202,6 +205,79 @@ PUREFUNC OPT_T NAMESPACED(parse)(Text_t text, OptionalInt_t base, Text_t *remain return (OPT_T){.has_value = true, .value = NAMESPACED(from_int)(full_int, true)}; } +public +PUREFUNC INT_T NAMESPACED(from_num64)(Num_t n, bool truncate) { + INT_T i = (INT_T)n; + if (!truncate && unlikely((Num_t)i != n)) + fail_text( + Text$concat(Text("Could not convert Num to an " NAME_STR " without truncation: "), Num$value_as_text(n))); + return i; +} + +public +PUREFUNC INT_T NAMESPACED(from_num32)(Num32_t n, bool truncate) { + INT_T i = (INT_T)n; + if (!truncate && unlikely((Num32_t)i != n)) + fail_text(Text$concat(Text("Could not convert Num32 to an " NAME_STR " without truncation: "), + Num32$value_as_text(n))); + return i; +} + +public +PUREFUNC INT_T NAMESPACED(from_int)(Int_t i, bool truncate) { + if likely (i.small & 1L) { + INT_T ret = i.small >> 2L; +#if INTX_C_H__INT_BITS < 32 + if (!truncate && unlikely((int64_t)ret != (i.small >> 2L))) + fail("Integer is too big to fit in an " NAME_STR ": ", i); +#endif + return ret; + } + if (!truncate && unlikely(!mpz_fits_slong_p(i.big))) fail("Integer is too big to fit in an " NAME_STR ": ", i); + return mpz_get_si(i.big); +} + +#if INTX_C_H__INT_BITS < 64 +public +PUREFUNC INT_T NAMESPACED(from_int64)(Int64_t i64, bool truncate) { + INT_T i = (INT_T)i64; + if (!truncate && unlikely((int64_t)i != i64)) fail("Integer is too big to fit in an " NAME_STR ": ", i64); + return i; +} +#elif INTX_C_H__INT_BITS > 64 +public +CONSTFUNC INT_T NAMESPACED(from_int64)(Int64_t i) { return (INT_T)i; } +#endif + +#if INTX_C_H__INT_BITS < 32 +public +PUREFUNC INT_T NAMESPACED(from_int32)(Int32_t i32, bool truncate) { + INT_T i = (INT_T)i32; + if (!truncate && unlikely((int32_t)i != i32)) fail("Integer is too big to fit in an " NAME_STR ": ", i32); + return i; +} +#elif INTX_C_H__INT_BITS > 32 +public +CONSTFUNC INT_T NAMESPACED(from_int32)(Int32_t i) { return (INT_T)i; } +#endif + +#if INTX_C_H__INT_BITS < 16 +public +PUREFUNC INT_T NAMESPACED(from_int16)(Int16_t i16, bool truncate) { + INT_T i = (INT_T)i16; + if (!truncate && unlikely((int16_t)i != i16)) fail("Integer is too big to fit in an " NAME_STR ": ", i16); + return i; +} +#elif INTX_C_H__INT_BITS > 16 +public +CONSTFUNC INT_T NAMESPACED(from_int16)(Int16_t i) { return (INT_T)i; } +#endif + +#if INTX_C_H__INT_BITS > 8 +public +CONSTFUNC INT_T NAMESPACED(from_int8)(Int8_t i) { return (INT_T)i; } +#endif + public CONSTFUNC INT_T NAMESPACED(gcd)(INT_T x, INT_T y) { if (x == 0 || y == 0) return 0; diff --git a/src/stdlib/intX.h b/src/stdlib/intX.h index 1c8b4a05..e9ecbfa1 100644 --- a/src/stdlib/intX.h +++ b/src/stdlib/intX.h @@ -6,9 +6,9 @@ // #include #include +#include #include "datatypes.h" -#include "stdlib.h" #include "types.h" #include "util.h" @@ -88,64 +88,30 @@ MACROLIKE PUREFUNC INTX_T NAMESPACED(unsigned_right_shifted)(INTX_T x, INTX_T y) void NAMESPACED(serialize)(const void *obj, FILE *out, Table_t *, const TypeInfo_t *); void NAMESPACED(deserialize)(FILE *in, void *outval, List_t *, const TypeInfo_t *); -MACROLIKE PUREFUNC INTX_T NAMESPACED(from_num64)(Num_t n, bool truncate) { - INTX_T i = (INTX_T)n; - if (!truncate && unlikely((Num_t)i != n)) fail("Could not convert Num to an " NAME_STR " without truncation: ", n); - return i; -} - -MACROLIKE PUREFUNC INTX_T NAMESPACED(from_num32)(Num32_t n, bool truncate) { - INTX_T i = (INTX_T)n; - if (!truncate && unlikely((Num32_t)i != n)) - fail("Could not convert Num32 to an " NAME_STR " without truncation: ", n); - return i; -} - -MACROLIKE PUREFUNC INTX_T NAMESPACED(from_int)(Int_t i, bool truncate) { - if likely (i.small & 1L) { - INTX_T ret = i.small >> 2L; -#if INTX_H__INT_BITS < 32 - if (!truncate && unlikely((int64_t)ret != (i.small >> 2L))) - fail("Integer is too big to fit in an " NAME_STR ": ", i); -#endif - return ret; - } - if (!truncate && unlikely(!mpz_fits_slong_p(i.big))) fail("Integer is too big to fit in an " NAME_STR ": ", i); - return mpz_get_si(i.big); -} +PUREFUNC INTX_T NAMESPACED(from_num64)(Num_t n, bool truncate); +PUREFUNC INTX_T NAMESPACED(from_num32)(Num32_t n, bool truncate); +PUREFUNC INTX_T NAMESPACED(from_int)(Int_t i, bool truncate); #if INTX_H__INT_BITS < 64 -MACROLIKE PUREFUNC INTX_T NAMESPACED(from_int64)(Int64_t i64, bool truncate) { - INTX_T i = (INTX_T)i64; - if (!truncate && unlikely((int64_t)i != i64)) fail("Integer is too big to fit in an " NAME_STR ": ", i64); - return i; -} +PUREFUNC INTX_T NAMESPACED(from_int64)(Int64_t i64, bool truncate); #elif INTX_H__INT_BITS > 64 -MACROLIKE CONSTFUNC INTX_T NAMESPACED(from_int64)(Int64_t i) { return (INTX_T)i; } +CONSTFUNC INTX_T NAMESPACED(from_int64)(Int64_t i); #endif #if INTX_H__INT_BITS < 32 -MACROLIKE PUREFUNC INTX_T NAMESPACED(from_int32)(Int32_t i32, bool truncate) { - INTX_T i = (INTX_T)i32; - if (!truncate && unlikely((int32_t)i != i32)) fail("Integer is too big to fit in an " NAME_STR ": ", i32); - return i; -} +PUREFUNC INTX_T NAMESPACED(from_int32)(Int32_t i32, bool truncate); #elif INTX_H__INT_BITS > 32 -MACROLIKE CONSTFUNC INTX_T NAMESPACED(from_int32)(Int32_t i) { return (INTX_T)i; } +CONSTFUNC INTX_T NAMESPACED(from_int32)(Int32_t i); #endif #if INTX_H__INT_BITS < 16 -MACROLIKE PUREFUNC INTX_T NAMESPACED(from_int16)(Int16_t i16, bool truncate) { - INTX_T i = (INTX_T)i16; - if (!truncate && unlikely((int16_t)i != i16)) fail("Integer is too big to fit in an " NAME_STR ": ", i16); - return i; -} +PUREFUNC INTX_T NAMESPACED(from_int16)(Int16_t i16, bool truncate); #elif INTX_H__INT_BITS > 16 -MACROLIKE CONSTFUNC INTX_T NAMESPACED(from_int16)(Int16_t i) { return (INTX_T)i; } +CONSTFUNC INTX_T NAMESPACED(from_int16)(Int16_t i); #endif #if INTX_H__INT_BITS > 8 -MACROLIKE CONSTFUNC INTX_T NAMESPACED(from_int8)(Int8_t i) { return (INTX_T)i; } +CONSTFUNC INTX_T NAMESPACED(from_int8)(Int8_t i); #endif #undef PASTE3_ diff --git a/src/stdlib/lists.c b/src/stdlib/lists.c index 80c407da..3149cf82 100644 --- a/src/stdlib/lists.c +++ b/src/stdlib/lists.c @@ -6,6 +6,7 @@ #include #include +#include "../util.h" #include "integers.h" #include "lists.h" #include "math.h" diff --git a/src/stdlib/memory.c b/src/stdlib/memory.c index 53a180fb..fa92da3e 100644 --- a/src/stdlib/memory.c +++ b/src/stdlib/memory.c @@ -6,9 +6,9 @@ #include #include +#include "../print.h" #include "memory.h" #include "metamethods.h" -#include "print.h" #include "text.h" #include "types.h" #include "util.h" diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c index 70b8e4e1..b3fd233a 100644 --- a/src/stdlib/metamethods.c +++ b/src/stdlib/metamethods.c @@ -1,12 +1,15 @@ // Metamethods are methods that all types share for hashing, equality, comparison, and textifying +#include #include #include +#include "fail.h" #include "lists.h" #include "metamethods.h" #include "siphash.h" #include "tables.h" +#include "text.h" #include "types.h" #include "util.h" @@ -34,7 +37,7 @@ PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_ public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type) { - if (!type->metamethods.as_text) fail("No text metamethod provided for type!"); + if (!type->metamethods.as_text) fail_text(Text("No text metamethod provided for type!")); return type->metamethods.as_text(obj, colorize, type); } @@ -72,7 +75,7 @@ void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t return; } - if (fread(outval, (size_t)type->size, 1, input) != 1) fail("Not enough data in stream to deserialize"); + if (fread(outval, (size_t)type->size, 1, input) != 1) fail_text(Text("Not enough data in stream to deserialize")); } public @@ -88,13 +91,13 @@ void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type) { __attribute__((noreturn)) public void cannot_serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { (void)obj, (void)out, (void)pointers; - Text_t typestr = generic_as_text(NULL, false, type); - fail("Values of type ", typestr, " cannot be serialized or deserialized!"); + Text_t type_text = generic_as_text(NULL, false, type); + fail_text(Text$concat(Text("Values of type "), type_text, Text(" cannot be serialized or deserialized!"))); } __attribute__((noreturn)) public void cannot_deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) { (void)obj, (void)in, (void)pointers; - Text_t typestr = generic_as_text(NULL, false, type); - fail("Values of type ", typestr, " cannot be serialized or deserialized!"); + Text_t type_text = generic_as_text(NULL, false, type); + fail_text(Text$concat(Text("Values of type "), type_text, Text(" cannot be serialized or deserialized!"))); } diff --git a/src/stdlib/numX.c.h b/src/stdlib/numX.c.h index 2fde8c45..a8ab0de8 100644 --- a/src/stdlib/numX.c.h +++ b/src/stdlib/numX.c.h @@ -6,11 +6,13 @@ // #include #include +#include #include #include #include #include +#include "fail.h" #include "text.h" #include "types.h" @@ -89,6 +91,42 @@ PUREFUNC int32_t NAMESPACED(compare)(const void *x, const void *y, const TypeInf } #endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif +public +CONSTFUNC NUM_T NAMESPACED(from_int)(Int_t i, bool truncate) { + if likely (i.small & 0x1) { + NUM_T ret = (NUM_T)(i.small >> 2); + if unlikely (!truncate && (int64_t)ret != (i.small >> 2)) + fail_text(Text$concat(Text("Could not convert integer to " TYPE_STR " without losing precision: "), + Int64$value_as_text(i.small >> 2))); + return ret; + } else { + NUM_T ret = mpz_get_d(i.big); + if (!truncate) { + mpz_t roundtrip; + mpz_init_set_d(roundtrip, (double)ret); + if unlikely (mpz_cmp(i.big, roundtrip) != 0) + fail_text(Text$concat(Text("Could not convert integer to " TYPE_STR " without losing precision: "), + Int$value_as_text(i))); + } + return ret; + } +} +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +public +CONSTFUNC NUM_T NAMESPACED(from_int64)(Int64_t i, bool truncate) { + NUM_T n = (NUM_T)i; + if unlikely (!truncate && (Int64_t)n != i) + fail_text(Text$concat(Text("Could not convert integer to " TYPE_STR " without losing precision: "), + Int64$value_as_text(i))); + return n; +} + public PUREFUNC bool NAMESPACED(equal)(const void *x, const void *y, const TypeInfo_t *info) { (void)info; diff --git a/src/stdlib/numX.h b/src/stdlib/numX.h index 3d65cb59..210c4cc7 100644 --- a/src/stdlib/numX.h +++ b/src/stdlib/numX.h @@ -9,7 +9,6 @@ #include #include "datatypes.h" -#include "stdlib.h" #include "types.h" #include "util.h" @@ -58,36 +57,8 @@ MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_num32)(float n) { return (NUM_T)n; } MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_num64)(double n) { return (NUM_T)n; } #endif -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif -MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_int)(Int_t i, bool truncate) { - if likely (i.small & 0x1) { - NUM_T ret = (NUM_T)(i.small >> 2); - if unlikely (!truncate && (int64_t)ret != (i.small >> 2)) - fail("Could not convert integer to " TYPE_STR " without losing precision: ", i.small >> 2); - return ret; - } else { - NUM_T ret = mpz_get_d(i.big); - if (!truncate) { - mpz_t roundtrip; - mpz_init_set_d(roundtrip, (double)ret); - if unlikely (mpz_cmp(i.big, roundtrip) != 0) - fail("Could not convert integer to " TYPE_STR " without losing precision: ", i); - } - return ret; - } -} -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_int64)(Int64_t i, bool truncate) { - NUM_T n = (NUM_T)i; - if unlikely (!truncate && (Int64_t)n != i) - fail("Could not convert integer to " TYPE_STR " without losing precision: ", i); - return n; -} +CONSTFUNC NUM_T NAMESPACED(from_int)(Int_t i, bool truncate); +CONSTFUNC NUM_T NAMESPACED(from_int64)(Int64_t i, bool truncate); MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_int32)(Int32_t i) { return (NUM_T)i; } MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_int16)(Int16_t i) { return (NUM_T)i; } MACROLIKE CONSTFUNC NUM_T NAMESPACED(from_int8)(Int8_t i) { return (NUM_T)i; } diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c index 0198fda8..678e143a 100644 --- a/src/stdlib/paths.c +++ b/src/stdlib/paths.c @@ -17,6 +17,7 @@ #include #include +#include "../print.h" #include "../unistr-fixed.h" #include "../util.h" #include "enums.h" @@ -24,7 +25,6 @@ #include "lists.h" #include "optionals.h" #include "paths.h" -#include "print.h" #include "structs.h" #include "text.h" #include "types.h" diff --git a/src/stdlib/paths.h b/src/stdlib/paths.h index c272314c..a9d49a34 100644 --- a/src/stdlib/paths.h +++ b/src/stdlib/paths.h @@ -11,8 +11,7 @@ Path_t Path$from_str(const char *str); Path_t Path$from_text(Text_t text); -// This function is defined as an extern in `src/stdlib/print.h` -// int Path$print(FILE *f, Path_t path); +int Path$print(FILE *f, Path_t path); // UNSAFE: this works because each type of path has a .components in the same place #define Path$components(path) ((path).components) // END UNSAFE diff --git a/src/stdlib/print.c b/src/stdlib/print.c deleted file mode 100644 index 7da1343f..00000000 --- a/src/stdlib/print.c +++ /dev/null @@ -1,251 +0,0 @@ -// This file defines some of the helper functions used for printing values - -#include -#include -#include -#include - -#include "fpconv.h" -#include "print.h" -#include "util.h" - -public -int _print_int(FILE *f, int64_t n) { - char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0' - char *p = &buf[19]; - bool negative = n < 0; - - do { - *(p--) = '0' + (n % 10); - n /= 10; - } while (n > 0); - - if (negative) *(p--) = '-'; - - return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); -} - -public -int _print_uint(FILE *f, uint64_t n) { - char buf[21] = {[20] = 0}; // Big enough for UINT64_MAX + '\0' - char *p = &buf[19]; - - do { - *(p--) = '0' + (n % 10); - n /= 10; - } while (n > 0); - - return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); -} - -public -int _print_hex(FILE *f, hex_format_t hex) { - int printed = 0; - if (!hex.no_prefix) printed += fputs("0x", f); - if (hex.digits > 0) { - hex.digits -= (hex.n == 0); // Don't need a leading zero for a zero - for (uint64_t n = hex.n; n > 0 && hex.digits > 0; n /= 16) { - hex.digits -= 1; - } - for (; hex.digits > 0; hex.digits -= 1) { - printed += fputc('0', f); - } - } - char buf[9] = {[8] = '\0'}; // Enough space for FFFFFFFF + '\0' - char *p = &buf[7]; - do { - uint8_t digit = hex.n % 16; - if (digit <= 9) *(p--) = '0' + digit; - else if (hex.uppercase) *(p--) = 'A' + digit - 10; - else *(p--) = 'a' + digit - 10; - hex.n /= 16; - } while (hex.n > 0); - printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[7] - p), f); - return printed; -} - -public -int _print_oct(FILE *f, oct_format_t oct) { - int printed = 0; - if (!oct.no_prefix) printed += fputs("0o", f); - if (oct.digits > 0) { - oct.digits -= (oct.n == 0); // Don't need a leading zero for a zero - for (uint64_t n = oct.n; n > 0 && oct.digits > 0; n /= 8) - oct.digits -= 1; - for (; oct.digits > 0; oct.digits -= 1) - printed += fputc('0', f); - } - char buf[12] = {[11] = '\0'}; // Enough space for octal UINT64_MAX + '\0' - char *p = &buf[10]; - do { - *(p--) = '0' + (oct.n % 8); - oct.n /= 8; - } while (oct.n > 0); - printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[10] - p), f); - return printed; -} - -public -int _print_double(FILE *f, double n) { - static char buf[24]; - int len = fpconv_dtoa(n, buf); - return (int)fwrite(buf, sizeof(char), (size_t)len, f); -} - -public -int _print_hex_double(FILE *f, hex_double_t hex) { - if (hex.d != hex.d) return fputs("NAN", f); - else if (hex.d == 1.0 / 0.0) return fputs("INF", f); - else if (hex.d == -1.0 / 0.0) return fputs("-INF", f); - else if (hex.d == 0.0) return fputs("0.0", f); - - union { - double d; - uint64_t u; - } bits = {.d = hex.d}; - - int sign = (bits.u >> 63) & 1ull; - int exp = (int)((bits.u >> 52) & 0x7FF) - 1023ull; - uint64_t frac = bits.u & 0xFFFFFFFFFFFFFull; - - char buf[25]; - char *p = buf; - - if (sign) *p++ = '-'; - *p++ = '0'; - *p++ = 'x'; - - uint64_t mantissa = (1ull << 52) | frac; // implicit 1 - int mantissa_shift = 52; - - while ((mantissa & 0xF) == 0 && mantissa_shift > 0) { - mantissa >>= 4; - mantissa_shift -= 4; - } - - uint64_t int_part = mantissa >> mantissa_shift; - *p++ = "0123456789abcdef"[int_part]; - - *p++ = '.'; - - while (mantissa_shift > 0) { - mantissa_shift -= 4; - uint64_t digit = (mantissa >> mantissa_shift) & 0xF; - *p++ = "0123456789abcdef"[digit]; - } - - *p++ = 'p'; - - if (exp >= 0) { - *p++ = '+'; - } else { - *p++ = '-'; - exp = -exp; - } - - char expbuf[6]; - int ei = 5; - expbuf[ei--] = '\0'; - do { - expbuf[ei--] = '0' + (exp % 10); - exp /= 10; - } while (exp && ei >= 0); - - ei++; - while (expbuf[ei]) - *p++ = expbuf[ei++]; - - *p = '\0'; - return fwrite(buf, sizeof(char), (size_t)(p - buf), f); -} - -public -int _print_char(FILE *f, char c) { -#define ESC(e) "'\\" e "'" - const char *named[256] = { - ['\''] = ESC("'"), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"), - ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")}; - const char *name = named[(uint8_t)c]; - if (name != NULL) return fputs(name, f); - else if (isprint(c)) return fputc('\'', f) + fputc(c, f) + fputc('\'', f); - else - return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits = 2, .no_prefix = true, .uppercase = true)) - + fputs("'", f)); -#undef ESC -} - -public -int _print_quoted(FILE *f, quoted_t quoted) { -#define ESC(e) "\\" e - const char *named[256] = { - ['"'] = ESC("\""), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"), - ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")}; - int printed = fputc('"', f); - for (const char *p = quoted.str; *p; p++) { - const char *name = named[(uint8_t)*p]; - if (name != NULL) { - printed += fputs(name, f); - } else if (isprint(*p) || (uint8_t)*p > 0x7F) { - printed += fputc(*p, f); - } else { - printed += - fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits = 2, .no_prefix = true, .uppercase = true)); - } - } - printed += fputc('"', f); -#undef ESC - return printed; -} - -#if defined(__GLIBC__) && defined(_GNU_SOURCE) -// GLIBC has fopencookie() -static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) { - gc_stream_t *stream = (gc_stream_t *)cookie; - if (stream->position + size + 1 > *stream->size) - *stream->buffer = - GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL))); - memcpy(&(*stream->buffer)[stream->position], buf, size); - stream->position += size; - (*stream->buffer)[stream->position] = '\0'; - return (ssize_t)size; -} - -public -FILE *gc_memory_stream(char **buf, size_t *size) { - gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); - stream->size = size; - stream->buffer = buf; - *stream->size = 16; - *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); - (*stream->buffer)[0] = '\0'; - stream->position = 0; - cookie_io_functions_t functions = {.write = _gc_stream_write}; - return fopencookie(stream, "w", functions); -} -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -// BSDs have funopen() and fwopen() -static int _gc_stream_write(void *cookie, const char *buf, int size) { - gc_stream_t *stream = (gc_stream_t *)cookie; - if (stream->position + size + 1 > *stream->size) - *stream->buffer = - GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL))); - memcpy(&(*stream->buffer)[stream->position], buf, size); - stream->position += size; - (*stream->buffer)[stream->position] = '\0'; - return size; -} - -public -FILE *gc_memory_stream(char **buf, size_t *size) { - gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t)); - stream->size = size; - stream->buffer = buf; - *stream->size = 16; - *stream->buffer = GC_MALLOC_ATOMIC(*stream->size); - (*stream->buffer)[0] = '\0'; - stream->position = 0; - return fwopen(stream, _gc_stream_write); -} -#else -#error "This platform doesn't support fopencookie() or funopen()!" -#endif diff --git a/src/stdlib/print.h b/src/stdlib/print.h deleted file mode 100644 index 7106d561..00000000 --- a/src/stdlib/print.h +++ /dev/null @@ -1,165 +0,0 @@ -// This file defines some functions to make it easy to do formatted text -// without using printf style specifiers: -// -// print(...) - print text -// fprint(file, ...) - print text to file -// print_err(...) - print an error message and exit with EXIT_FAILURE -// String(...) - return an allocated string - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "datatypes.h" -#include "mapmacro.h" - -// GCC lets you define macro-like functions which are always inlined and never -// compiled using this combination of flags. See: https://gcc.gnu.org/onlinedocs/gcc/Inline.html -#ifndef PRINT_FN -#ifdef __TINYC__ -#define PRINT_FN static inline __attribute__((gnu_inline, always_inline)) int -#else -#define PRINT_FN extern inline __attribute__((gnu_inline, always_inline)) int -#endif -#endif - -typedef struct { - uint64_t n; - bool no_prefix; - bool uppercase; - int digits; -} hex_format_t; -#define hex(x, ...) ((hex_format_t){.n = x, __VA_ARGS__}) - -typedef struct { - double d; -} hex_double_t; -#define hex_double(x, ...) ((hex_double_t){.d = x, __VA_ARGS__}) - -typedef struct { - uint64_t n; - bool no_prefix; - int digits; -} oct_format_t; -#define oct(x, ...) ((oct_format_t){.n = x, __VA_ARGS__}) - -typedef struct { - const char *str; -} quoted_t; -#define quoted(s) ((quoted_t){s}) - -typedef struct { - const char *str; - size_t length; -} string_slice_t; -#define string_slice(...) ((string_slice_t){__VA_ARGS__}) - -typedef struct { - char c; - int length; -} repeated_char_t; -#define repeated_char(ch, len) ((repeated_char_t){.c = ch, .length = len}) - -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#define FMT64 "ll" -#else -#define FMT64 "l" -#endif - -int _print_int(FILE *f, int64_t x); -int _print_uint(FILE *f, uint64_t x); -int _print_double(FILE *f, double x); -int _print_hex(FILE *f, hex_format_t hex); -int _print_hex_double(FILE *f, hex_double_t hex); -int _print_oct(FILE *f, oct_format_t oct); -PRINT_FN _print_float(FILE *f, float x) { return _print_double(f, (double)x); } -PRINT_FN _print_pointer(FILE *f, void *p) { return _print_hex(f, hex((uint64_t)p)); } -PRINT_FN _print_bool(FILE *f, bool b) { return fputs(b ? "yes" : "no", f); } -PRINT_FN _print_str(FILE *f, const char *s) { return fputs(s ? s : "(null)", f); } -int _print_char(FILE *f, char c); -int _print_quoted(FILE *f, quoted_t quoted); -PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) { - return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f); -} -PRINT_FN _print_repeated_char(FILE *f, repeated_char_t repeated) { - int len = 0; - for (int n = 0; n < repeated.length; n++) - len += fputc(repeated.c, f); - return len; -} - -extern int Text$print(FILE *stream, Text_t text); -extern int Path$print(FILE *stream, Path_t path); -extern int Int$print(FILE *f, Int_t i); -#ifndef _fprint1 -#define _fprint1(f, x) \ - _Generic((x), \ - char *: _print_str, \ - const char *: _print_str, \ - char: _print_char, \ - bool: _print_bool, \ - int64_t: _print_int, \ - int32_t: _print_int, \ - int16_t: _print_int, \ - int8_t: _print_int, \ - uint64_t: _print_uint, \ - uint32_t: _print_uint, \ - uint16_t: _print_uint, \ - uint8_t: _print_uint, \ - float: _print_float, \ - double: _print_double, \ - hex_format_t: _print_hex, \ - hex_double_t: _print_hex_double, \ - oct_format_t: _print_oct, \ - quoted_t: _print_quoted, \ - string_slice_t: _print_string_slice, \ - repeated_char_t: _print_repeated_char, \ - Text_t: Text$print, \ - Path_t: Path$print, \ - Int_t: Int$print, \ - void *: _print_pointer)(f, x) -#endif - -typedef struct { - char **buffer; - size_t *size; - size_t position; -} gc_stream_t; - -FILE *gc_memory_stream(char **buf, size_t *size); - -#define _print(x) _n += _fprint1(_printing, x) -#define _fprint(f, ...) \ - ({ \ - FILE *_printing = f; \ - int _n = 0; \ - MAP_LIST(_print, __VA_ARGS__); \ - _n; \ - }) -#define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n") -#define print(...) fprint(stdout, __VA_ARGS__) -#define fprint_inline(f, ...) _fprint(f, __VA_ARGS__) -#define print_inline(...) fprint_inline(stdout, __VA_ARGS__) -#define String(...) \ - ({ \ - char *_buf = NULL; \ - size_t _size = 0; \ - FILE *_stream = gc_memory_stream(&_buf, &_size); \ - assert(_stream); \ - _fprint(_stream, __VA_ARGS__); \ - fflush(_stream); \ - _buf; \ - }) -#define print_err(...) \ - ({ \ - fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); \ - exit(EXIT_FAILURE); \ - }) diff --git a/src/stdlib/stacktrace.c b/src/stdlib/stacktrace.c index 1eba8188..7bc42755 100644 --- a/src/stdlib/stacktrace.c +++ b/src/stdlib/stacktrace.c @@ -15,7 +15,7 @@ #include #include "../config.h" -#include "print.h" +#include "../print.h" #include "simpleparse.h" #include "util.h" diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c index 7ed18af1..b156692c 100644 --- a/src/stdlib/stdlib.c +++ b/src/stdlib/stdlib.c @@ -14,11 +14,12 @@ #include #include "../config.h" +#include "../print.h" +#include "../util.h" #include "files.h" #include "metamethods.h" #include "optionals.h" #include "paths.h" -#include "print.h" #include "siphash.h" #include "stacktrace.h" #include "stdlib.h" @@ -158,12 +159,6 @@ void tomo_init(void) { atexit(tomo_cleanup); } -public -_Noreturn void fail_text(Text_t message) { fail(message); } - -public -Text_t builtin_last_err() { return Text$from_str(strerror(errno)); } - static int _inspect_depth = 0; static file_t *file = NULL; diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h index 087ed4bf..134f8ffa 100644 --- a/src/stdlib/stdlib.h +++ b/src/stdlib/stdlib.h @@ -2,14 +2,10 @@ #pragma once -#include #include #include -#include // IWYU pragma: export #include "datatypes.h" -#include "print.h" -#include "stacktrace.h" // IWYU pragma: export #include "types.h" extern bool USE_COLOR; @@ -20,46 +16,6 @@ void tomo_init(void); void tomo_at_cleanup(Closure_t fn); void tomo_cleanup(void); -#define fail(...) \ - ({ \ - tomo_cleanup(); \ - fflush(stdout); \ - if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \033[m\n\n", stderr); \ - else fputs("==================== ERROR ====================\n\n", stderr); \ - print_stacktrace(stderr, 1); \ - if (USE_COLOR) fputs("\n\x1b[31;1m", stderr); \ - else fputs("\n", stderr); \ - fprint_inline(stderr, "Error: ", __VA_ARGS__); \ - if (USE_COLOR) fputs("\x1b[m\n", stderr); \ - else fputs("\n", stderr); \ - fflush(stderr); \ - raise(SIGABRT); \ - exit(1); \ - }) - -#define fail_source(filename, start, end, message) \ - ({ \ - tomo_cleanup(); \ - fflush(stdout); \ - if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \ - else fputs("==================== ERROR ====================\n\n", stderr); \ - print_stacktrace(stderr, 0); \ - fputs("\n", stderr); \ - if (USE_COLOR) fputs("\x1b[31;1m", stderr); \ - Text$print(stderr, message); \ - file_t *_file = (filename) ? load_file(filename) : NULL; \ - if ((filename) && _file) { \ - fputs("\n", stderr); \ - highlight_error(_file, _file->text + (start), _file->text + (end), "\x1b[31;1m", 1, USE_COLOR); \ - } \ - if (USE_COLOR) fputs("\x1b[m", stderr); \ - fflush(stderr); \ - raise(SIGABRT); \ - exit(1); \ - }) - -_Noreturn void fail_text(Text_t message); -Text_t builtin_last_err(); __attribute__((nonnull)) void start_inspect(const char *filename, int64_t start, int64_t end); void end_inspect(const void *expr, const TypeInfo_t *type); #define inspect(type, expr, typeinfo, start, end) \ diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index d417545d..d4a51276 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -13,6 +13,7 @@ #include "c_strings.h" #include "datatypes.h" +#include "fail.h" #include "lists.h" #include "memory.h" #include "metamethods.h" @@ -146,7 +147,7 @@ static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const TypeInfo_t *type) { if (unlikely(new_capacity > TABLE_MAX_BUCKETS)) - fail("Table has exceeded the maximum table size (2^31) and cannot grow further!"); + fail_text(Text("Table has exceeded the maximum table size (2^31) and cannot grow further!")); size_t alloc_size = sizeof(bucket_info_t) + sizeof(bucket_t[new_capacity]); t->bucket_info = GC_MALLOC_ATOMIC(alloc_size); memset(t->bucket_info->buckets, 0, sizeof(bucket_t[new_capacity])); diff --git a/src/stdlib/text.h b/src/stdlib/text.h index 08423cfe..d3ed032b 100644 --- a/src/stdlib/text.h +++ b/src/stdlib/text.h @@ -51,8 +51,7 @@ static inline Text_t Text_from_text(Text_t t) { return 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__}) #define Texts(...) Text$concat(MAP_LIST(convert_to_text, __VA_ARGS__)) -// This function is defined as an extern in `src/stdlib/print.h` -// int Text$print(FILE *stream, Text_t t); +int Text$print(FILE *stream, Text_t t); Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int); Text_t Text$from(Text_t text, Int_t first); Text_t Text$to(Text_t text, Int_t last); diff --git a/src/stdlib/tomo.h b/src/stdlib/tomo.h index ff8f90a2..fce9cdb5 100644 --- a/src/stdlib/tomo.h +++ b/src/stdlib/tomo.h @@ -14,6 +14,7 @@ #include "cli.h" // IWYU pragma: export #include "datatypes.h" // IWYU pragma: export #include "enums.h" // IWYU pragma: export +#include "fail.h" // IWYU pragma: export #include "files.h" // IWYU pragma: export #include "functiontype.h" // IWYU pragma: export #include "integers.h" // IWYU pragma: export @@ -24,10 +25,10 @@ #include "optionals.h" // IWYU pragma: export #include "paths.h" // IWYU pragma: export #include "pointers.h" // IWYU pragma: export -#include "print.h" // IWYU pragma: export #include "result.h" // IWYU pragma: export #include "siphash.h" // IWYU pragma: export #include "stacktrace.h" // IWYU pragma: export +#include "stdlib.h" // IWYU pragma: export #include "structs.h" // IWYU pragma: export #include "tables.h" // IWYU pragma: export #include "text.h" // IWYU pragma: export diff --git a/src/tomo.c b/src/tomo.c index 4a886bfc..f5027fff 100644 --- a/src/tomo.c +++ b/src/tomo.c @@ -22,6 +22,7 @@ #include "modules.h" #include "naming.h" #include "parse/files.h" +#include "print.h" #include "stdlib/bools.h" #include "stdlib/bytes.h" #include "stdlib/c_strings.h" @@ -31,7 +32,6 @@ #include "stdlib/lists.h" #include "stdlib/optionals.h" #include "stdlib/paths.h" -#include "stdlib/print.h" #include "stdlib/random.h" #include "stdlib/siphash.h" #include "stdlib/tables.h" diff --git a/src/util.h b/src/util.h index 53b10a83..05b9abe9 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,29 @@ #pragma once #include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include "./stdlib/stacktrace.h" // IWYU pragma: export #include "./stdlib/util.h" // IWYU pragma: export +#include "print.h" // IWYU pragma: export +#include "stdlib/stdlib.h" // IWYU pragma: export #define new(t, ...) ((t *)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t))) + +#define fail(...) \ + ({ \ + tomo_cleanup(); \ + fflush(stdout); \ + if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \033[m\n\n", stderr); \ + else fputs("==================== ERROR ====================\n\n", stderr); \ + print_stacktrace(stderr, 1); \ + if (USE_COLOR) fputs("\n\x1b[31;1m", stderr); \ + else fputs("\n", stderr); \ + fprint_inline(stderr, "Error: ", __VA_ARGS__); \ + if (USE_COLOR) fputs("\x1b[m\n", stderr); \ + else fputs("\n", stderr); \ + fflush(stderr); \ + raise(SIGABRT); \ + exit(1); \ + }) -- cgit v1.2.3