From a33f73061776d6814f67fecd230c0706bc1ff10c Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 10 Mar 2024 00:03:21 -0500 Subject: Rearranging some files --- Makefile | 12 +- ast.h | 4 +- builtins/array.c | 4 +- builtins/array.h | 2 +- builtins/bool.c | 4 +- builtins/color.c | 2 +- builtins/files.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++++ builtins/files.h | 42 +++++++ builtins/functions.c | 12 +- builtins/halfsiphash.h | 22 ++++ builtins/integers.c | 2 +- builtins/macros.h | 31 +++++ builtins/memory.c | 4 +- builtins/nums.c | 4 +- builtins/pointer.c | 8 +- builtins/table.c | 6 +- builtins/text.c | 2 +- builtins/tomo.h | 50 ++++++++ builtins/types.c | 8 +- builtins/util.c | 84 +++++++++++++ builtins/util.h | 59 +++++++++ compile.c | 4 +- compile.h | 2 +- enums.c | 2 +- environment.c | 2 +- files.c | 320 ------------------------------------------------- files.h | 42 ------- parse.c | 2 +- structs.c | 2 +- tomo.h | 51 -------- typecheck.c | 2 +- types.c | 2 +- util.c | 84 ------------- util.h | 59 --------- 34 files changed, 654 insertions(+), 602 deletions(-) create mode 100644 builtins/files.c create mode 100644 builtins/files.h create mode 100644 builtins/halfsiphash.h create mode 100644 builtins/macros.h create mode 100644 builtins/tomo.h create mode 100644 builtins/util.c create mode 100644 builtins/util.h delete mode 100644 files.c delete mode 100644 files.h delete mode 100644 tomo.h delete mode 100644 util.c delete mode 100644 util.h diff --git a/Makefile b/Makefile index 671e17b3..a5b7d11f 100644 --- a/Makefile +++ b/Makefile @@ -25,13 +25,13 @@ O=-Og CFLAGS=$(CCONFIG) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) LDLIBS=-lgc -lcord -lm -lunistring BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/color.o builtins/nums.o builtins/functions.o builtins/integers.o \ - builtins/pointer.o builtins/memory.o builtins/text.o builtins/table.o builtins/types.o + builtins/pointer.o builtins/memory.o builtins/text.o builtins/table.o builtins/types.o builtins/util.o builtins/files.o all: libtomo.so tomo -tomo: tomo.c SipHash/halfsiphash.o util.o files.o ast.o parse.o environment.o types.o typecheck.o structs.o enums.o compile.o $(BUILTIN_OBJS) +tomo: tomo.c SipHash/halfsiphash.o ast.o parse.o environment.o types.o typecheck.o structs.o enums.o compile.o $(BUILTIN_OBJS) -libtomo.so: util.o files.o $(BUILTIN_OBJS) SipHash/halfsiphash.o +libtomo.so: $(BUILTIN_OBJS) SipHash/halfsiphash.o $(CC) $^ $(CFLAGS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) $(LDLIBS) -Wl,-soname,libtomo.so -shared -o $@ SipHash/halfsiphash.c: @@ -50,13 +50,13 @@ clean: pandoc --lua-filter=.pandoc/bold-code.lua -s $< -t man -o $@ install: tomo libtomo.so - mkdir -p -m 755 "$(PREFIX)/man/man1" "$(PREFIX)/bin" "$(PREFIX)/lib" "$(PREFIX)/share/tomo/modules" - cp -v tomo.h "$(PREFIX)/include/" + mkdir -p -m 755 "$(PREFIX)/man/man1" "$(PREFIX)/bin" "$(PREFIX)/include/tomo" "$(PREFIX)/lib" "$(PREFIX)/share/tomo/modules" + cp -v builtins/*.h "$(PREFIX)/include/tomo/" cp -v libtomo.so "$(PREFIX)/lib/" rm -f "$(PREFIX)/bin/tomo" cp -v tomo "$(PREFIX)/bin/" uninstall: - rm -rvf "$(PREFIX)/bin/tomo" "$(PREFIX)/lib/libtomo.so" "$(PREFIX)/share/tomo"; \ + rm -rvf "$(PREFIX)/bin/tomo" "$(PREFIX)/include/tomo" "$(PREFIX)/lib/libtomo.so" "$(PREFIX)/share/tomo"; \ .PHONY: all clean install uninstall test tags diff --git a/ast.h b/ast.h index 847f2224..3ee7f61d 100644 --- a/ast.h +++ b/ast.h @@ -4,8 +4,8 @@ #include #include -#include "files.h" -#include "util.h" +#include "builtins/files.h" +#include "builtins/util.h" #define NewAST(_file, _start, _end, ast_tag, ...) (new(ast_t, .file=_file, .start=_start, .end=_end,\ .tag=ast_tag, .__data.ast_tag={__VA_ARGS__})) diff --git a/builtins/array.c b/builtins/array.c index 07814f66..2fd66f58 100644 --- a/builtins/array.c +++ b/builtins/array.c @@ -11,8 +11,8 @@ #include "array.h" #include "types.h" #include "functions.h" -#include "../SipHash/halfsiphash.h" -#include "../util.h" +#include "halfsiphash.h" +#include "util.h" static inline size_t get_item_size(const TypeInfo *info) { diff --git a/builtins/array.h b/builtins/array.h index 52fd65e3..d36db573 100644 --- a/builtins/array.h +++ b/builtins/array.h @@ -2,7 +2,7 @@ #include #include -#include "../util.h" +#include "util.h" #include "datatypes.h" #include "functions.h" #include "types.h" diff --git a/builtins/bool.c b/builtins/bool.c index 327a101d..35eaafec 100644 --- a/builtins/bool.c +++ b/builtins/bool.c @@ -8,9 +8,9 @@ #include #include -#include "../SipHash/halfsiphash.h" -#include "../util.h" +#include "util.h" #include "bool.h" +#include "halfsiphash.h" #include "types.h" public CORD Bool__as_text(const bool *b, bool colorize, const TypeInfo *type) diff --git a/builtins/color.c b/builtins/color.c index b84d8a71..4732382a 100644 --- a/builtins/color.c +++ b/builtins/color.c @@ -4,7 +4,7 @@ #include #include -#include "../util.h" +#include "util.h" #include "color.h" public bool USE_COLOR = true; diff --git a/builtins/files.c b/builtins/files.c new file mode 100644 index 00000000..9fe9b916 --- /dev/null +++ b/builtins/files.c @@ -0,0 +1,320 @@ +// +// files.c - Implementation of some file loading functionality. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "files.h" +#include "util.h" + +static const int tabstop = 4; + +public char *resolve_path(const char *path, const char *relative_to, const char *system_path) +{ + if (!relative_to || streq(relative_to, "/dev/stdin")) relative_to = "."; + if (!path || strlen(path) == 0) return NULL; + + // Resolve the path to an absolute path, assuming it's relative to the file + // it was found in: + char buf[PATH_MAX] = {0}; + if (streq(path, "~") || strncmp(path, "~/", 2) == 0) { + char *resolved = realpath(heap_strf("%s%s", getenv("HOME"), path+1), buf); + if (resolved) return heap_str(resolved); + } else if (streq(path, ".") || strncmp(path, "./", 2) == 0) { + char *relative_dir = dirname(heap_str(relative_to)); + char *resolved = realpath(heap_strf("%s/%s", relative_dir, path), buf); + if (resolved) return heap_str(resolved); + } else if (path[0] == '/') { + // Absolute path: + char *resolved = realpath(path, buf); + if (resolved) return heap_str(resolved); + } else { + // Relative path: + char *relative_dir = dirname(heap_str(relative_to)); + if (!system_path) system_path = "."; + char *copy = strdup(system_path); + for (char *dir, *pos = copy; (dir = strsep(&pos, ":")); ) { + if (dir[0] == '/') { + char *resolved = realpath(heap_strf("%s/%s", dir, path), buf); + if (resolved) return heap_str(resolved); + } else if (dir[0] == '~' && (dir[1] == '\0' || dir[1] == '/')) { + char *resolved = realpath(heap_strf("%s%s/%s", getenv("HOME"), dir, path), buf); + if (resolved) return heap_str(resolved); + } else if (streq(dir, ".") || strncmp(dir, "./", 2) == 0) { + char *resolved = realpath(heap_strf("%s/%s", relative_dir, path), buf); + if (resolved) return heap_str(resolved); + } else if (streq(dir, ".") || streq(dir, "..") || strncmp(dir, "./", 2) == 0 || strncmp(dir, "../", 3) == 0) { + char *resolved = realpath(heap_strf("%s/%s/%s", relative_dir, dir, path), buf); + if (resolved) return heap_str(resolved); + } else { + char *resolved = realpath(heap_strf("%s/%s", dir, path), buf); + if (resolved) return heap_str(resolved); + } + } + free(copy); + } + return NULL; +} + +static file_t *_load_file(const char* filename, FILE *file) +{ + if (!file) return NULL; + + file_t *ret = new(file_t, .filename=filename); + + size_t file_size = 0, line_cap = 0; + char *file_buf = NULL, *line_buf = NULL; + FILE *mem = open_memstream(&file_buf, &file_size); + int64_t line_len = 0; + while ((line_len = getline(&line_buf, &line_cap, file)) >= 0) { + file_line_t line_info = {.offset=file_size, .indent=0, .is_empty=false}; + char *p; + for (p = line_buf; *p == '\t'; ++p) + line_info.indent += 1; + line_info.is_empty = *p != '\r' && *p != '\n'; + if (ret->line_capacity <= ret->num_lines) { + ret->lines = GC_REALLOC(ret->lines, sizeof(file_line_t)*(ret->line_capacity += 32)); + } + ret->lines[ret->num_lines++] = line_info; + fwrite(line_buf, sizeof(char), line_len, mem); + fflush(mem); + } + fclose(file); + + char *copy = GC_MALLOC_ATOMIC(file_size+1); + memcpy(copy, file_buf, file_size); + copy[file_size] = '\0'; + ret->text = copy; + ret->len = file_size; + fclose(mem); + + free(file_buf); + ret->relative_filename = filename; + if (filename && filename[0] != '<' && !streq(filename, "/dev/stdin")) { + filename = resolve_path(filename, ".", "."); + // Convert to relative path (if applicable) + char buf[PATH_MAX]; + char *cwd = getcwd(buf, sizeof(buf)); + int64_t cwd_len = strlen(cwd); + if (strncmp(cwd, filename, cwd_len) == 0 && filename[cwd_len] == '/') + ret->relative_filename = &filename[cwd_len+1]; + } + return ret; +} + +// +// Read an entire file into memory. +// +public file_t *load_file(const char* filename) +{ + FILE *file = filename[0] ? fopen(filename, "r") : stdin; + return _load_file(filename, file); +} + +// +// Create a virtual file from a string. +// +public file_t *spoof_file(const char* filename, const char *text) +{ + FILE *file = fmemopen((char*)text, strlen(text)+1, "r"); + return _load_file(filename, file); +} + +// +// Given a pointer, determine which line number it points to (1-indexed) +// +public int64_t get_line_number(file_t *f, const char *p) +{ + // Binary search: + int64_t lo = 0, hi = (int64_t)f->num_lines-1; + if (p < f->text) return 0; + int64_t offset = (int64_t)(p - f->text); + while (lo <= hi) { + int64_t mid = (lo + hi) / 2; + file_line_t *line = &f->lines[mid]; + if (line->offset == offset) + return mid + 1; + else if (line->offset < offset) + lo = mid + 1; + else if (line->offset > offset) + hi = mid - 1; + } + return lo; // Return the line number whose line starts closest before p +} + +// +// Given a pointer, determine which line column it points to. +// +public int64_t get_line_column(file_t *f, const char *p) +{ + int64_t line_no = get_line_number(f, p); + file_line_t *line = &f->lines[line_no-1]; + return 1 + (int64_t)(p - (f->text + line->offset)); +} + +// +// Given a pointer, get the indentation of the line it's on. +// +public int64_t get_indent(file_t *f, const char *p) +{ + int64_t line_no = get_line_number(f, p); + file_line_t *line = &f->lines[line_no-1]; + return line->indent; +} + +// +// Return a pointer to the line with the specified line number (1-indexed) +// +public const char *get_line(file_t *f, int64_t line_number) +{ + if (line_number == 0 || line_number > (int64_t)f->num_lines) return NULL; + file_line_t *line = &f->lines[line_number-1]; + return f->text + line->offset; +} + +// +// Return a value like /foo:line:col +// +public const char *get_file_pos(file_t *f, const char *p) +{ + return heap_strf("%s:%ld:%ld", f->filename, get_line_number(f, p), get_line_column(f, p)); +} + +static int fputc_column(FILE *out, char c, char print_char, int *column) +{ + int printed = 0; + if (print_char == '\t') print_char = ' '; + if (c == '\t') { + for (int to_fill = tabstop - (*column % tabstop); to_fill > 0; --to_fill) { + printed += fputc(print_char, out); + ++*column; + } + } else { + printed += fputc(print_char, out); + ++*column; + } + return printed; +} + +// +// Print a span from a file +// +public int fprint_span(FILE *out, file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color) +{ + if (!file) return 0; + + // Handle spans that come from multiple files: + if (start < file->text || start > file->text + file->len) + start = end; + if (end < file->text || end > file->text + file->len) + end = start; + // Just in case neither end of the span came from this file: + if (end < file->text || end > file->text + file->len) + start = end = file->text; + + const char *lineno_fmt, *normal_color, *empty_marker; + bool print_carets = false; + int printed = 0; + if (use_color) { + lineno_fmt = "\x1b[0;2m%*lu\x1b(0\x78\x1b(B\x1b[m "; + normal_color = "\x1b[m"; + empty_marker = "\x1b(0\x61\x1b(B"; + printed += fprintf(out, "\x1b[33;4;1m%s\x1b[m\n", file->relative_filename); + } else { + lineno_fmt = "%*lu| "; + hl_color = ""; + normal_color = ""; + empty_marker = " "; + print_carets = true; + printed += fprintf(out, "%s\n", file->relative_filename); + } + + if (context_lines == 0) + return fprintf(out, "%s%.*s%s", hl_color, (int)(end - start), start, normal_color); + + int64_t start_line = get_line_number(file, start), + end_line = get_line_number(file, end); + + int64_t first_line = start_line - (context_lines - 1), + last_line = end_line + (context_lines - 1); + + if (first_line < 1) first_line = 1; + if (last_line > file->num_lines) last_line = file->num_lines; + + int digits = 1; + for (int64_t i = last_line; i > 0; i /= 10) ++digits; + + for (int64_t line_no = first_line; line_no <= last_line; ++line_no) { + if (line_no > first_line + 5 && line_no < last_line - 5) { + if (use_color) + printed += fprintf(out, "\x1b[0;2;3;4m ... %ld lines omitted ... \x1b[m\n", (last_line - first_line) - 11); + else + printed += fprintf(out, " ... %ld lines omitted ...\n", (last_line - first_line) - 11); + line_no = last_line - 6; + continue; + } + + printed += fprintf(out, lineno_fmt, digits, line_no); + const char *line = get_line(file, line_no); + if (!line) break; + + int column = 0; + const char *p = line; + // Before match + for (; *p && *p != '\r' && *p != '\n' && p < start; ++p) + printed += fputc_column(out, *p, *p, &column); + + // Zero-width matches + if (p == start && start == end) { + printed += fprintf(out, "%s%s%s", hl_color, empty_marker, normal_color); + column += 1; + } + + // Inside match + if (start <= p && p < end) { + printed += fputs(hl_color, out); + for (; *p && *p != '\r' && *p != '\n' && p < end; ++p) + printed += fputc_column(out, *p, *p, &column); + printed += fputs(normal_color, out); + } + + // After match + for (; *p && *p != '\r' && *p != '\n'; ++p) + printed += fputc_column(out, *p, *p, &column); + + printed += fprintf(out, "\n"); + + const char *eol = strchrnul(line, '\n'); + if (print_carets && start >= line && start < eol && line <= start) { + for (int num = 0; num < digits; num++) + printed += fputc(' ', out); + printed += fputs(": ", out); + int column = 0; + for (const char *sp = line; *sp && *sp != '\n'; ++sp) { + char print_char; + if (sp < start) + print_char = ' '; + else if (sp == start && sp == end) + print_char = '^'; + else if (sp >= start && sp < end) + print_char = '-'; + else + print_char = ' '; + printed += fputc_column(out, *sp, print_char, &column); + } + printed += fputs("\n", out); + } + } + fflush(out); + return printed; +} + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/files.h b/builtins/files.h new file mode 100644 index 00000000..79dd48cd --- /dev/null +++ b/builtins/files.h @@ -0,0 +1,42 @@ +// +// files.h - Definitions of an API for loading files. +// +#pragma once + +#include +#include +#include +#include + +typedef struct { + int64_t offset; + int64_t indent:63; + bool is_empty:1; +} file_line_t; + +typedef struct { + const char *filename, *relative_filename; + const char *text; + int64_t len; + int64_t num_lines, line_capacity; + file_line_t *lines; +} file_t; + +char *resolve_path(const char *path, const char *relative_to, const char *system_path); +__attribute__((nonnull)) +file_t *load_file(const char *filename); +__attribute__((nonnull, returns_nonnull)) +file_t *spoof_file(const char *filename, const char *text); +__attribute__((pure, nonnull)) +int64_t get_line_number(file_t *f, const char *p); +__attribute__((pure, nonnull)) +int64_t get_line_column(file_t *f, const char *p); +__attribute__((pure, nonnull)) +int64_t get_indent(file_t *f, const char *p); +__attribute__((pure, nonnull)) +const char *get_line(file_t *f, int64_t line_number); +__attribute__((pure, nonnull)) +const char *get_file_pos(file_t *f, const char *p); +int fprint_span(FILE *out, file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color); + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/functions.c b/builtins/functions.c index 448b7758..ae67fcb9 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -7,15 +7,15 @@ #include #include -#include "../SipHash/halfsiphash.h" -#include "../files.h" -#include "../util.h" -#include "functions.h" +#include "files.h" +#include "util.h" #include "array.h" -#include "table.h" -#include "text.h" +#include "functions.h" +#include "halfsiphash.h" #include "pointer.h" #include "string.h" +#include "table.h" +#include "text.h" #include "types.h" extern bool USE_COLOR; diff --git a/builtins/halfsiphash.h b/builtins/halfsiphash.h new file mode 100644 index 00000000..a1af8cd2 --- /dev/null +++ b/builtins/halfsiphash.h @@ -0,0 +1,22 @@ +/* + SipHash reference C implementation + + Copyright (c) 2012-2021 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +#include +#include + +int halfsiphash(const void *in, const size_t inlen, const void *k, uint8_t *out, + const size_t outlen); diff --git a/builtins/integers.c b/builtins/integers.c index 6de85c3e..4116879e 100644 --- a/builtins/integers.c +++ b/builtins/integers.c @@ -4,9 +4,9 @@ #include #include -#include "../SipHash/halfsiphash.h" #include "array.h" #include "datatypes.h" +#include "halfsiphash.h" #include "integers.h" #include "string.h" #include "types.h" diff --git a/builtins/macros.h b/builtins/macros.h new file mode 100644 index 00000000..c6f474ec --- /dev/null +++ b/builtins/macros.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define $heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x)) +#define $stack(x) (__typeof(x)*)((__typeof(x)[1]){x}) +#define $tagged(obj_expr, type_name, tag_name) ({ __typeof(obj_expr) $obj = obj_expr; \ + $obj.$tag == $tag$##type_name##$##tag_name ? &$obj.tag_name : NULL; }) + + +#define not(x) _Generic(x, bool: (bool)!(x), int64_t: ~(x), int32_t: ~(x), int16_t: ~(x), int8_t: ~(x), \ + array_t: ((x).length == 0), table_t: ((x).entries.length == 0), CORD: ((x) == CORD_EMPTY), \ + default: _Static_assert(0, "Not supported")) +#define Bool(x) _Generic(x, bool: (bool)(x), int64_t: (x != 0), int32_t: (x != 0), int16_t: (x != 0), int8_t: (x != 0), CORD: ((x) == CORD_EMPTY), \ + array_t: ((x).length > 0), table_t: ((x).entries.length > 0), CORD: ((x) != CORD_EMPTY), \ + default: _Static_assert(0, "Not supported")) +#define and(x, y) _Generic(x, bool: (bool)((x) && (y)), default: ((x) & (y))) +#define or(x, y) _Generic(x, bool: (bool)((x) || (y)), default: ((x) | (y))) +#define xor(x, y) _Generic(x, bool: (bool)((x) ^ (y)), default: ((x) ^ (y))) +#define mod(x, n) ((x) % (n)) +#define mod1(x, n) (((x) % (n)) + (__typeof(x))1) +#define $cmp(x, y, info) (_Generic(x, int8_t: (x>0)-(y>0), int16_t: (x>0)-(y>0), int32_t: (x>0)-(y>0), int64_t: (x>0)-(y>0), bool: (x>0)-(y>0), \ + CORD: CORD_cmp((CORD)x, (CORD)y), char*: strcmp((char*)x, (char*)y), default: generic_compare($stack(x), $stack(y), info))) diff --git a/builtins/memory.c b/builtins/memory.c index d4af4cc2..f33196be 100644 --- a/builtins/memory.c +++ b/builtins/memory.c @@ -8,8 +8,8 @@ #include #include -#include "../util.h" -#include "../SipHash/halfsiphash.h" +#include "util.h" +#include "halfsiphash.h" #include "memory.h" #include "types.h" diff --git a/builtins/nums.c b/builtins/nums.c index 32ec89fb..b05c6fab 100644 --- a/builtins/nums.c +++ b/builtins/nums.c @@ -1,13 +1,13 @@ +#include #include #include -#include #include #include #include #include -#include "../SipHash/halfsiphash.h" #include "array.h" +#include "halfsiphash.h" #include "nums.h" #include "string.h" #include "types.h" diff --git a/builtins/pointer.c b/builtins/pointer.c index 54bab4b3..d490485f 100644 --- a/builtins/pointer.c +++ b/builtins/pointer.c @@ -1,16 +1,16 @@ +#include +#include #include #include #include #include #include -#include #include -#include -#include "../util.h" -#include "../SipHash/halfsiphash.h" +#include "util.h" #include "functions.h" +#include "halfsiphash.h" #include "types.h" typedef struct recursion_s { diff --git a/builtins/table.c b/builtins/table.c index 5631a7fb..be4444ac 100644 --- a/builtins/table.c +++ b/builtins/table.c @@ -17,13 +17,13 @@ #include #include -#include "../SipHash/halfsiphash.h" -#include "../util.h" +#include "util.h" #include "array.h" #include "datatypes.h" +#include "halfsiphash.h" #include "memory.h" -#include "text.h" #include "table.h" +#include "text.h" #include "types.h" // #define DEBUG_TABLES diff --git a/builtins/text.c b/builtins/text.c index 4641bc1d..e443da33 100644 --- a/builtins/text.c +++ b/builtins/text.c @@ -14,9 +14,9 @@ #include #include -#include "../SipHash/halfsiphash.h" #include "array.h" #include "functions.h" +#include "halfsiphash.h" #include "text.h" #include "types.h" diff --git a/builtins/tomo.h b/builtins/tomo.h new file mode 100644 index 00000000..dd00c628 --- /dev/null +++ b/builtins/tomo.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "array.h" +#include "bool.h" +#include "color.h" +#include "datatypes.h" +#include "functions.h" +#include "halfsiphash.h" +#include "integers.h" +#include "macros.h" +#include "memory.h" +#include "nums.h" +#include "pointer.h" +#include "table.h" +#include "text.h" +#include "types.h" + +#define $heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x)) +#define $stack(x) (__typeof(x)*)((__typeof(x)[1]){x}) +#define $tagged(obj_expr, type_name, tag_name) ({ __typeof(obj_expr) $obj = obj_expr; \ + $obj.$tag == $tag$##type_name##$##tag_name ? &$obj.tag_name : NULL; }) + + +#define not(x) _Generic(x, bool: (bool)!(x), int64_t: ~(x), int32_t: ~(x), int16_t: ~(x), int8_t: ~(x), \ + array_t: ((x).length == 0), table_t: ((x).entries.length == 0), CORD: ((x) == CORD_EMPTY), \ + default: _Static_assert(0, "Not supported")) +#define Bool(x) _Generic(x, bool: (bool)(x), int64_t: (x != 0), int32_t: (x != 0), int16_t: (x != 0), int8_t: (x != 0), CORD: ((x) == CORD_EMPTY), \ + array_t: ((x).length > 0), table_t: ((x).entries.length > 0), CORD: ((x) != CORD_EMPTY), \ + default: _Static_assert(0, "Not supported")) +#define and(x, y) _Generic(x, bool: (bool)((x) && (y)), default: ((x) & (y))) +#define or(x, y) _Generic(x, bool: (bool)((x) || (y)), default: ((x) | (y))) +#define xor(x, y) _Generic(x, bool: (bool)((x) ^ (y)), default: ((x) ^ (y))) +#define mod(x, n) ((x) % (n)) +#define mod1(x, n) (((x) % (n)) + (__typeof(x))1) +#define $cmp(x, y, info) (_Generic(x, int8_t: (x>0)-(y>0), int16_t: (x>0)-(y>0), int32_t: (x>0)-(y>0), int64_t: (x>0)-(y>0), bool: (x>0)-(y>0), \ + CORD: CORD_cmp((CORD)x, (CORD)y), char*: strcmp((char*)x, (char*)y), default: generic_compare($stack(x), $stack(y), info))) + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/types.c b/builtins/types.c index 59bf5c47..72be5afa 100644 --- a/builtins/types.c +++ b/builtins/types.c @@ -1,16 +1,16 @@ // Generic type constructor #include #include -#include #include +#include #include +#include "util.h" #include "array.h" -#include "table.h" +#include "halfsiphash.h" #include "pointer.h" +#include "table.h" #include "types.h" -#include "../util.h" -#include "../SipHash/halfsiphash.h" public CORD Type__as_text(const void *typeinfo, bool colorize, const TypeInfo *type) { diff --git a/builtins/util.c b/builtins/util.c new file mode 100644 index 00000000..16ef7aaf --- /dev/null +++ b/builtins/util.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +public char *heap_strn(const char *str, size_t len) +{ + if (!str) return NULL; + if (len == 0) return ""; + char *heaped = GC_MALLOC_ATOMIC(len + 1); + memcpy(heaped, str, len); + heaped[len] = '\0'; + return heaped; +} + +public char *heap_str(const char *str) +{ + if (!str) return NULL; + return heap_strn(str, strlen(str)); +} + +public char *heap_strf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + char *tmp = NULL; + int len = vasprintf(&tmp, fmt, args); + if (len < 0) return NULL; + va_end(args); + char *ret = heap_strn(tmp, (size_t)len); + free(tmp); + return ret; +} + +// Name mangling algorithm to produce valid identifiers: +// Escape individual chars as "_x%02X" +// Things being escaped: +// - Leading digit +// - Non alphanumeric/non-underscore characters +// - "_" when followed by "x" and two uppercase hex digits +public char *mangle(const char *name) +{ + size_t len = 0; + for (const char *p = name; *p; p++) { + if ((!isalnum(*p) && *p != '_') // Non-identifier character + || (p == name && isdigit(*p)) // Leading digit + || (p[0] == '_' && p[1] == 'x' && strspn(p+2, "ABCDEF0123456789") >= 2)) { // Looks like hex escape + len += strlen("_x00"); // Hex escape + } else { + len += 1; + } + } + char *mangled = GC_MALLOC_ATOMIC(len + 1); + char *dest = mangled; + for (const char *src = name; *src; src++) { + if ((!isalnum(*src) && *src != '_') // Non-identifier character + || (src == name && isdigit(*src)) // Leading digit + || (src[0] == '_' && src[1] == 'x' && strspn(src+2, "ABCDEF0123456789") >= 2)) { // Looks like hex escape + dest += sprintf(dest, "_x%02X", *src); // Hex escape + } else { + *(dest++) = *src; + } + } + mangled[len] = '\0'; + return mangled; +} + +CORD CORD_asprintf(CORD fmt, ...) +{ + va_list args; + va_start(args, fmt); + CORD c = NULL; + CORD_vsprintf(&c, fmt, args); + va_end(args); + return c; +} + + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/util.h b/builtins/util.h new file mode 100644 index 00000000..c858f6ce --- /dev/null +++ b/builtins/util.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#define streq(a, b) (((a) == NULL && (b) == NULL) || (((a) == NULL) == ((b) == NULL) && strcmp(a, b) == 0)) +#define new(t, ...) ((t*)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t))) +#define copy(obj_ptr) ((__typeof(obj_ptr))memcpy(GC_MALLOC(sizeof(*(obj_ptr))), obj_ptr, sizeof(*(obj_ptr)))) +#define grow(arr, new_size) ((typeof (arr))GC_REALLOC(arr, (sizeof(arr[0]))*(new_size))) +#define Match(x, _tag) ((x)->tag == _tag ? &(x)->__data._tag : (errx(1, __FILE__ ":%d This was supposed to be a " # _tag "\n", __LINE__), &(x)->__data._tag)) +#define Tagged(t, _tag, ...) new(t, .tag=_tag, .__data._tag={__VA_ARGS__}) + +#ifndef auto +#define auto __auto_type +#endif + +#ifndef public +#define public __attribute__ ((visibility ("default"))) +#endif + +char *heap_strn(const char *str, size_t len); +char *heap_str(const char *str); +char *heap_strf(const char *fmt, ...); +CORD CORD_asprintf(CORD fmt, ...); +#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__) + +#define asprintfa(...) ({ char *_buf = alloca(snprintf(0, 0, __VA_ARGS__)); sprintf(_buf, __VA_ARGS__); _buf; }) + +#define REVERSE_LIST(list) do { \ + __typeof(list) _prev = NULL; \ + __typeof(list) _next = NULL; \ + auto _current = list; \ + while (_current != NULL) { \ + _next = _current->next; \ + _current->next = _prev; \ + _prev = _current; \ + _current = _next; \ + } \ + list = _prev; \ +} while(0) + +#define LIST_MAP(src, var, ...) ({\ + __typeof(src) __mapped = NULL; \ + __typeof(src) *__next = &__mapped; \ + for (__typeof(src) var = src; var; var = var->next) { \ + *__next = GC_MALLOC(sizeof(__typeof(*(src)))); \ + **__next = *var; \ + **__next = (__typeof(*(src))){__VA_ARGS__}; \ + __next = &((*__next)->next); \ + } \ + __mapped; }) + + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/compile.c b/compile.c index a395a75c..9d1604cc 100644 --- a/compile.c +++ b/compile.c @@ -12,7 +12,7 @@ #include "structs.h" #include "environment.h" #include "typecheck.h" -#include "util.h" +#include "builtins/util.h" CORD compile_type_ast(type_ast_t *t) { @@ -1518,7 +1518,7 @@ CORD compile_type_info(env_t *env, type_t *t) module_code_t compile_file(ast_t *ast) { env_t *env = new_compilation_unit(); - CORD_appendf(&env->code->imports, "#include \n"); + CORD_appendf(&env->code->imports, "#include \n"); for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { bind_statement(env, stmt->ast); diff --git a/compile.h b/compile.h index c50e22aa..b8bdbc36 100644 --- a/compile.h +++ b/compile.h @@ -4,7 +4,7 @@ #include #include -#include "util.h" +#include "builtins/util.h" #include "environment.h" typedef struct { diff --git a/enums.c b/enums.c index 6aaa9ced..ff0c09fc 100644 --- a/enums.c +++ b/enums.c @@ -10,7 +10,7 @@ #include "structs.h" #include "environment.h" #include "typecheck.h" -#include "util.h" +#include "builtins/util.h" static CORD compile_str_method(env_t *env, ast_t *ast) { diff --git a/environment.c b/environment.c index d9573e2f..3ba7cdd2 100644 --- a/environment.c +++ b/environment.c @@ -6,7 +6,7 @@ #include "builtins/table.h" #include "builtins/text.h" #include "typecheck.h" -#include "util.h" +#include "builtins/util.h" typedef struct { const char *name; diff --git a/files.c b/files.c deleted file mode 100644 index 9fe9b916..00000000 --- a/files.c +++ /dev/null @@ -1,320 +0,0 @@ -// -// files.c - Implementation of some file loading functionality. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "files.h" -#include "util.h" - -static const int tabstop = 4; - -public char *resolve_path(const char *path, const char *relative_to, const char *system_path) -{ - if (!relative_to || streq(relative_to, "/dev/stdin")) relative_to = "."; - if (!path || strlen(path) == 0) return NULL; - - // Resolve the path to an absolute path, assuming it's relative to the file - // it was found in: - char buf[PATH_MAX] = {0}; - if (streq(path, "~") || strncmp(path, "~/", 2) == 0) { - char *resolved = realpath(heap_strf("%s%s", getenv("HOME"), path+1), buf); - if (resolved) return heap_str(resolved); - } else if (streq(path, ".") || strncmp(path, "./", 2) == 0) { - char *relative_dir = dirname(heap_str(relative_to)); - char *resolved = realpath(heap_strf("%s/%s", relative_dir, path), buf); - if (resolved) return heap_str(resolved); - } else if (path[0] == '/') { - // Absolute path: - char *resolved = realpath(path, buf); - if (resolved) return heap_str(resolved); - } else { - // Relative path: - char *relative_dir = dirname(heap_str(relative_to)); - if (!system_path) system_path = "."; - char *copy = strdup(system_path); - for (char *dir, *pos = copy; (dir = strsep(&pos, ":")); ) { - if (dir[0] == '/') { - char *resolved = realpath(heap_strf("%s/%s", dir, path), buf); - if (resolved) return heap_str(resolved); - } else if (dir[0] == '~' && (dir[1] == '\0' || dir[1] == '/')) { - char *resolved = realpath(heap_strf("%s%s/%s", getenv("HOME"), dir, path), buf); - if (resolved) return heap_str(resolved); - } else if (streq(dir, ".") || strncmp(dir, "./", 2) == 0) { - char *resolved = realpath(heap_strf("%s/%s", relative_dir, path), buf); - if (resolved) return heap_str(resolved); - } else if (streq(dir, ".") || streq(dir, "..") || strncmp(dir, "./", 2) == 0 || strncmp(dir, "../", 3) == 0) { - char *resolved = realpath(heap_strf("%s/%s/%s", relative_dir, dir, path), buf); - if (resolved) return heap_str(resolved); - } else { - char *resolved = realpath(heap_strf("%s/%s", dir, path), buf); - if (resolved) return heap_str(resolved); - } - } - free(copy); - } - return NULL; -} - -static file_t *_load_file(const char* filename, FILE *file) -{ - if (!file) return NULL; - - file_t *ret = new(file_t, .filename=filename); - - size_t file_size = 0, line_cap = 0; - char *file_buf = NULL, *line_buf = NULL; - FILE *mem = open_memstream(&file_buf, &file_size); - int64_t line_len = 0; - while ((line_len = getline(&line_buf, &line_cap, file)) >= 0) { - file_line_t line_info = {.offset=file_size, .indent=0, .is_empty=false}; - char *p; - for (p = line_buf; *p == '\t'; ++p) - line_info.indent += 1; - line_info.is_empty = *p != '\r' && *p != '\n'; - if (ret->line_capacity <= ret->num_lines) { - ret->lines = GC_REALLOC(ret->lines, sizeof(file_line_t)*(ret->line_capacity += 32)); - } - ret->lines[ret->num_lines++] = line_info; - fwrite(line_buf, sizeof(char), line_len, mem); - fflush(mem); - } - fclose(file); - - char *copy = GC_MALLOC_ATOMIC(file_size+1); - memcpy(copy, file_buf, file_size); - copy[file_size] = '\0'; - ret->text = copy; - ret->len = file_size; - fclose(mem); - - free(file_buf); - ret->relative_filename = filename; - if (filename && filename[0] != '<' && !streq(filename, "/dev/stdin")) { - filename = resolve_path(filename, ".", "."); - // Convert to relative path (if applicable) - char buf[PATH_MAX]; - char *cwd = getcwd(buf, sizeof(buf)); - int64_t cwd_len = strlen(cwd); - if (strncmp(cwd, filename, cwd_len) == 0 && filename[cwd_len] == '/') - ret->relative_filename = &filename[cwd_len+1]; - } - return ret; -} - -// -// Read an entire file into memory. -// -public file_t *load_file(const char* filename) -{ - FILE *file = filename[0] ? fopen(filename, "r") : stdin; - return _load_file(filename, file); -} - -// -// Create a virtual file from a string. -// -public file_t *spoof_file(const char* filename, const char *text) -{ - FILE *file = fmemopen((char*)text, strlen(text)+1, "r"); - return _load_file(filename, file); -} - -// -// Given a pointer, determine which line number it points to (1-indexed) -// -public int64_t get_line_number(file_t *f, const char *p) -{ - // Binary search: - int64_t lo = 0, hi = (int64_t)f->num_lines-1; - if (p < f->text) return 0; - int64_t offset = (int64_t)(p - f->text); - while (lo <= hi) { - int64_t mid = (lo + hi) / 2; - file_line_t *line = &f->lines[mid]; - if (line->offset == offset) - return mid + 1; - else if (line->offset < offset) - lo = mid + 1; - else if (line->offset > offset) - hi = mid - 1; - } - return lo; // Return the line number whose line starts closest before p -} - -// -// Given a pointer, determine which line column it points to. -// -public int64_t get_line_column(file_t *f, const char *p) -{ - int64_t line_no = get_line_number(f, p); - file_line_t *line = &f->lines[line_no-1]; - return 1 + (int64_t)(p - (f->text + line->offset)); -} - -// -// Given a pointer, get the indentation of the line it's on. -// -public int64_t get_indent(file_t *f, const char *p) -{ - int64_t line_no = get_line_number(f, p); - file_line_t *line = &f->lines[line_no-1]; - return line->indent; -} - -// -// Return a pointer to the line with the specified line number (1-indexed) -// -public const char *get_line(file_t *f, int64_t line_number) -{ - if (line_number == 0 || line_number > (int64_t)f->num_lines) return NULL; - file_line_t *line = &f->lines[line_number-1]; - return f->text + line->offset; -} - -// -// Return a value like /foo:line:col -// -public const char *get_file_pos(file_t *f, const char *p) -{ - return heap_strf("%s:%ld:%ld", f->filename, get_line_number(f, p), get_line_column(f, p)); -} - -static int fputc_column(FILE *out, char c, char print_char, int *column) -{ - int printed = 0; - if (print_char == '\t') print_char = ' '; - if (c == '\t') { - for (int to_fill = tabstop - (*column % tabstop); to_fill > 0; --to_fill) { - printed += fputc(print_char, out); - ++*column; - } - } else { - printed += fputc(print_char, out); - ++*column; - } - return printed; -} - -// -// Print a span from a file -// -public int fprint_span(FILE *out, file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color) -{ - if (!file) return 0; - - // Handle spans that come from multiple files: - if (start < file->text || start > file->text + file->len) - start = end; - if (end < file->text || end > file->text + file->len) - end = start; - // Just in case neither end of the span came from this file: - if (end < file->text || end > file->text + file->len) - start = end = file->text; - - const char *lineno_fmt, *normal_color, *empty_marker; - bool print_carets = false; - int printed = 0; - if (use_color) { - lineno_fmt = "\x1b[0;2m%*lu\x1b(0\x78\x1b(B\x1b[m "; - normal_color = "\x1b[m"; - empty_marker = "\x1b(0\x61\x1b(B"; - printed += fprintf(out, "\x1b[33;4;1m%s\x1b[m\n", file->relative_filename); - } else { - lineno_fmt = "%*lu| "; - hl_color = ""; - normal_color = ""; - empty_marker = " "; - print_carets = true; - printed += fprintf(out, "%s\n", file->relative_filename); - } - - if (context_lines == 0) - return fprintf(out, "%s%.*s%s", hl_color, (int)(end - start), start, normal_color); - - int64_t start_line = get_line_number(file, start), - end_line = get_line_number(file, end); - - int64_t first_line = start_line - (context_lines - 1), - last_line = end_line + (context_lines - 1); - - if (first_line < 1) first_line = 1; - if (last_line > file->num_lines) last_line = file->num_lines; - - int digits = 1; - for (int64_t i = last_line; i > 0; i /= 10) ++digits; - - for (int64_t line_no = first_line; line_no <= last_line; ++line_no) { - if (line_no > first_line + 5 && line_no < last_line - 5) { - if (use_color) - printed += fprintf(out, "\x1b[0;2;3;4m ... %ld lines omitted ... \x1b[m\n", (last_line - first_line) - 11); - else - printed += fprintf(out, " ... %ld lines omitted ...\n", (last_line - first_line) - 11); - line_no = last_line - 6; - continue; - } - - printed += fprintf(out, lineno_fmt, digits, line_no); - const char *line = get_line(file, line_no); - if (!line) break; - - int column = 0; - const char *p = line; - // Before match - for (; *p && *p != '\r' && *p != '\n' && p < start; ++p) - printed += fputc_column(out, *p, *p, &column); - - // Zero-width matches - if (p == start && start == end) { - printed += fprintf(out, "%s%s%s", hl_color, empty_marker, normal_color); - column += 1; - } - - // Inside match - if (start <= p && p < end) { - printed += fputs(hl_color, out); - for (; *p && *p != '\r' && *p != '\n' && p < end; ++p) - printed += fputc_column(out, *p, *p, &column); - printed += fputs(normal_color, out); - } - - // After match - for (; *p && *p != '\r' && *p != '\n'; ++p) - printed += fputc_column(out, *p, *p, &column); - - printed += fprintf(out, "\n"); - - const char *eol = strchrnul(line, '\n'); - if (print_carets && start >= line && start < eol && line <= start) { - for (int num = 0; num < digits; num++) - printed += fputc(' ', out); - printed += fputs(": ", out); - int column = 0; - for (const char *sp = line; *sp && *sp != '\n'; ++sp) { - char print_char; - if (sp < start) - print_char = ' '; - else if (sp == start && sp == end) - print_char = '^'; - else if (sp >= start && sp < end) - print_char = '-'; - else - print_char = ' '; - printed += fputc_column(out, *sp, print_char, &column); - } - printed += fputs("\n", out); - } - } - fflush(out); - return printed; -} - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/files.h b/files.h deleted file mode 100644 index 79dd48cd..00000000 --- a/files.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// files.h - Definitions of an API for loading files. -// -#pragma once - -#include -#include -#include -#include - -typedef struct { - int64_t offset; - int64_t indent:63; - bool is_empty:1; -} file_line_t; - -typedef struct { - const char *filename, *relative_filename; - const char *text; - int64_t len; - int64_t num_lines, line_capacity; - file_line_t *lines; -} file_t; - -char *resolve_path(const char *path, const char *relative_to, const char *system_path); -__attribute__((nonnull)) -file_t *load_file(const char *filename); -__attribute__((nonnull, returns_nonnull)) -file_t *spoof_file(const char *filename, const char *text); -__attribute__((pure, nonnull)) -int64_t get_line_number(file_t *f, const char *p); -__attribute__((pure, nonnull)) -int64_t get_line_column(file_t *f, const char *p); -__attribute__((pure, nonnull)) -int64_t get_indent(file_t *f, const char *p); -__attribute__((pure, nonnull)) -const char *get_line(file_t *f, int64_t line_number); -__attribute__((pure, nonnull)) -const char *get_file_pos(file_t *f, const char *p); -int fprint_span(FILE *out, file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color); - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/parse.c b/parse.c index bed73e0b..ef0a89ad 100644 --- a/parse.c +++ b/parse.c @@ -12,7 +12,7 @@ #include #include "ast.h" -#include "util.h" +#include "builtins/util.h" static const char closing[128] = {['(']=')', ['[']=']', ['<']='>', ['{']='}'}; diff --git a/structs.c b/structs.c index a5f4b964..b5ea5638 100644 --- a/structs.c +++ b/structs.c @@ -9,7 +9,7 @@ #include "compile.h" #include "environment.h" #include "typecheck.h" -#include "util.h" +#include "builtins/util.h" static bool is_plain_data(env_t *env, type_t *t) { diff --git a/tomo.h b/tomo.h deleted file mode 100644 index 7f4a6254..00000000 --- a/tomo.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SipHash/halfsiphash.h" -#include "builtins/array.h" -#include "builtins/bool.h" -#include "builtins/color.h" -#include "builtins/datatypes.h" -#include "builtins/functions.h" -#include "builtins/integers.h" -#include "builtins/memory.h" -#include "builtins/nums.h" -#include "builtins/pointer.h" -#include "builtins/table.h" -#include "builtins/text.h" -#include "builtins/types.h" - -#define $heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x)) -#define $stack(x) (__typeof(x)*)((__typeof(x)[1]){x}) -#define $tagged(obj_expr, type_name, tag_name) ({ __typeof(obj_expr) $obj = obj_expr; \ - $obj.$tag == $tag$##type_name##$##tag_name ? &$obj.tag_name : NULL; }) - - -#define not(x) _Generic(x, bool: (bool)!(x), int64_t: ~(x), int32_t: ~(x), int16_t: ~(x), int8_t: ~(x), \ - array_t: ((x).length == 0), table_t: ((x).entries.length == 0), CORD: ((x) == CORD_EMPTY), \ - default: _Static_assert(0, "Not supported")) -#define Bool(x) _Generic(x, bool: (bool)(x), int64_t: (x != 0), int32_t: (x != 0), int16_t: (x != 0), int8_t: (x != 0), CORD: ((x) == CORD_EMPTY), \ - array_t: ((x).length > 0), table_t: ((x).entries.length > 0), CORD: ((x) != CORD_EMPTY), \ - default: _Static_assert(0, "Not supported")) -#define and(x, y) _Generic(x, bool: (bool)((x) && (y)), default: ((x) & (y))) -#define or(x, y) _Generic(x, bool: (bool)((x) || (y)), default: ((x) | (y))) -#define xor(x, y) _Generic(x, bool: (bool)((x) ^ (y)), default: ((x) ^ (y))) -#define mod(x, n) ((x) % (n)) -#define mod1(x, n) (((x) % (n)) + (__typeof(x))1) -#define $cmp(x, y, info) (_Generic(x, int8_t: (x>0)-(y>0), int16_t: (x>0)-(y>0), int32_t: (x>0)-(y>0), int64_t: (x>0)-(y>0), bool: (x>0)-(y>0), \ - CORD: CORD_cmp((CORD)x, (CORD)y), char*: strcmp((char*)x, (char*)y), default: generic_compare($stack(x), $stack(y), info))) -#define min(c_type, x, y, info) ({ c_type $lhs = x, $rhs = y; generic_compare(&$lhs, &$rhs, info) <= 0 ? $lhs : $rhs; }) -#define max(c_type, x, y, info) ({ c_type $lhs = x, $rhs = y; generic_compare(&$lhs, &$rhs, info) >= 0 ? $lhs : $rhs; }) - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/typecheck.c b/typecheck.c index 5cabf3f1..769d8680 100644 --- a/typecheck.c +++ b/typecheck.c @@ -12,7 +12,7 @@ #include "parse.h" #include "typecheck.h" #include "types.h" -#include "util.h" +#include "builtins/util.h" type_t *parse_type_ast(env_t *env, type_ast_t *ast) { diff --git a/types.c b/types.c index ba6c1b62..e37a3b90 100644 --- a/types.c +++ b/types.c @@ -7,7 +7,7 @@ #include "builtins/table.h" #include "types.h" -#include "util.h" +#include "builtins/util.h" CORD type_to_cord(type_t *t) { switch (t->tag) { diff --git a/util.c b/util.c deleted file mode 100644 index 16ef7aaf..00000000 --- a/util.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" - -public char *heap_strn(const char *str, size_t len) -{ - if (!str) return NULL; - if (len == 0) return ""; - char *heaped = GC_MALLOC_ATOMIC(len + 1); - memcpy(heaped, str, len); - heaped[len] = '\0'; - return heaped; -} - -public char *heap_str(const char *str) -{ - if (!str) return NULL; - return heap_strn(str, strlen(str)); -} - -public char *heap_strf(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - char *tmp = NULL; - int len = vasprintf(&tmp, fmt, args); - if (len < 0) return NULL; - va_end(args); - char *ret = heap_strn(tmp, (size_t)len); - free(tmp); - return ret; -} - -// Name mangling algorithm to produce valid identifiers: -// Escape individual chars as "_x%02X" -// Things being escaped: -// - Leading digit -// - Non alphanumeric/non-underscore characters -// - "_" when followed by "x" and two uppercase hex digits -public char *mangle(const char *name) -{ - size_t len = 0; - for (const char *p = name; *p; p++) { - if ((!isalnum(*p) && *p != '_') // Non-identifier character - || (p == name && isdigit(*p)) // Leading digit - || (p[0] == '_' && p[1] == 'x' && strspn(p+2, "ABCDEF0123456789") >= 2)) { // Looks like hex escape - len += strlen("_x00"); // Hex escape - } else { - len += 1; - } - } - char *mangled = GC_MALLOC_ATOMIC(len + 1); - char *dest = mangled; - for (const char *src = name; *src; src++) { - if ((!isalnum(*src) && *src != '_') // Non-identifier character - || (src == name && isdigit(*src)) // Leading digit - || (src[0] == '_' && src[1] == 'x' && strspn(src+2, "ABCDEF0123456789") >= 2)) { // Looks like hex escape - dest += sprintf(dest, "_x%02X", *src); // Hex escape - } else { - *(dest++) = *src; - } - } - mangled[len] = '\0'; - return mangled; -} - -CORD CORD_asprintf(CORD fmt, ...) -{ - va_list args; - va_start(args, fmt); - CORD c = NULL; - CORD_vsprintf(&c, fmt, args); - va_end(args); - return c; -} - - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/util.h b/util.h deleted file mode 100644 index c858f6ce..00000000 --- a/util.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#define streq(a, b) (((a) == NULL && (b) == NULL) || (((a) == NULL) == ((b) == NULL) && strcmp(a, b) == 0)) -#define new(t, ...) ((t*)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t))) -#define copy(obj_ptr) ((__typeof(obj_ptr))memcpy(GC_MALLOC(sizeof(*(obj_ptr))), obj_ptr, sizeof(*(obj_ptr)))) -#define grow(arr, new_size) ((typeof (arr))GC_REALLOC(arr, (sizeof(arr[0]))*(new_size))) -#define Match(x, _tag) ((x)->tag == _tag ? &(x)->__data._tag : (errx(1, __FILE__ ":%d This was supposed to be a " # _tag "\n", __LINE__), &(x)->__data._tag)) -#define Tagged(t, _tag, ...) new(t, .tag=_tag, .__data._tag={__VA_ARGS__}) - -#ifndef auto -#define auto __auto_type -#endif - -#ifndef public -#define public __attribute__ ((visibility ("default"))) -#endif - -char *heap_strn(const char *str, size_t len); -char *heap_str(const char *str); -char *heap_strf(const char *fmt, ...); -CORD CORD_asprintf(CORD fmt, ...); -#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__) - -#define asprintfa(...) ({ char *_buf = alloca(snprintf(0, 0, __VA_ARGS__)); sprintf(_buf, __VA_ARGS__); _buf; }) - -#define REVERSE_LIST(list) do { \ - __typeof(list) _prev = NULL; \ - __typeof(list) _next = NULL; \ - auto _current = list; \ - while (_current != NULL) { \ - _next = _current->next; \ - _current->next = _prev; \ - _prev = _current; \ - _current = _next; \ - } \ - list = _prev; \ -} while(0) - -#define LIST_MAP(src, var, ...) ({\ - __typeof(src) __mapped = NULL; \ - __typeof(src) *__next = &__mapped; \ - for (__typeof(src) var = src; var; var = var->next) { \ - *__next = GC_MALLOC(sizeof(__typeof(*(src)))); \ - **__next = *var; \ - **__next = (__typeof(*(src))){__VA_ARGS__}; \ - __next = &((*__next)->next); \ - } \ - __mapped; }) - - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 -- cgit v1.2.3