diff options
44 files changed, 561 insertions, 555 deletions
@@ -1,28 +1,32 @@ PREFIX=/usr VERSION=0.0.1 -CCONFIG=-std=c11 -Werror -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -fPIC -I. \ +CC=gcc +CCONFIG=-std=c23 -Werror -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -fPIC -I. \ -fsanitize=signed-integer-overflow -fno-sanitize-recover -fvisibility=hidden -fdollars-in-identifiers LTO=-flto=auto -fno-fat-lto-objects -Wl,-flto LDFLAGS= # MAKEFLAGS := --jobs=$(shell nproc) --output-sync=target -CWARN=-Wall -Wextra -Wno-format -Wshadow - # -Wpedantic -Wsign-conversion -Wtype-limits -Wunused-result -Wnull-dereference \ - # -Waggregate-return -Walloc-zero -Walloca -Warith-conversion -Wcast-align -Wcast-align=strict \ - # -Wdangling-else -Wdate-time -Wdisabled-optimization -Wdouble-promotion -Wduplicated-branches \ - # -Wduplicated-cond -Wexpansion-to-defined -Wfloat-conversion -Wfloat-equal -Wformat-nonliteral \ - # -Wformat-security -Wformat-signedness -Wframe-address -Winline -Winvalid-pch -Wjump-misses-init \ - # -Wlogical-op -Wlong-long -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn \ - # -Wnull-dereference -Woverlength-strings -Wpacked -Wpacked-not-aligned -Wpointer-arith \ - # -Wredundant-decls -Wshadow -Wshadow=compatible-local -Wshadow=global -Wshadow=local \ - # -Wsign-conversion -Wstack-protector -Wsuggest-attribute=const -Wswitch-default -Wswitch-enum \ - # -Wsync-nand -Wtrampolines -Wundef -Wunsuffixed-float-constants -Wunused -Wunused-but-set-variable \ - # -Wunused-const-variable -Wunused-local-typedefs -Wunused-macros -Wvariadic-macros -Wvector-operation-performance \ - # -Wvla -Wwrite-strings +CWARN=-Wall -Wextra -Wno-format -Wshadow \ + -Wpedantic \ + -Wno-pointer-arith \ + -Wsign-conversion -Wtype-limits -Wunused-result -Wnull-dereference \ + -Walloc-zero -Walloca -Warith-conversion -Wcast-align -Wcast-align=strict \ + -Wdangling-else -Wdate-time -Wdisabled-optimization -Wdouble-promotion -Wduplicated-branches \ + -Wduplicated-cond -Wexpansion-to-defined -Wfloat-equal \ + -Wframe-address -Winline -Winvalid-pch -Wjump-misses-init \ + -Wlogical-op -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn \ + -Wnull-dereference -Woverlength-strings -Wpacked -Wpacked-not-aligned \ + -Wredundant-decls -Wshadow -Wshadow=compatible-local -Wshadow=global -Wshadow=local \ + -Wsign-conversion -Wstack-protector -Wsuggest-attribute=const -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wswitch-default \ + -Wsync-nand -Wtrampolines -Wundef -Wunused -Wunused-but-set-variable \ + -Wunused-const-variable -Wunused-local-typedefs -Wunused-macros -Wvariadic-macros -Wvector-operation-performance \ + -Wwrite-strings OSFLAGS != case $$(uname -s) in *BSD|Darwin) echo '-D_BSD_SOURCE';; Linux) echo '-D_GNU_SOURCE';; *) echo '-D_DEFAULT_SOURCE';; esac EXTRA= G=-ggdb O=-Og CFLAGS=$(CCONFIG) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) +CFLAGS_PLACEHOLDER="$$(echo -e '\033[2m<flags...>\033[m')" LDLIBS=-lgc -lcord -lm -lunistring -lgmp -ldl BUILTIN_OBJS=builtins/siphash.o builtins/array.o builtins/bool.o builtins/channel.o builtins/nums.o builtins/functions.o builtins/integers.o \ builtins/pointer.o builtins/memory.o builtins/text.o builtins/thread.o builtins/c_string.o builtins/table.o \ @@ -32,16 +36,19 @@ TESTS=$(patsubst %.tm,%.tm.testresult,$(wildcard test/*.tm)) all: libtomo.so tomo tomo: tomo.o $(BUILTIN_OBJS) ast.o parse.o environment.o types.o typecheck.o structs.o enums.o compile.o repl.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ + @echo $(CC) $(CFLAGS_PLACEHOLDER) $(LDFLAGS) $^ $(LDLIBS) -o $@ + @$(CC) $(CFLAGS) $(CWARN) $(LDFLAGS) $^ $(LDLIBS) -o $@ libtomo.so: $(BUILTIN_OBJS) - $(CC) $^ $(CFLAGS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) -lgc -lcord -lm -lunistring -lgmp -ldl -Wl,-soname,libtomo.so -shared -o $@ + @echo $(CC) $^ $(CFLAGS_PLACEHOLDER) $(G) $(O) $(OSFLAGS) -lgc -lcord -lm -lunistring -lgmp -ldl -Wl,-soname,libtomo.so -shared -o $@ + @$(CC) $^ $(CFLAGS) $(CWARN) $(G) $(O) $(OSFLAGS) -lgc -lcord -lm -lunistring -lgmp -ldl -Wl,-soname,libtomo.so -shared -o $@ tags: ctags *.[ch] **/*.[ch] %.o: %.c ast.h environment.h types.h - $(CC) $(CFLAGS) -c $< -o $@ + @echo $(CC) $(CFLAGS_PLACEHOLDER) -c $< -o $@ + @$(CC) $(CFLAGS) $(CWARN) -c $< -o $@ %.tm.testresult: %.tm tomo @printf '\x1b[33;1;4m%s\x1b[m\n' $< @@ -57,7 +64,7 @@ test: $(TESTS) clean: rm -f tomo *.o builtins/*.o libtomo.so test/*.tm.{c,h,o,testresult} examples/*.tm.*{c,h,o} -%.1: %.1.md +%: %.md pandoc --lua-filter=.pandoc/bold-code.lua -s $< -t man -o $@ install: tomo libtomo.so tomo.1 @@ -155,9 +155,9 @@ CORD ast_to_xml(ast_t *ast) T(Use, "<Use>%r</Use>", xml_escape(data.path)) T(LinkerDirective, "<LinkerDirective>%r</LinkerDirective>", xml_escape(data.directive)) T(InlineCCode, "<InlineCode>%r</InlineCode>", xml_escape(data.code)) + default: return "???"; #undef T } - return "???"; } CORD type_ast_to_xml(type_ast_t *t) @@ -176,8 +176,8 @@ CORD type_ast_to_xml(type_ast_t *t) T(TableTypeAST, "<TableType>%r %r</TableType>", type_ast_to_xml(data.key), type_ast_to_xml(data.value)) T(FunctionTypeAST, "<FunctionType>%r %r</FunctionType>", arg_list_to_xml(data.args), type_ast_to_xml(data.ret)) #undef T + default: return CORD_EMPTY; } - return NULL; } int printf_ast(FILE *stream, const struct printf_info *info, const void *const args[]) @@ -193,7 +193,7 @@ int printf_ast(FILE *stream, const struct printf_info *info, const void *const a } } -bool is_idempotent(ast_t *ast) +PUREFUNC bool is_idempotent(ast_t *ast) { switch (ast->tag) { case Int: case Bool: case Num: case Var: case Nil: case TextLiteral: return true; @@ -209,46 +209,4 @@ bool is_idempotent(ast_t *ast) } } -bool type_ast_eq(type_ast_t *x, type_ast_t *y) -{ - if (x->tag != y->tag) return false; - switch (x->tag) { - case UnknownTypeAST: return true; - case VarTypeAST: return streq(Match(x, VarTypeAST)->name, Match(y, VarTypeAST)->name); - case PointerTypeAST: { - auto x_info = Match(x, PointerTypeAST); - auto y_info = Match(y, PointerTypeAST); - return (x_info->is_optional == y_info->is_optional - && x_info->is_stack == y_info->is_stack - && x_info->is_readonly == y_info->is_readonly - && type_ast_eq(x_info->pointed, y_info->pointed)); - } - case ArrayTypeAST: return type_ast_eq(Match(x, ArrayTypeAST)->item, Match(y, ArrayTypeAST)->item); - case SetTypeAST: return type_ast_eq(Match(x, SetTypeAST)->item, Match(y, SetTypeAST)->item); - case ChannelTypeAST: return type_ast_eq(Match(x, ChannelTypeAST)->item, Match(y, ChannelTypeAST)->item); - case TableTypeAST: { - auto tx = Match(x, TableTypeAST); - auto ty = Match(y, TableTypeAST); - return type_ast_eq(tx->key, ty->key) && type_ast_eq(tx->value, ty->value); - } - case FunctionTypeAST: { - auto x_fn = Match(x, FunctionTypeAST); - auto y_fn = Match(y, FunctionTypeAST); - if (!type_ast_eq(x_fn->ret, y_fn->ret)) - return false; - for (arg_ast_t *x_arg = x_fn->args, *y_arg = y_fn->args; x_arg || y_arg; x_arg = x_arg->next, y_arg = y_arg->next) { - if (!x_arg || !y_arg) return false; - if (!x_arg->type) - errx(1, "I can't compare function types that don't have all explicitly typed args"); - if (!y_arg->type) - errx(1, "I can't compare function types that don't have all explicitly typed args"); - if (!type_ast_eq(x_arg->type, y_arg->type)) - return false; - } - return true; - } - } - return true; -} - // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -76,6 +76,7 @@ struct type_ast_s { file_t *file; const char *start, *end; union { +#pragma GCC diagnostic ignored "-Wpedantic" struct {} UnknownTypeAST; struct { const char *name; @@ -308,6 +309,6 @@ CORD ast_to_xml(ast_t *ast); CORD type_ast_to_xml(type_ast_t *ast); int printf_ast(FILE *stream, const struct printf_info *info, const void *const args[]); ast_list_t *get_ast_children(ast_t *ast); -bool is_idempotent(ast_t *ast); +PUREFUNC bool is_idempotent(ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/array.c b/builtins/array.c index f09af917..a6786e0f 100644 --- a/builtins/array.c +++ b/builtins/array.c @@ -22,7 +22,7 @@ #include "siphash.h" #include "siphash-internals.h" -static inline int64_t get_padded_item_size(const TypeInfo *info) +PUREFUNC static inline int64_t get_padded_item_size(const TypeInfo *info) { int64_t size = info->ArrayInfo.item->size; if (info->ArrayInfo.item->align > 1 && size % info->ArrayInfo.item->align) @@ -36,12 +36,13 @@ public void Array$compact(Array_t *arr, int64_t padded_item_size) { void *copy = NULL; if (arr->length > 0) { - copy = arr->atomic ? GC_MALLOC_ATOMIC(arr->length * padded_item_size) : GC_MALLOC(arr->length * padded_item_size); + copy = arr->atomic ? GC_MALLOC_ATOMIC((size_t)arr->length * (size_t)padded_item_size) + : GC_MALLOC((size_t)arr->length * (size_t)padded_item_size); if ((int64_t)arr->stride == padded_item_size) { - memcpy(copy, arr->data, arr->length * padded_item_size); + memcpy(copy, arr->data, (size_t)arr->length * (size_t)padded_item_size); } else { for (int64_t i = 0; i < arr->length; i++) - memcpy(copy + i*padded_item_size, arr->data + arr->stride*i, padded_item_size); + memcpy(copy + i*padded_item_size, arr->data + arr->stride*i, (size_t)padded_item_size); } } *arr = (Array_t){ @@ -63,15 +64,17 @@ public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_ if (!arr->data) { arr->free = 4; - arr->data = arr->atomic ? GC_MALLOC_ATOMIC(arr->free * padded_item_size) : GC_MALLOC(arr->free * padded_item_size); + arr->data = arr->atomic ? GC_MALLOC_ATOMIC((size_t)arr->free * (size_t)padded_item_size) + : GC_MALLOC((size_t)arr->free * (size_t)padded_item_size); arr->stride = padded_item_size; } else if (arr->free < 1 || arr->data_refcount != 0 || (int64_t)arr->stride != padded_item_size) { arr->free = MIN(ARRAY_MAX_FREE_ENTRIES, MAX(8, arr->length/4)); - void *copy = arr->atomic ? GC_MALLOC_ATOMIC((arr->length + arr->free) * padded_item_size) : GC_MALLOC((arr->length + arr->free) * padded_item_size); + void *copy = arr->atomic ? GC_MALLOC_ATOMIC((size_t)(arr->length + arr->free) * (size_t)padded_item_size) + : GC_MALLOC((size_t)(arr->length + arr->free) * (size_t)padded_item_size); for (int64_t i = 0; i < index-1; i++) - memcpy(copy + i*padded_item_size, arr->data + arr->stride*i, padded_item_size); + memcpy(copy + i*padded_item_size, arr->data + arr->stride*i, (size_t)padded_item_size); for (int64_t i = index-1; i < (int64_t)arr->length; i++) - memcpy(copy + (i+1)*padded_item_size, arr->data + arr->stride*i, padded_item_size); + memcpy(copy + (i+1)*padded_item_size, arr->data + arr->stride*i, (size_t)padded_item_size); arr->data = copy; arr->data_refcount = 0; arr->stride = padded_item_size; @@ -80,12 +83,12 @@ public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_ memmove( arr->data + index*padded_item_size, arr->data + (index-1)*padded_item_size, - (arr->length - index + 1)*padded_item_size); + (size_t)((arr->length - index + 1)*padded_item_size)); } assert(arr->free > 0); --arr->free; ++arr->length; - memcpy((void*)arr->data + (index-1)*padded_item_size, item, padded_item_size); + memcpy((void*)arr->data + (index-1)*padded_item_size, item, (size_t)padded_item_size); } public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, int64_t padded_item_size) @@ -115,43 +118,43 @@ public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, i if (index != arr->length+1) memmove((void*)arr->data + index*padded_item_size, arr->data + (index-1)*padded_item_size, - (arr->length - index + to_insert.length-1)*padded_item_size); + (size_t)((arr->length - index + to_insert.length-1)*padded_item_size)); for (int64_t i = 0; i < to_insert.length; i++) memcpy((void*)arr->data + (index-1 + i)*padded_item_size, - to_insert.data + i*to_insert.stride, padded_item_size); + to_insert.data + i*to_insert.stride, (size_t)padded_item_size); } else { // Otherwise, allocate a new chunk of memory for the array and populate it: int64_t new_len = arr->length + to_insert.length; arr->free = MIN(ARRAY_MAX_FREE_ENTRIES, MAX(8, new_len/4)); - void *data = arr->atomic ? GC_MALLOC_ATOMIC((new_len + arr->free) * padded_item_size) - : GC_MALLOC((new_len + arr->free) * padded_item_size); + void *data = arr->atomic ? GC_MALLOC_ATOMIC((size_t)((new_len + arr->free) * padded_item_size)) + : GC_MALLOC((size_t)((new_len + arr->free) * padded_item_size)); void *p = data; // Copy first chunk of `arr` if needed: if (index > 1) { if (arr->stride == padded_item_size) { - p = mempcpy(p, arr->data, (index-1)*padded_item_size); + p = mempcpy(p, arr->data, (size_t)((index-1)*padded_item_size)); } else { for (int64_t i = 0; i < index-1; i++) - p = mempcpy(p, arr->data + arr->stride*i, padded_item_size); + p = mempcpy(p, arr->data + arr->stride*i, (size_t)padded_item_size); } } // Copy `to_insert` if (to_insert.stride == padded_item_size) { - p = mempcpy(p, to_insert.data, to_insert.length*padded_item_size); + p = mempcpy(p, to_insert.data, (size_t)(to_insert.length*padded_item_size)); } else { for (int64_t i = 0; i < index-1; i++) - p = mempcpy(p, to_insert.data + to_insert.stride*i, padded_item_size); + p = mempcpy(p, to_insert.data + to_insert.stride*i, (size_t)padded_item_size); } // Copy last chunk of `arr` if needed: if (index < arr->length + 1) { if (arr->stride == padded_item_size) { - p = mempcpy(p, arr->data + padded_item_size*(index-1), (arr->length - index + 1)*padded_item_size); + p = mempcpy(p, arr->data + padded_item_size*(index-1), (size_t)((arr->length - index + 1)*padded_item_size)); } else { for (int64_t i = index-1; i < arr->length-1; i++) - p = mempcpy(p, arr->data + arr->stride*i, padded_item_size); + p = mempcpy(p, arr->data + arr->stride*i, (size_t)padded_item_size); } } arr->length = new_len; @@ -178,10 +181,11 @@ public void Array$remove_at(Array_t *arr, Int_t int_index, Int_t int_count, int6 if (arr->free >= 0) arr->free += count; } else if (arr->data_refcount != 0 || (int64_t)arr->stride != padded_item_size) { - void *copy = arr->atomic ? GC_MALLOC_ATOMIC((arr->length-1) * padded_item_size) : GC_MALLOC((arr->length-1) * padded_item_size); + void *copy = arr->atomic ? GC_MALLOC_ATOMIC((size_t)((arr->length-1) * padded_item_size)) + : GC_MALLOC((size_t)((arr->length-1) * padded_item_size)); for (int64_t src = 1, dest = 1; src <= (int64_t)arr->length; src++) { if (src < index || src >= index + count) { - memcpy(copy + (dest - 1)*padded_item_size, arr->data + arr->stride*(src - 1), padded_item_size); + memcpy(copy + (dest - 1)*padded_item_size, arr->data + arr->stride*(src - 1), (size_t)padded_item_size); ++dest; } } @@ -189,7 +193,8 @@ public void Array$remove_at(Array_t *arr, Int_t int_index, Int_t int_count, int6 arr->free = 0; arr->data_refcount = 0; } else { - memmove((void*)arr->data + (index-1)*padded_item_size, arr->data + (index-1 + count)*padded_item_size, (arr->length - index + count - 1)*padded_item_size); + memmove((void*)arr->data + (index-1)*padded_item_size, arr->data + (index-1 + count)*padded_item_size, + (size_t)((arr->length - index + count - 1)*padded_item_size)); arr->free += count; } arr->length -= count; @@ -241,16 +246,17 @@ public void Array$sort(Array_t *arr, closure_t comparison, int64_t padded_item_s if (arr->data_refcount != 0 || (int64_t)arr->stride != padded_item_size) Array$compact(arr, padded_item_size); - qsort_r(arr->data, arr->length, padded_item_size, comparison.fn, comparison.userdata); + qsort_r(arr->data, (size_t)arr->length, (size_t)padded_item_size, comparison.fn, comparison.userdata); } public Array_t Array$sorted(Array_t arr, closure_t comparison, int64_t padded_item_size) { Array$compact(&arr, padded_item_size); - qsort_r(arr.data, arr.length, padded_item_size, comparison.fn, comparison.userdata); + qsort_r(arr.data, (size_t)arr.length, (size_t)padded_item_size, comparison.fn, comparison.userdata); return arr; } +#pragma GCC diagnostic ignored "-Wstack-protector" public void Array$shuffle(Array_t *arr, int64_t padded_item_size) { if (arr->data_refcount != 0 || (int64_t)arr->stride != padded_item_size) @@ -259,9 +265,9 @@ public void Array$shuffle(Array_t *arr, int64_t padded_item_size) char tmp[padded_item_size]; for (int64_t i = arr->length-1; i > 1; i--) { int64_t j = arc4random_uniform(i+1); - memcpy(tmp, arr->data + i*padded_item_size, padded_item_size); - memcpy((void*)arr->data + i*padded_item_size, arr->data + j*padded_item_size, padded_item_size); - memcpy((void*)arr->data + j*padded_item_size, tmp, padded_item_size); + memcpy(tmp, arr->data + i*padded_item_size, (size_t)padded_item_size); + memcpy((void*)arr->data + i*padded_item_size, arr->data + j*padded_item_size, (size_t)padded_item_size); + memcpy((void*)arr->data + j*padded_item_size, tmp, (size_t)padded_item_size); } } @@ -301,7 +307,7 @@ public Array_t Array$sample(Array_t arr, Int_t int_n, Array_t weights, int64_t p return (Array_t){}; Array_t selected = { - .data=arr.atomic ? GC_MALLOC_ATOMIC(n * padded_item_size) : GC_MALLOC(n * padded_item_size), + .data=arr.atomic ? GC_MALLOC_ATOMIC((size_t)(n * padded_item_size)) : GC_MALLOC((size_t)(n * padded_item_size)), .length=n, .stride=padded_item_size, .atomic=arr.atomic}; @@ -324,7 +330,7 @@ public Array_t Array$sample(Array_t arr, Int_t int_n, Array_t weights, int64_t p if (total == 0.0) { for (int64_t i = 0; i < n; i++) { int64_t index = arc4random_uniform(arr.length); - memcpy(selected.data + i*padded_item_size, arr.data + arr.stride*index, padded_item_size); + memcpy(selected.data + i*padded_item_size, arr.data + arr.stride*index, (size_t)padded_item_size); } } else { double inverse_average = (double)arr.length / total; @@ -367,7 +373,7 @@ public Array_t Array$sample(Array_t arr, Int_t int_n, Array_t weights, int64_t p int64_t index = (int64_t)r; if ((r - (double)index) > aliases[index].odds) index = aliases[index].alias; - memcpy(selected.data + i*selected.stride, arr.data + index*arr.stride, padded_item_size); + memcpy(selected.data + i*selected.stride, arr.data + index*arr.stride, (size_t)padded_item_size); } } return selected; @@ -421,10 +427,10 @@ public Array_t Array$by(Array_t array, Int_t int_stride, int64_t padded_item_siz void *copy = NULL; int64_t len = (stride < 0 ? array.length / -stride : array.length / stride) + ((array.length % stride) != 0); if (len > 0) { - copy = array.atomic ? GC_MALLOC_ATOMIC(len * padded_item_size) : GC_MALLOC(len * padded_item_size); + copy = array.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size)) : GC_MALLOC((size_t)(len * padded_item_size)); void *start = (stride < 0 ? array.data + (array.stride * (array.length - 1)) : array.data); for (int64_t i = 0; i < len; i++) - memcpy(copy + i*padded_item_size, start + array.stride*stride*i, padded_item_size); + memcpy(copy + i*padded_item_size, start + array.stride*stride*i, (size_t)padded_item_size); } return (Array_t){ .data=copy, @@ -463,19 +469,20 @@ public Array_t Array$reversed(Array_t array, int64_t padded_item_size) public Array_t Array$concat(Array_t x, Array_t y, int64_t padded_item_size) { - void *data = x.atomic ? GC_MALLOC_ATOMIC(padded_item_size*(x.length + y.length)) : GC_MALLOC(padded_item_size*(x.length + y.length)); + void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size*(x.length + y.length))) + : GC_MALLOC((size_t)(padded_item_size*(x.length + y.length))); if (x.stride == padded_item_size) { - memcpy(data, x.data, padded_item_size*x.length); + memcpy(data, x.data, (size_t)(padded_item_size*x.length)); } else { for (int64_t i = 0; i < x.length; i++) - memcpy(data + i*padded_item_size, x.data + i*padded_item_size, padded_item_size); + memcpy(data + i*padded_item_size, x.data + i*padded_item_size, (size_t)padded_item_size); } if (y.stride == padded_item_size) { - memcpy(data + padded_item_size*x.length, y.data, padded_item_size*y.length); + memcpy(data + padded_item_size*x.length, y.data, (size_t)(padded_item_size*y.length)); } else { for (int64_t i = 0; i < x.length; i++) - memcpy(data + (x.length + i)*padded_item_size, y.data + i*padded_item_size, padded_item_size); + memcpy(data + (x.length + i)*padded_item_size, y.data + i*padded_item_size, (size_t)padded_item_size); } return (Array_t){ @@ -514,11 +521,11 @@ public int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo item_padded_size += type->ArrayInfo.item->align - (item_padded_size % type->ArrayInfo.item->align); // padding if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size && item->size == item_padded_size) { - int32_t cmp = (int32_t)memcmp(x->data, y->data, MIN(x->length, y->length)*item_padded_size); + int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length)*item_padded_size)); if (cmp != 0) return cmp; } else { for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) { - int32_t cmp = (int32_t)memcmp(x->data+ x->stride*i, y->data + y->stride*i, item->size); + int32_t cmp = (int32_t)memcmp(x->data+ x->stride*i, y->data + y->stride*i, (size_t)(item->size)); if (cmp != 0) return cmp; } } @@ -533,7 +540,7 @@ public int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo public bool Array$equal(const Array_t *x, const Array_t *y, const TypeInfo *type) { - return (Array$compare(x, y, type) == 0); + return x == y || (x->length == y->length && Array$compare(x, y, type) == 0); } public Text_t Array$as_text(const Array_t *arr, bool colorize, const TypeInfo *type) @@ -570,11 +577,12 @@ public uint64_t Array$hash(const Array_t *arr, const TypeInfo *type) return siphashfinish_last_part(&sh, 0); } +#pragma GCC diagnostic ignored "-Wstack-protector" static void siftdown(Array_t *heap, int64_t startpos, int64_t pos, closure_t comparison, int64_t padded_item_size) { assert(pos > 0 && pos < heap->length); char newitem[padded_item_size]; - memcpy(newitem, heap->data + heap->stride*pos, padded_item_size); + memcpy(newitem, heap->data + heap->stride*pos, (size_t)(padded_item_size)); while (pos > startpos) { int64_t parentpos = (pos - 1) >> 1; typedef int32_t (*cmp_fn_t)(void*, void*, void*); @@ -582,10 +590,10 @@ static void siftdown(Array_t *heap, int64_t startpos, int64_t pos, closure_t com if (cmp >= 0) break; - memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*parentpos, padded_item_size); + memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*parentpos, (size_t)(padded_item_size)); pos = parentpos; } - memcpy(heap->data + heap->stride*pos, newitem, padded_item_size); + memcpy(heap->data + heap->stride*pos, newitem, (size_t)(padded_item_size)); } static void siftup(Array_t *heap, int64_t pos, closure_t comparison, int64_t padded_item_size) @@ -595,7 +603,7 @@ static void siftup(Array_t *heap, int64_t pos, closure_t comparison, int64_t pad assert(pos < endpos); char old_top[padded_item_size]; - memcpy(old_top, heap->data + heap->stride*pos, padded_item_size); + memcpy(old_top, heap->data + heap->stride*pos, (size_t)(padded_item_size)); // Bubble up the smallest leaf node int64_t limit = endpos >> 1; while (pos < limit) { @@ -610,10 +618,10 @@ static void siftup(Array_t *heap, int64_t pos, closure_t comparison, int64_t pad } // Move the child node up: - memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*childpos, padded_item_size); + memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*childpos, (size_t)(padded_item_size)); pos = childpos; } - memcpy(heap->data + heap->stride*pos, old_top, padded_item_size); + memcpy(heap->data + heap->stride*pos, old_top, (size_t)(padded_item_size)); // Shift the node's parents down: siftdown(heap, startpos, pos, comparison, padded_item_size); } @@ -642,7 +650,7 @@ public void Array$heap_pop(Array_t *heap, closure_t comparison, int64_t padded_i } else { if (heap->data_refcount != 0) Array$compact(heap, padded_item_size); - memcpy(heap->data, heap->data + heap->stride*(heap->length-1), padded_item_size); + memcpy(heap->data, heap->data + heap->stride*(heap->length-1), (size_t)(padded_item_size)); --heap->length; siftup(heap, 0, comparison, padded_item_size); } diff --git a/builtins/array.h b/builtins/array.h index 98e949c8..99a892fc 100644 --- a/builtins/array.h +++ b/builtins/array.h @@ -80,16 +80,16 @@ Array_t Array$sample(Array_t arr, Int_t n, Array_t weights, int64_t padded_item_ Table_t Array$counts(Array_t arr, const TypeInfo *type); void Array$clear(Array_t *array); void Array$compact(Array_t *arr, int64_t padded_item_size); -bool Array$has(Array_t array, void *item, const TypeInfo *type); +PUREFUNC bool Array$has(Array_t array, void *item, const TypeInfo *type); #define Array$has_value(arr, item_expr, type) ({ __typeof(item_expr) item = item_expr; Array$has(arr, &item, type); }) -Array_t Array$from(Array_t array, Int_t first); -Array_t Array$to(Array_t array, Int_t last); -Array_t Array$by(Array_t array, Int_t stride, int64_t padded_item_size); -Array_t Array$reversed(Array_t array, int64_t padded_item_size); +PUREFUNC Array_t Array$from(Array_t array, Int_t first); +PUREFUNC Array_t Array$to(Array_t array, Int_t last); +PUREFUNC Array_t Array$by(Array_t array, Int_t stride, int64_t padded_item_size); +PUREFUNC Array_t Array$reversed(Array_t array, int64_t padded_item_size); Array_t Array$concat(Array_t x, Array_t y, int64_t padded_item_size); -uint64_t Array$hash(const Array_t *arr, const TypeInfo *type); -int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo *type); -bool Array$equal(const Array_t *x, const Array_t *y, const TypeInfo *type); +PUREFUNC uint64_t Array$hash(const Array_t *arr, const TypeInfo *type); +PUREFUNC int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo *type); +PUREFUNC bool Array$equal(const Array_t *x, const Array_t *y, const TypeInfo *type); Text_t Array$as_text(const Array_t *arr, bool colorize, const TypeInfo *type); void Array$heapify(Array_t *heap, closure_t comparison, int64_t padded_item_size); void Array$heap_push(Array_t *heap, const void *item, closure_t comparison, int64_t padded_item_size); diff --git a/builtins/bool.c b/builtins/bool.c index 677cfd97..63eb73f9 100644 --- a/builtins/bool.c +++ b/builtins/bool.c @@ -13,7 +13,7 @@ #include "types.h" #include "util.h" -public Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo *type) +PUREFUNC public Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo *type) { (void)type; if (!b) return Text("Bool"); diff --git a/builtins/bool.h b/builtins/bool.h index cf2237fd..5f222c49 100644 --- a/builtins/bool.h +++ b/builtins/bool.h @@ -7,12 +7,13 @@ #include <stdint.h> #include "types.h" +#include "util.h" #define Bool_t bool #define yes (Bool_t)true #define no (Bool_t)false -Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo *type); +PUREFUNC Text_t Bool$as_text(const bool *b, bool colorize, const TypeInfo *type); bool Bool$from_text(Text_t text, bool *success); Bool_t Bool$random(double p); diff --git a/builtins/c_string.c b/builtins/c_string.c index d916bfa9..3e3ef740 100644 --- a/builtins/c_string.c +++ b/builtins/c_string.c @@ -21,7 +21,7 @@ public Text_t CString$as_text(const void *c_string, bool colorize, const TypeInf return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), Text$quoted(text, colorize), Text(")")); } -public int32_t CString$compare(const char **x, const char **y) +PUREFUNC public int32_t CString$compare(const char **x, const char **y) { if (x == y) return 0; @@ -32,12 +32,12 @@ public int32_t CString$compare(const char **x, const char **y) return strcmp(*x, *y); } -public bool CString$equal(const char **x, const char **y) +PUREFUNC public bool CString$equal(const char **x, const char **y) { return CString$compare(x, y) == 0; } -public uint64_t CString$hash(const char **c_str) +PUREFUNC public uint64_t CString$hash(const char **c_str) { if (!*c_str) return 0; return siphash24((void*)*c_str, strlen(*c_str)); diff --git a/builtins/c_string.h b/builtins/c_string.h index 76c74c23..10621e62 100644 --- a/builtins/c_string.h +++ b/builtins/c_string.h @@ -9,9 +9,9 @@ #include "types.h" Text_t CString$as_text(const void *str, bool colorize, const TypeInfo *info); -int CString$compare(const char **x, const char **y); -bool CString$equal(const char **x, const char **y); -uint64_t CString$hash(const char **str); +PUREFUNC int CString$compare(const char **x, const char **y); +PUREFUNC bool CString$equal(const char **x, const char **y); +PUREFUNC uint64_t CString$hash(const char **str); extern const TypeInfo CString$info; diff --git a/builtins/channel.c b/builtins/channel.c index e877b6b5..b5868ee6 100644 --- a/builtins/channel.c +++ b/builtins/channel.c @@ -65,7 +65,7 @@ public void Channel$get(channel_t *channel, void *out, bool front, int64_t item_ (void)pthread_mutex_lock(&channel->mutex); while (channel->items.length == 0) pthread_cond_wait(&channel->cond, &channel->mutex); - memcpy(out, channel->items.data + channel->items.stride * (front ? 0 : channel->items.length-1), item_size); + memcpy(out, channel->items.data + channel->items.stride * (front ? 0 : channel->items.length-1), (size_t)(item_size)); Int_t index = front ? I_small(1) : Int64_to_Int(channel->items.length); Array$remove_at(&channel->items, index, I_small(1), padded_item_size); (void)pthread_mutex_unlock(&channel->mutex); @@ -78,7 +78,7 @@ public void Channel$peek(channel_t *channel, void *out, bool front, int64_t item while (channel->items.length == 0) pthread_cond_wait(&channel->cond, &channel->mutex); int64_t index = front ? 0 : channel->items.length-1; - memcpy(out, channel->items.data + channel->items.stride*index, item_size); + memcpy(out, channel->items.data + channel->items.stride*index, (size_t)(item_size)); (void)pthread_mutex_unlock(&channel->mutex); (void)pthread_cond_signal(&channel->cond); } @@ -106,13 +106,13 @@ public uint64_t Channel$hash(const channel_t **channel, const TypeInfo *type) return siphash24((void*)*channel, sizeof(channel_t*)); } -public int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type) +PUREFUNC public int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type) { (void)type; return (*x > *y) - (*x < *y); } -bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type) +PUREFUNC bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type) { (void)type; return (*x == *y); diff --git a/builtins/channel.h b/builtins/channel.h index 89711045..5eaf2a19 100644 --- a/builtins/channel.h +++ b/builtins/channel.h @@ -21,9 +21,9 @@ void Channel$peek(channel_t *channel, void *out, bool front, int64_t item_size); #define Channel$peek_value(channel, front, t) ({ t _val; Channel$peek(channel, &_val, front, sizeof(t)); _val; }) void Channel$clear(channel_t *channel); Array_t Channel$view(channel_t *channel); -uint64_t Channel$hash(const channel_t **channel, const TypeInfo *type); -int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type); -bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type); +PUREFUNC uint64_t Channel$hash(const channel_t **channel, const TypeInfo *type); +PUREFUNC int32_t Channel$compare(const channel_t **x, const channel_t **y, const TypeInfo *type); +PUREFUNC bool Channel$equal(const channel_t **x, const channel_t **y, const TypeInfo *type); Text_t Channel$as_text(const channel_t **channel, bool colorize, const TypeInfo *type); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/datatypes.h b/builtins/datatypes.h index f7cc23ee..aa7670b7 100644 --- a/builtins/datatypes.h +++ b/builtins/datatypes.h @@ -47,7 +47,7 @@ typedef struct { typedef struct { uint32_t count:31, last_free:31; uint8_t data_refcount:2; - bucket_t buckets[0]; + bucket_t buckets[]; } bucket_info_t; typedef struct table_s { diff --git a/builtins/files.c b/builtins/files.c index dc91d0b0..6ff3f988 100644 --- a/builtins/files.c +++ b/builtins/files.c @@ -94,8 +94,8 @@ static file_t *_load_file(const char* filename, FILE *file) while ((line_len = getline(&line_buf, &line_cap, file)) >= 0) { if (ret->line_capacity <= ret->num_lines) ret->line_offsets = GC_REALLOC(ret->line_offsets, sizeof(int64_t[ret->line_capacity += 32])); - ret->line_offsets[ret->num_lines++] = file_size; - fwrite(line_buf, sizeof(char), line_len, mem); + ret->line_offsets[ret->num_lines++] = (int64_t)file_size; + fwrite(line_buf, sizeof(char), (size_t)line_len, mem); fflush(mem); } fclose(file); @@ -104,7 +104,7 @@ static file_t *_load_file(const char* filename, FILE *file) memcpy(copy, file_buf, file_size); copy[file_size] = '\0'; ret->text = copy; - ret->len = file_size; + ret->len = (int64_t)file_size; fclose(mem); free(file_buf); @@ -114,7 +114,7 @@ static file_t *_load_file(const char* filename, FILE *file) // Convert to relative path (if applicable) char buf[PATH_MAX]; char *cwd = getcwd(buf, sizeof(buf)); - int64_t cwd_len = strlen(cwd); + size_t cwd_len = strlen(cwd); if (strncmp(cwd, filename, cwd_len) == 0 && filename[cwd_len] == '/') ret->relative_filename = &filename[cwd_len+1]; } diff --git a/builtins/functions.c b/builtins/functions.c index 93c4abff..b4e1a5cc 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -63,7 +63,8 @@ void print_stack_trace(FILE *out, int start, int stop) fflush(out); } -public void fail(const char *fmt, ...) +__attribute__((format(printf, 1, 2))) +public _Noreturn void fail(const char *fmt, ...) { fflush(stdout); if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); @@ -77,9 +78,11 @@ public void fail(const char *fmt, ...) print_stack_trace(stderr, 2, 4); fflush(stderr); raise(SIGABRT); + _exit(1); } -public void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...) +__attribute__((format(printf, 4, 5))) +public _Noreturn void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...) { if (USE_COLOR) fputs("\n\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); else fputs("\n==================== ERROR ====================\n\n", stderr); @@ -100,9 +103,10 @@ public void fail_source(const char *filename, int64_t start, int64_t end, const print_stack_trace(stderr, 2, 4); fflush(stderr); raise(SIGABRT); + _exit(1); } -public uint64_t generic_hash(const void *obj, const TypeInfo *type) +PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo *type) { switch (type->tag) { case TextInfo: return Text$hash((void*)obj); @@ -114,14 +118,14 @@ public uint64_t generic_hash(const void *obj, const TypeInfo *type) if (!type->CustomInfo.hash) goto hash_data; return type->CustomInfo.hash(obj, type); - default: { + case PointerInfo: case FunctionInfo: case TypeInfoInfo: case OpaqueInfo: default: { hash_data:; - return siphash24((void*)obj, type->size); + return siphash24((void*)obj, (size_t)(type->size)); } } } -public int32_t generic_compare(const void *x, const void *y, const TypeInfo *type) +PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo *type) { if (x == y) return 0; @@ -136,13 +140,13 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ if (!type->CustomInfo.compare) goto compare_data; return type->CustomInfo.compare(x, y, type); - default: + case TypeInfoInfo: case OpaqueInfo: default: compare_data: - return (int32_t)memcmp((void*)x, (void*)y, type->size); + return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size)); } } -public bool generic_equal(const void *x, const void *y, const TypeInfo *type) +PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo *type) { if (x == y) return true; @@ -157,7 +161,7 @@ public bool generic_equal(const void *x, const void *y, const TypeInfo *type) if (!type->CustomInfo.equal) goto use_generic_compare; return type->CustomInfo.equal(x, y, type); - default: + case TypeInfoInfo: case OpaqueInfo: default: use_generic_compare: return (generic_compare(x, y, type) == 0); } @@ -180,6 +184,7 @@ public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo *ty if (!type->CustomInfo.as_text) fail("No text function provided for type!\n"); return type->CustomInfo.as_text(obj, colorize, type); + case OpaqueInfo: return Text("???"); default: errx(1, "Invalid type tag: %d", type->tag); } } @@ -270,6 +275,11 @@ public Text_t ask(Text_t prompt, bool bold, bool force_tty) FILE *out = stdout; FILE *in = stdin; + char *line = NULL; + size_t bufsize = 0; + ssize_t length = 0; + char *gc_input = NULL; + if (force_tty && !isatty(STDOUT_FILENO)) { out = fopen("/dev/tty", "w"); if (!out) goto cleanup; @@ -288,9 +298,7 @@ public Text_t ask(Text_t prompt, bool bold, bool force_tty) } } - char *line = NULL; - size_t bufsize = 0; - ssize_t length = getline(&line, &bufsize, in); + length = getline(&line, &bufsize, in); if (length == -1) { fputs("\n", out); // finish the line, since we didn't get any input goto cleanup; @@ -301,10 +309,10 @@ public Text_t ask(Text_t prompt, bool bold, bool force_tty) --length; } - char *gc_input = GC_MALLOC_ATOMIC(length + 1); - memcpy(gc_input, line, length + 1); + gc_input = GC_MALLOC_ATOMIC((size_t)(length + 1)); + memcpy(gc_input, line, (size_t)(length + 1)); - ret = Text$from_strn(gc_input, length); + ret = Text$from_strn(gc_input, (size_t)(length)); cleanup: if (out && out != stdout) fclose(out); diff --git a/builtins/functions.h b/builtins/functions.h index cc1f5a81..f258a20d 100644 --- a/builtins/functions.h +++ b/builtins/functions.h @@ -8,10 +8,13 @@ #include "datatypes.h" #include "types.h" +#include "util.h" void tomo_init(void); -void fail(const char *fmt, ...); -void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...); +__attribute__((format(printf, 1, 2))) +_Noreturn void fail(const char *fmt, ...); +__attribute__((format(printf, 4, 5))) +_Noreturn void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...); Text_t builtin_last_err(); void start_test(const char *filename, int64_t start, int64_t end); void end_test(const void *expr, const TypeInfo *type, const char *expected, const char *filename, int64_t start, int64_t end); @@ -22,9 +25,9 @@ void say(Text_t text, bool newline); Text_t ask(Text_t prompt, bool bold, bool force_tty); _Noreturn void tomo_exit(Text_t text, int32_t status); -uint64_t generic_hash(const void *obj, const TypeInfo *type); -int32_t generic_compare(const void *x, const void *y, const TypeInfo *type); -bool generic_equal(const void *x, const void *y, const TypeInfo *type); +PUREFUNC uint64_t generic_hash(const void *obj, const TypeInfo *type); +PUREFUNC int32_t generic_compare(const void *x, const void *y, const TypeInfo *type); +PUREFUNC bool generic_equal(const void *x, const void *y, const TypeInfo *type); Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo *type); int generic_print(const void *obj, bool colorize, const TypeInfo *type); closure_t spawn(closure_t fn); diff --git a/builtins/integers.c b/builtins/integers.c index 523ec4d1..31e32f3d 100644 --- a/builtins/integers.c +++ b/builtins/integers.c @@ -36,29 +36,29 @@ public Text_t Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type) { } } -public int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo *type) { +public PUREFUNC int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo *type) { (void)type; if (__builtin_expect(((x->small | y->small) & 1) == 0, 0)) return x->big == y->big ? 0 : mpz_cmp(*x->big, *y->big); return (x->small > y->small) - (x->small < y->small); } -public int32_t Int$compare_value(const Int_t x, const Int_t y) { +public PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) { if (__builtin_expect(((x.small | y.small) & 1) == 0, 0)) return x.big == y.big ? 0 : mpz_cmp(*x.big, *y.big); return (x.small > y.small) - (x.small < y.small); } -public bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo *type) { +public PUREFUNC bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo *type) { (void)type; return x->small == y->small || (__builtin_expect(((x->small | y->small) & 1) == 0, 0) && mpz_cmp(*x->big, *y->big) == 0); } -public bool Int$equal_value(const Int_t x, const Int_t y) { +public PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) { return x.small == y.small || (__builtin_expect(((x.small | y.small) & 1) == 0, 0) && mpz_cmp(*x.big, *y.big) == 0); } -public uint64_t Int$hash(const Int_t *x, const TypeInfo *type) { +public PUREFUNC uint64_t Int$hash(const Int_t *x, const TypeInfo *type) { (void)type; if (__builtin_expect(x->small & 1, 1)) { int64_t i = (x->small>>2); @@ -81,8 +81,8 @@ public Text_t Int$format(Int_t i, Int_t digits_int) if (needed_zeroes <= 0) return Text$from_str(str); - char *zeroes = GC_MALLOC_ATOMIC(needed_zeroes); - memset(zeroes, '0', needed_zeroes); + char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes)); + memset(zeroes, '0', (size_t)(needed_zeroes)); if (negative) return Text$concat(Text("-"), Text$from_str(zeroes), Text$from_str(str + 1)); else @@ -108,8 +108,8 @@ public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0x"), Text$from_str(str)) : Text$from_str(str); - char *zeroes = GC_MALLOC_ATOMIC(needed_zeroes); - memset(zeroes, '0', needed_zeroes); + char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes)); + memset(zeroes, '0', (size_t)(needed_zeroes)); if (prefix) return Text$concat(Text("0x"), Text$from_str(zeroes), Text$from_str(str)); else @@ -131,8 +131,8 @@ public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) { if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0o"), Text$from_str(str)) : Text$from_str(str); - char *zeroes = GC_MALLOC_ATOMIC(needed_zeroes); - memset(zeroes, '0', needed_zeroes); + char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes)); + memset(zeroes, '0', (size_t)(needed_zeroes)); if (prefix) return Text$concat(Text("0o"), Text$from_str(zeroes), Text$from_str(str)); else @@ -302,7 +302,7 @@ public Int_t Int$power(Int_t base, Int_t exponent) fail("Cannot take a negative power of an integer!"); mpz_t result; mpz_init_set_int(result, base); - mpz_pow_ui(result, result, exp); + mpz_pow_ui(result, result, (uint64_t)exp); return Int$from_mpz(result); } @@ -339,7 +339,7 @@ public Int_t Int$random(Int_t min, Int_t max) { return Int$plus(min, Int$from_mpz(r)); } -public Range_t Int$to(Int_t from, Int_t to) { +public PUREFUNC Range_t Int$to(Int_t from, Int_t to) { return (Range_t){from, to, Int$compare_value(to, from) >= 0 ? (Int_t){.small=(1<<2)|1} : (Int_t){.small=(-1>>2)|1}}; } @@ -409,11 +409,11 @@ public const TypeInfo Int$info = { if (!i) return Text(#KindOfInt); \ return Text$format(colorize ? "\x1b[35m%" fmt "\x1b[m" : "%" fmt, *i); \ } \ - public int32_t KindOfInt ## $compare(const c_type *x, const c_type *y, const TypeInfo *type) { \ + public PUREFUNC int32_t KindOfInt ## $compare(const c_type *x, const c_type *y, const TypeInfo *type) { \ (void)type; \ return (*x > *y) - (*x < *y); \ } \ - public bool KindOfInt ## $equal(const c_type *x, const c_type *y, const TypeInfo *type) { \ + public PUREFUNC bool KindOfInt ## $equal(const c_type *x, const c_type *y, const TypeInfo *type) { \ (void)type; \ return *x == *y; \ } \ @@ -458,7 +458,7 @@ public const TypeInfo Int$info = { public Range_t KindOfInt ## $to(c_type from, c_type to) { \ return (Range_t){Int64_to_Int(from), Int64_to_Int(to), to >= from ? (Int_t){.small=(1<<2)&1} : (Int_t){.small=(1<<2)&1}}; \ } \ - public c_type KindOfInt ## $from_text(Text_t text, bool *success) { \ + public PUREFUNC c_type KindOfInt ## $from_text(Text_t text, bool *success) { \ bool parsed_int = false; \ Int_t full_int = Int$from_text(text, &parsed_int); \ if (!parsed_int && success) *success = false; \ @@ -482,10 +482,10 @@ public const TypeInfo Int$info = { .CustomInfo={.compare=(void*)KindOfInt##$compare, .as_text=(void*)KindOfInt##$as_text}, \ }; -DEFINE_INT_TYPE(int64_t, Int64, "ld_i64", INT64_MIN, INT64_MAX); -DEFINE_INT_TYPE(int32_t, Int32, "d_i32", INT32_MIN, INT32_MAX); -DEFINE_INT_TYPE(int16_t, Int16, "d_i16", INT16_MIN, INT16_MAX); -DEFINE_INT_TYPE(int8_t, Int8, "d_i8", INT8_MIN, INT8_MAX); +DEFINE_INT_TYPE(int64_t, Int64, "ld_i64", INT64_MIN, INT64_MAX) +DEFINE_INT_TYPE(int32_t, Int32, "d_i32", INT32_MIN, INT32_MAX) +DEFINE_INT_TYPE(int16_t, Int16, "d_i16", INT16_MIN, INT16_MAX) +DEFINE_INT_TYPE(int8_t, Int8, "d_i8", INT8_MIN, INT8_MAX) #undef DEFINE_INT_TYPE // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/builtins/integers.h b/builtins/integers.h index e5765de3..e69914c8 100644 --- a/builtins/integers.h +++ b/builtins/integers.h @@ -25,16 +25,16 @@ #define DEFINE_INT_TYPE(c_type, type_name) \ Text_t type_name ## $as_text(const c_type *i, bool colorize, const TypeInfo *type); \ - int32_t type_name ## $compare(const c_type *x, const c_type *y, const TypeInfo *type); \ - bool type_name ## $equal(const c_type *x, const c_type *y, const TypeInfo *type); \ + PUREFUNC int32_t type_name ## $compare(const c_type *x, const c_type *y, const TypeInfo *type); \ + PUREFUNC bool type_name ## $equal(const c_type *x, const c_type *y, const TypeInfo *type); \ Text_t type_name ## $format(c_type i, Int_t digits); \ Text_t type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \ Text_t type_name ## $octal(c_type i, Int_t digits, bool prefix); \ Array_t type_name ## $bits(c_type x); \ c_type type_name ## $random(c_type min, c_type max); \ Range_t type_name ## $to(c_type from, c_type to); \ - c_type type_name ## $from_text(Text_t text, bool *success); \ - static inline c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \ + PUREFUNC c_type type_name ## $from_text(Text_t text, bool *success); \ + PUREFUNC static inline c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \ return x < min ? min : (x > max ? max : x); \ } \ extern const c_type type_name ## $min, type_name##$max; \ @@ -59,10 +59,10 @@ return type_name ## $modulo(D-1, d) + 1; \ } -DEFINE_INT_TYPE(int64_t, Int64); -DEFINE_INT_TYPE(int32_t, Int32); -DEFINE_INT_TYPE(int16_t, Int16); -DEFINE_INT_TYPE(int8_t, Int8); +DEFINE_INT_TYPE(int64_t, Int64) +DEFINE_INT_TYPE(int32_t, Int32) +DEFINE_INT_TYPE(int16_t, Int16) +DEFINE_INT_TYPE(int8_t, Int8) #undef DEFINE_INT_TYPE #define Int64$abs(...) I64(labs(__VA_ARGS__)) @@ -71,17 +71,17 @@ DEFINE_INT_TYPE(int8_t, Int8); #define Int8$abs(...) I8(abs(__VA_ARGS__)) Text_t Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type); -uint64_t Int$hash(const Int_t *x, const TypeInfo *type); -int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo *type); -int32_t Int$compare_value(const Int_t x, const Int_t y); -bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo *type); -bool Int$equal_value(const Int_t x, const Int_t y); +PUREFUNC uint64_t Int$hash(const Int_t *x, const TypeInfo *type); +PUREFUNC int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo *type); +PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y); +PUREFUNC bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo *type); +PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y); Text_t Int$format(Int_t i, Int_t digits); Text_t Int$hex(Int_t i, Int_t digits, bool uppercase, bool prefix); Text_t Int$octal(Int_t i, Int_t digits, bool prefix); void Int$init_random(long seed); Int_t Int$random(Int_t min, Int_t max); -Range_t Int$to(Int_t from, Int_t to); +PUREFUNC Range_t Int$to(Int_t from, Int_t to); Int_t Int$from_str(const char *str, bool *success); Int_t Int$from_text(Text_t text, bool *success); Int_t Int$abs(Int_t x); @@ -91,20 +91,18 @@ Int_t Int$sqrt(Int_t i); #define BIGGEST_SMALL_INT ((1<<29)-1) #define Int$from_mpz(mpz) (\ - mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ({ \ - (Int_t){.small=(mpz_get_si(mpz)<<2)|1}; \ - }) : ({ \ - mpz_t *result_obj = new(mpz_t); \ - memcpy(result_obj, &mpz, sizeof(mpz_t)); \ - (Int_t){.big=result_obj}; \ - })) + mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ( \ + (Int_t){.small=(mpz_get_si(mpz)<<2)|1} \ + ) : ( \ + (Int_t){.big=memcpy(new(mpz_t), &mpz, sizeof(mpz_t))} \ + )) #define mpz_init_set_int(mpz, i) do { \ if (__builtin_expect((i).small & 1, 1)) mpz_init_set_si(mpz, (i).small >> 2); \ else mpz_init_set(mpz, *(i).big); \ } while (0) -#define I(i) ((int64_t)(i) == (int32_t)(i) ? ((Int_t){.small=((uint64_t)(i)<<2)|1}) : Int64_to_Int(i)) +#define I(i) ((int64_t)(i) == (int32_t)(i) ? ((Int_t){.small=(int64_t)((uint64_t)(i)<<2)|1}) : Int64_to_Int(i)) #define I_small(i) ((Int_t){.small=((uint64_t)(i)<<2)|1}) #define I_is_zero(i) ((i).small == 1) @@ -121,7 +119,6 @@ Int_t Int$slow_bit_or(Int_t x, Int_t y); Int_t Int$slow_bit_xor(Int_t x, Int_t y); Int_t Int$slow_negative(Int_t x); Int_t Int$slow_negated(Int_t x); -Int_t Int$abs(Int_t x); bool Int$is_prime(Int_t x, Int_t reps); Int_t Int$next_prime(Int_t x); Int_t Int$prev_prime(Int_t x); @@ -280,7 +277,8 @@ static inline Int_t Int64_to_Int(int64_t i) #define Int16_to_Int(i) Int64_to_Int(i) #define Int8_to_Int(i) Int64_to_Int(i) -static inline Int64_t Int_to_Int64(Int_t i, bool truncate) { +#pragma GCC diagnostic ignored "-Winline" +PUREFUNC static inline Int64_t Int_to_Int64(Int_t i, bool truncate) { if (__builtin_expect(i.small & 1, 1)) return (int64_t)(i.small >> 2); if (__builtin_expect(!truncate && !mpz_fits_slong_p(*i.big), 0)) @@ -288,7 +286,7 @@ static inline Int64_t Int_to_Int64(Int_t i, bool truncate) { return mpz_get_si(*i.big); } -static inline Int32_t Int_to_Int32(Int_t i, bool truncate) { +PUREFUNC static inline Int32_t Int_to_Int32(Int_t i, bool truncate) { int64_t i64 = Int_to_Int64(i, truncate); int32_t i32 = (int32_t)i64; if (__builtin_expect(i64 != i32 && !truncate, 0)) @@ -296,7 +294,7 @@ static inline Int32_t Int_to_Int32(Int_t i, bool truncate) { return i32; } -static inline Int16_t Int_to_Int16(Int_t i, bool truncate) { +PUREFUNC static inline Int16_t Int_to_Int16(Int_t i, bool truncate) { int64_t i64 = Int_to_Int64(i, truncate); int16_t i16 = (int16_t)i64; if (__builtin_expect(i64 != i16 && !truncate, 0)) @@ -304,7 +302,7 @@ static inline Int16_t Int_to_Int16(Int_t i, bool truncate) { return i16; } -static inline Int8_t Int_to_Int8(Int_t i, bool truncate) { +PUREFUNC static inline Int8_t Int_to_Int8(Int_t i, bool truncate) { int64_t i64 = Int_to_Int64(i, truncate); int8_t i8 = (int8_t)i64; if (__builtin_expect(i64 != i8 && !truncate, 0)) @@ -312,14 +310,14 @@ static inline Int8_t Int_to_Int8(Int_t i, bool truncate) { return i8; } -static inline Int_t Num_to_Int(double n) +PUREFUNC static inline Int_t Num_to_Int(double n) { mpz_t result; mpz_init_set_d(result, n); return Int$from_mpz(result); } -static inline double Int_to_Num(Int_t i) +PUREFUNC static inline double Int_to_Num(Int_t i) { if (__builtin_expect(i.small & 1, 1)) return (double)(i.small >> 2); @@ -330,7 +328,7 @@ static inline double Int_to_Num(Int_t i) #define Int_to_Num32(i) (Num32_t)Int_to_Num(i) #define CONVERSION_FUNC(hi, lo) \ - static inline int##lo##_t Int##hi##_to_Int##lo(int##hi##_t i, bool truncate) { \ + PUREFUNC static inline int##lo##_t Int##hi##_to_Int##lo(int##hi##_t i, bool truncate) { \ if (__builtin_expect(!truncate && (i != (int##lo##_t)i), 0)) \ fail("Cannot truncate the Int" #hi " %ld to an Int" #lo, (int64_t)i); \ return (int##lo##_t)i; \ @@ -344,11 +342,12 @@ CONVERSION_FUNC(32, 8) CONVERSION_FUNC(16, 8) #undef CONVERSION_FUNC +#pragma GCC diagnostic ignored "-Wfloat-equal" #define CONVERSION_FUNC(num, int_type) \ - static inline int_type##_t num##_to_##int_type(num##_t n, bool truncate) { \ - num##_t rounded = round(n); \ + PUREFUNC static inline int_type##_t num##_to_##int_type(num##_t n, bool truncate) { \ + num##_t rounded = (num##_t)round((double)n); \ if (__builtin_expect(!truncate && (num##_t)(int_type##_t)rounded != rounded, 0)) \ - fail("Cannot truncate the " #num " %g to an " #int_type, rounded); \ + fail("Cannot truncate the " #num " %g to an " #int_type, (double)rounded); \ return (int_type##_t)rounded; \ } diff --git a/builtins/nums.c b/builtins/nums.c index 35ec9b18..90eb75ce 100644 --- a/builtins/nums.c +++ b/builtins/nums.c @@ -14,23 +14,23 @@ #include "text.h" #include "types.h" -public Text_t Num$as_text(const double *f, bool colorize, const TypeInfo *type) { +public PUREFUNC Text_t Num$as_text(const double *f, bool colorize, const TypeInfo *type) { (void)type; if (!f) return Text("Num"); return Text$format(colorize ? "\x1b[35m%.16g\x1b[33;2m\x1b[m" : "%.16g", *f); } -public int32_t Num$compare(const double *x, const double *y, const TypeInfo *type) { +public PUREFUNC int32_t Num$compare(const double *x, const double *y, const TypeInfo *type) { (void)type; return (*x > *y) - (*x < *y); } -public bool Num$equal(const double *x, const double *y, const TypeInfo *type) { +public PUREFUNC bool Num$equal(const double *x, const double *y, const TypeInfo *type) { (void)type; return *x == *y; } -public bool Num$near(double a, double b, double ratio, double absolute) { +public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute) { if (ratio < 0) ratio = 0; else if (ratio > 1) ratio = 1; @@ -62,7 +62,7 @@ public double Num$random(void) { return drand48(); } -public double Num$mix(double amount, double x, double y) { +public CONSTFUNC double Num$mix(double amount, double x, double y) { return (1.0-amount)*x + amount*y; } @@ -78,9 +78,9 @@ public double Num$nan(Text_t tag) { return nan(Text$as_c_string(tag)); } -public bool Num$isinf(double n) { return !!isinf(n); } -public bool Num$finite(double n) { return !!finite(n); } -public bool Num$isnan(double n) { return !!isnan(n); } +public CONSTFUNC bool Num$isinf(double n) { return !!isinf(n); } +public CONSTFUNC bool Num$finite(double n) { return !!finite(n); } +public CONSTFUNC bool Num$isnan(double n) { return !!isnan(n); } public const TypeInfo Num$info = { .size=sizeof(double), @@ -93,23 +93,23 @@ public const TypeInfo Num$info = { }, }; -public Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo *type) { +public PUREFUNC Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo *type) { (void)type; if (!f) return Text("Num32"); - return Text$format(colorize ? "\x1b[35m%.8g_f32\x1b[33;2m\x1b[m" : "%.8g_f32", *f); + return Text$format(colorize ? "\x1b[35m%.8g_f32\x1b[33;2m\x1b[m" : "%.8g_f32", (double)*f); } -public int32_t Num32$compare(const float *x, const float *y, const TypeInfo *type) { +public PUREFUNC int32_t Num32$compare(const float *x, const float *y, const TypeInfo *type) { (void)type; return (*x > *y) - (*x < *y); } -public bool Num32$equal(const float *x, const float *y, const TypeInfo *type) { +public PUREFUNC bool Num32$equal(const float *x, const float *y, const TypeInfo *type) { (void)type; return *x == *y; } -public bool Num32$near(float a, float b, float ratio, float absolute) { +public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) { if (ratio < 0) ratio = 0; else if (ratio > 1) ratio = 1; @@ -125,11 +125,11 @@ public bool Num32$near(float a, float b, float ratio, float absolute) { } public Text_t Num32$format(float f, Int_t precision) { - return Text$format("%.*f", (int)Int_to_Int64(precision, false), f); + return Text$format("%.*f", (int)Int_to_Int64(precision, false), (double)f); } public Text_t Num32$scientific(float f, Int_t precision) { - return Text$format("%.*e", (int)Int_to_Int64(precision, false), f); + return Text$format("%.*e", (int)Int_to_Int64(precision, false), (double)f); } public float Num32$mod(float num, float modulus) { @@ -141,8 +141,8 @@ public float Num32$random(void) { return (float)drand48(); } -public float Num32$mix(float amount, float x, float y) { - return (1.0-amount)*x + amount*y; +public CONSTFUNC float Num32$mix(float amount, float x, float y) { + return (1.0f-amount)*x + amount*y; } public float Num32$from_text(Text_t text, bool *success) { @@ -157,9 +157,9 @@ public float Num32$nan(Text_t tag) { return nanf(Text$as_c_string(tag)); } -public bool Num32$isinf(float n) { return isinf(n); } -public bool Num32$finite(float n) { return finite(n); } -public bool Num32$isnan(float n) { return isnan(n); } +public CONSTFUNC bool Num32$isinf(float n) { return isinf(n); } +public CONSTFUNC bool Num32$finite(float n) { return finite(n); } +public CONSTFUNC bool Num32$isnan(float n) { return isnan(n); } public const TypeInfo Num32$info = { .size=sizeof(float), diff --git a/builtins/nums.h b/builtins/nums.h index 059ac7bd..4205274b 100644 --- a/builtins/nums.h +++ b/builtins/nums.h @@ -8,6 +8,7 @@ #include <stdint.h> #include "types.h" +#include "util.h" #define Num_t double #define Num32_t float @@ -15,39 +16,39 @@ #define N64(n) ((double)n) Text_t Num$as_text(const double *f, bool colorize, const TypeInfo *type); -int32_t Num$compare(const double *x, const double *y, const TypeInfo *type); -bool Num$equal(const double *x, const double *y, const TypeInfo *type); -bool Num$near(double a, double b, double ratio, double absolute); +PUREFUNC int32_t Num$compare(const double *x, const double *y, const TypeInfo *type); +PUREFUNC bool Num$equal(const double *x, const double *y, const TypeInfo *type); +CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute); Text_t Num$format(double f, Int_t precision); Text_t Num$scientific(double f, Int_t precision); double Num$mod(double num, double modulus); -bool Num$isinf(double n); -bool Num$finite(double n); -bool Num$isnan(double n); +CONSTFUNC bool Num$isinf(double n); +CONSTFUNC bool Num$finite(double n); +CONSTFUNC bool Num$isnan(double n); double Num$nan(Text_t tag); double Num$random(void); -double Num$mix(double amount, double x, double y); +CONSTFUNC double Num$mix(double amount, double x, double y); double Num$from_text(Text_t text, bool *success); -static inline double Num$clamped(double x, double low, double high) { +CONSTFUNC static inline double Num$clamped(double x, double low, double high) { return (x <= low) ? low : (x >= high ? high : x); } extern const TypeInfo Num$info; Text_t Num32$as_text(const float *f, bool colorize, const TypeInfo *type); -int32_t Num32$compare(const float *x, const float *y, const TypeInfo *type); -bool Num32$equal(const float *x, const float *y, const TypeInfo *type); -bool Num32$near(float a, float b, float ratio, float absolute); +PUREFUNC int32_t Num32$compare(const float *x, const float *y, const TypeInfo *type); +PUREFUNC bool Num32$equal(const float *x, const float *y, const TypeInfo *type); +CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute); Text_t Num32$format(float f, Int_t precision); Text_t Num32$scientific(float f, Int_t precision); float Num32$mod(float num, float modulus); -bool Num32$isinf(float n); -bool Num32$finite(float n); -bool Num32$isnan(float n); +CONSTFUNC bool Num32$isinf(float n); +CONSTFUNC bool Num32$finite(float n); +CONSTFUNC bool Num32$isnan(float n); float Num32$random(void); -float Num32$mix(float amount, float x, float y); +CONSTFUNC float Num32$mix(float amount, float x, float y); float Num32$from_text(Text_t text, bool *success); float Num32$nan(Text_t tag); -static inline float Num32$clamped(float x, float low, float high) { +CONSTFUNC static inline float Num32$clamped(float x, float low, float high) { return (x <= low) ? low : (x >= high ? high : x); } extern const TypeInfo Num32$info; diff --git a/builtins/pointer.c b/builtins/pointer.c index 66cd308a..0d89e8a6 100644 --- a/builtins/pointer.c +++ b/builtins/pointer.c @@ -79,13 +79,13 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo *type return text; } -public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo *type) { +PUREFUNC public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo *type) { (void)type; const void *xp = *(const void**)x, *yp = *(const void**)y; return (xp > yp) - (xp < yp); } -public bool Pointer$equal(const void *x, const void *y, const TypeInfo *type) { +PUREFUNC public bool Pointer$equal(const void *x, const void *y, const TypeInfo *type) { (void)type; const void *xp = *(const void**)x, *yp = *(const void**)y; return xp == yp; diff --git a/builtins/pointer.h b/builtins/pointer.h index 7748da4b..c3c622cf 100644 --- a/builtins/pointer.h +++ b/builtins/pointer.h @@ -7,10 +7,11 @@ #include <stdint.h> #include "types.h" +#include "util.h" Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo *type); -int32_t Pointer$compare(const void *x, const void *y, const TypeInfo *type); -bool Pointer$equal(const void *x, const void *y, const TypeInfo *type); +PUREFUNC int32_t Pointer$compare(const void *x, const void *y, const TypeInfo *type); +PUREFUNC bool Pointer$equal(const void *x, const void *y, const TypeInfo *type); #define Null(t) (t*)NULL #define POINTER_TYPE(_sigil, _pointed) (&(TypeInfo){\ diff --git a/builtins/range.c b/builtins/range.c index 1c8106eb..9dfd1efe 100644 --- a/builtins/range.c +++ b/builtins/range.c @@ -15,7 +15,7 @@ #include "util.h" -static int32_t Range$compare(const Range_t *x, const Range_t *y, const TypeInfo *type) +PUREFUNC static int32_t Range$compare(const Range_t *x, const Range_t *y, const TypeInfo *type) { (void)type; if (x == y) return 0; @@ -26,7 +26,7 @@ static int32_t Range$compare(const Range_t *x, const Range_t *y, const TypeInfo return Int$compare(&x->step, &y->step, &Int$info); } -static bool Range$equal(const Range_t *x, const Range_t *y, const TypeInfo *type) +PUREFUNC static bool Range$equal(const Range_t *x, const Range_t *y, const TypeInfo *type) { (void)type; if (x == y) return true; @@ -44,12 +44,12 @@ static Text_t Range$as_text(const Range_t *r, bool use_color, const TypeInfo *ty Int$as_text(&r->step, use_color, &Int$info)); } -public Range_t Range$reversed(Range_t r) +PUREFUNC public Range_t Range$reversed(Range_t r) { return (Range_t){r.last, r.first, Int$negative(r.step)}; } -public Range_t Range$by(Range_t r, Int_t step) +PUREFUNC public Range_t Range$by(Range_t r, Int_t step) { return (Range_t){r.first, r.last, Int$times(step, r.step)}; } diff --git a/builtins/range.h b/builtins/range.h index 802c85f8..2a4f1d68 100644 --- a/builtins/range.h +++ b/builtins/range.h @@ -2,8 +2,8 @@ // Ranges represent numeric ranges -Range_t Range$reversed(Range_t r); -Range_t Range$by(Range_t r, Int_t step); +PUREFUNC Range_t Range$reversed(Range_t r); +PUREFUNC Range_t Range$by(Range_t r, Int_t step); extern const TypeInfo Range; diff --git a/builtins/shell.c b/builtins/shell.c index da6cbe5b..91cf792f 100644 --- a/builtins/shell.c +++ b/builtins/shell.c @@ -25,7 +25,7 @@ public Pattern_t Shell$escape_text(Text_t text) add_char('"'); add_char('\''); } else - add_char(*p); + add_char((uint8_t)*p); } add_char('\''); #undef add_char diff --git a/builtins/siphash-internals.h b/builtins/siphash-internals.h index 95b00b53..4a0dc7cf 100644 --- a/builtins/siphash-internals.h +++ b/builtins/siphash-internals.h @@ -83,6 +83,7 @@ static inline void siphashadd64bits (siphash *sh, const uint64_t in) { DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3); sh->v0 ^= mi; } +#pragma GCC diagnostic ignored "-Winline" static inline uint64_t siphashfinish_last_part (siphash *sh, uint64_t t) { sh->b |= t; sh->v3 ^= sh->b; @@ -118,6 +119,7 @@ static inline uint64_t siphashfinish (siphash *sh, const uint8_t *src, size_t sr case 2: t.u8[1] = src[1]; /* Falls through */ case 1: t.u8[0] = src[0]; + default: break; } return siphashfinish_last_part(sh, t.u64); } diff --git a/builtins/siphash.c b/builtins/siphash.c index add2a747..35c882ca 100644 --- a/builtins/siphash.c +++ b/builtins/siphash.c @@ -46,12 +46,13 @@ public uint64_t siphash24(const uint8_t *src, size_t src_sz) { siphash sh; if ((uint64_t)src % __alignof__(uint64_t) == 0) { +#pragma GCC diagnostic ignored "-Wcast-align" const uint64_t *in = (uint64_t*)src; /* Find largest src_sz evenly divisible by 8 bytes. */ - const ptrdiff_t src_sz_nearest_8bits = (src_sz >> 3) << 3; + const ptrdiff_t src_sz_nearest_8bits = ((ptrdiff_t)src_sz >> 3) << 3; const uint64_t *goal = (uint64_t*)(src + src_sz_nearest_8bits); siphashinit(&sh, src_sz); - src_sz -= src_sz_nearest_8bits; + src_sz -= (size_t)src_sz_nearest_8bits; while (in < goal) { siphashadd64bits(&sh, *in); in++; diff --git a/builtins/table.c b/builtins/table.c index a5dafd48..cd87c897 100644 --- a/builtins/table.c +++ b/builtins/table.c @@ -40,7 +40,6 @@ #define END_OF_CHAIN UINT32_MAX #define GET_ENTRY(t, i) ((t).entries.data + (t).entries.stride*(i)) -#define ENTRIES_TYPE(type) (&(TypeInfo){.size=sizeof(Array_t), .align=__alignof__(Array_t), .tag=ArrayInfo, .ArrayInfo.item=(&(TypeInfo){.size=entry_size(type), .align=entry_align(type), .tag=OpaqueInfo})}) static const TypeInfo MemoryPointer = { .size=sizeof(void*), @@ -59,27 +58,27 @@ const TypeInfo CStrToVoidStarTable = { .TableInfo={.key=&CString$info, .value=&MemoryPointer}, }; -static inline size_t entry_size(const TypeInfo *info) +PUREFUNC static inline size_t entry_size(const TypeInfo *info) { - size_t size = info->TableInfo.key->size; - if (info->TableInfo.value->align > 1 && size % info->TableInfo.value->align) - size += info->TableInfo.value->align - (size % info->TableInfo.value->align); // padding - size += info->TableInfo.value->size; - if (info->TableInfo.key->align > 1 && size % info->TableInfo.key->align) - size += info->TableInfo.key->align - (size % info->TableInfo.key->align); // padding + size_t size = (size_t)info->TableInfo.key->size; + if (info->TableInfo.value->align > 1 && size % (size_t)info->TableInfo.value->align) + size += (size_t)info->TableInfo.value->align - (size % (size_t)info->TableInfo.value->align); // padding + size += (size_t)info->TableInfo.value->size; + if (info->TableInfo.key->align > 1 && size % (size_t)info->TableInfo.key->align) + size += (size_t)info->TableInfo.key->align - (size % (size_t)info->TableInfo.key->align); // padding return size; } -static inline size_t entry_align(const TypeInfo *info) +PUREFUNC static inline size_t entry_align(const TypeInfo *info) { - return MAX(info->TableInfo.key->align, info->TableInfo.value->align); + return (size_t)MAX(info->TableInfo.key->align, info->TableInfo.value->align); } -static inline size_t value_offset(const TypeInfo *info) +PUREFUNC static inline size_t value_offset(const TypeInfo *info) { - size_t offset = info->TableInfo.key->size; - if (info->TableInfo.value->align > 1 && offset % info->TableInfo.value->align) - offset += info->TableInfo.value->align - (offset % info->TableInfo.value->align); // padding + size_t offset = (size_t)info->TableInfo.key->size; + if ((size_t)info->TableInfo.value->align > 1 && offset % (size_t)info->TableInfo.value->align) + offset += (size_t)info->TableInfo.value->align - (offset % (size_t)info->TableInfo.value->align); // padding return offset; } @@ -99,17 +98,17 @@ static inline void hshow(const Table_t *t) static void maybe_copy_on_write(Table_t *t, const TypeInfo *type) { if (t->entries.data_refcount != 0) - Array$compact(&t->entries, entry_size(type)); + Array$compact(&t->entries, (int64_t)entry_size(type)); if (t->bucket_info && t->bucket_info->data_refcount != 0) { - int64_t size = sizeof(bucket_info_t) + sizeof(bucket_t[t->bucket_info->count]); + size_t size = sizeof(bucket_info_t) + sizeof(bucket_t[t->bucket_info->count]); t->bucket_info = memcpy(GC_MALLOC(size), t->bucket_info, size); t->bucket_info->data_refcount = 0; } } // Return address of value or NULL -public void *Table$get_raw(Table_t t, const void *key, const TypeInfo *type) +PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo *type) { assert(type->tag == TableInfo); if (!key || !t.bucket_info) return NULL; @@ -131,7 +130,7 @@ public void *Table$get_raw(Table_t t, const void *key, const TypeInfo *type) return NULL; } -public void *Table$get(Table_t t, const void *key, const TypeInfo *type) +PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo *type) { assert(type->tag == TableInfo); for (const Table_t *iter = &t; iter; iter = iter->fallback) { @@ -201,7 +200,7 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type fail("Table has exceeded the maximum table size (2^31) and cannot grow further!"); hdebug("About to resize from %u to %u\n", t->bucket_info ? t->bucket_info->count : 0, new_capacity); hshow(t); - int64_t alloc_size = sizeof(bucket_info_t) + sizeof(bucket_t[new_capacity]); + 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])); t->bucket_info->count = new_capacity; @@ -217,6 +216,7 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type } // Return address of value +#pragma GCC diagnostic ignored "-Wstack-protector" public void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo *type) { assert(type->tag == TableInfo); @@ -237,7 +237,7 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const value_home = t->entries.data + offset; if (value && value_size > 0) - memcpy(value_home, value, value_size); + memcpy(value_home, value, (size_t)value_size); return value_home; } @@ -246,7 +246,7 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const // Resize buckets if necessary if (t->entries.length >= (int64_t)t->bucket_info->count) { - uint32_t newsize = t->bucket_info->count + MIN(t->bucket_info->count, 64); + uint32_t newsize = (uint32_t)t->bucket_info->count + MIN((uint32_t)t->bucket_info->count, 64); if (__builtin_expect(newsize > TABLE_MAX_BUCKETS, 0)) newsize = t->entries.length + 1; hashmap_resize_buckets(t, newsize, type); @@ -263,12 +263,12 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const char buf[entry_size(type)]; memset(buf, 0, sizeof(buf)); - memcpy(buf, key, key_size); + memcpy(buf, key, (size_t)key_size); if (value && value_size > 0) - memcpy(buf + value_offset(type), value, value_size); + memcpy(buf + value_offset(type), value, (size_t)value_size); else - memset(buf + value_offset(type), 0, value_size); - Array$insert(&t->entries, buf, I(0), entry_size(type)); + memset(buf + value_offset(type), 0, (size_t)value_size); + Array$insert(&t->entries, buf, I(0), (int64_t)entry_size(type)); int64_t entry_index = t->entries.length-1; void *entry = GET_ENTRY(*t, entry_index); @@ -351,7 +351,7 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo *type) // Last entry is being removed, so clear it out to be safe: memset(GET_ENTRY(*t, last_entry), 0, entry_size(type)); - Array$remove_at(&t->entries, I(t->entries.length), I(1), entry_size(type)); + Array$remove_at(&t->entries, I(t->entries.length), I(1), (int64_t)entry_size(type)); int64_t bucket_to_clear; if (prev) { // Middle (or end) of a chain @@ -374,7 +374,7 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo *type) hshow(t); } -public void *Table$entry(Table_t t, int64_t n) +CONSTFUNC public void *Table$entry(Table_t t, int64_t n) { if (n < 1 || n > Table$length(t)) return NULL; @@ -389,11 +389,11 @@ public void Table$clear(Table_t *t) public Table_t Table$sorted(Table_t t, const TypeInfo *type) { closure_t cmp = (closure_t){.fn=generic_compare, .userdata=(void*)type->TableInfo.key}; - Array_t entries = Array$sorted(t.entries, cmp, entry_size(type)); + Array_t entries = Array$sorted(t.entries, cmp, (int64_t)entry_size(type)); return Table$from_entries(entries, type); } -public bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo *type) +PUREFUNC public bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo *type) { if (x == y) return true; @@ -407,7 +407,7 @@ public bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo *type return (Table$compare(x, y, type) == 0); } -public int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo *type) +PUREFUNC public int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo *type) { if (x == y) return 0; @@ -438,7 +438,7 @@ public int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo return 0; } -public uint64_t Table$hash(const Table_t *t, const TypeInfo *type) +PUREFUNC public uint64_t Table$hash(const Table_t *t, const TypeInfo *type) { assert(type->tag == TableInfo); // Table hashes are computed as: @@ -473,7 +473,7 @@ public Text_t Table$as_text(const Table_t *t, bool colorize, const TypeInfo *typ Text("}")); } - int64_t val_off = value_offset(type); + int64_t val_off = (int64_t)value_offset(type); Text_t text = Text("{"); for (int64_t i = 0, length = Table$length(*t); i < length; i++) { if (i > 0) @@ -500,13 +500,13 @@ public Table_t Table$from_entries(Array_t entries, const TypeInfo *type) Table_t t = {}; int64_t length = entries.length + entries.length / 4; - int64_t alloc_size = sizeof(bucket_info_t) + sizeof(bucket_t[length]); + size_t alloc_size = sizeof(bucket_info_t) + sizeof(bucket_t[length]); t.bucket_info = GC_MALLOC_ATOMIC(alloc_size); memset(t.bucket_info->buckets, 0, sizeof(bucket_t[length])); t.bucket_info->count = length; t.bucket_info->last_free = length-1; - int64_t offset = value_offset(type); + size_t offset = value_offset(type); for (int64_t i = 0; i < entries.length; i++) { void *key = entries.data + i*entries.stride; Table$set(&t, key, key + offset, type); @@ -583,7 +583,7 @@ public Table_t Table$without(Table_t a, Table_t b, const TypeInfo *type) return result; } -public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type) +PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type) { if (a.entries.length > b.entries.length || (strict && a.entries.length == b.entries.length)) return false; @@ -595,18 +595,18 @@ public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo return true; } -public bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type) +PUREFUNC public bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type) { return Table$is_subset_of(b, a, strict, type); } -public void *Table$str_get(Table_t t, const char *key) +PUREFUNC public void *Table$str_get(Table_t t, const char *key) { void **ret = Table$get(t, &key, &CStrToVoidStarTable); return ret ? *ret : NULL; } -public void *Table$str_get_raw(Table_t t, const char *key) +PUREFUNC public void *Table$str_get_raw(Table_t t, const char *key) { void **ret = Table$get_raw(t, &key, &CStrToVoidStarTable); return ret ? *ret : NULL; @@ -627,7 +627,7 @@ public void Table$str_remove(Table_t *t, const char *key) return Table$remove(t, &key, &CStrToVoidStarTable); } -public void *Table$str_entry(Table_t t, int64_t n) +CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n) { return Table$entry(t, n); } diff --git a/builtins/table.h b/builtins/table.h index 91e87bc5..8e6e5de1 100644 --- a/builtins/table.h +++ b/builtins/table.h @@ -44,8 +44,8 @@ void *Table$get(Table_t t, const void *key, const TypeInfo *type); #define Table$has_value(table_expr, key_expr, info_expr) ({ \ const Table_t t = table_expr; __typeof(key_expr) k = key_expr; \ (Table$get(t, &k, info_expr) != NULL); }) -void *Table$get_raw(Table_t t, const void *key, const TypeInfo *type); -void *Table$entry(Table_t t, int64_t n); +PUREFUNC void *Table$get_raw(Table_t t, const void *key, const TypeInfo *type); +CONSTFUNC void *Table$entry(Table_t t, int64_t n); void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo *type); void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo *type); #define Table$set_value(t, key_expr, value_expr, type) ({ __typeof(key_expr) k = key_expr; __typeof(value_expr) v = value_expr; \ @@ -63,22 +63,22 @@ void Table$remove(Table_t *t, const void *key, const TypeInfo *type); Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo *type); Table_t Table$with(Table_t a, Table_t b, const TypeInfo *type); Table_t Table$without(Table_t a, Table_t b, const TypeInfo *type); -bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type); -bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type); +PUREFUNC bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type); +PUREFUNC bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo *type); void Table$clear(Table_t *t); Table_t Table$sorted(Table_t t, const TypeInfo *type); void Table$mark_copy_on_write(Table_t *t); #define TABLE_INCREF(t) ({ ARRAY_INCREF((t).entries); if ((t).bucket_info) (t).bucket_info->data_refcount += ((t).bucket_info->data_refcount < TABLE_MAX_DATA_REFCOUNT); }) #define TABLE_COPY(t) ({ TABLE_INCREF(t); t; }) -int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo *type); -bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo *type); -uint64_t Table$hash(const Table_t *t, const TypeInfo *type); +PUREFUNC int32_t Table$compare(const Table_t *x, const Table_t *y, const TypeInfo *type); +PUREFUNC bool Table$equal(const Table_t *x, const Table_t *y, const TypeInfo *type); +PUREFUNC uint64_t Table$hash(const Table_t *t, const TypeInfo *type); Text_t Table$as_text(const Table_t *t, bool colorize, const TypeInfo *type); -void *Table$str_entry(Table_t t, int64_t n); -void *Table$str_get(Table_t t, const char *key); -void *Table$str_get_raw(Table_t t, const char *key); +CONSTFUNC void *Table$str_entry(Table_t t, int64_t n); +PUREFUNC void *Table$str_get(Table_t t, const char *key); +PUREFUNC void *Table$str_get_raw(Table_t t, const char *key); void Table$str_set(Table_t *t, const char *key, const void *value); void *Table$str_reserve(Table_t *t, const char *key, const void *value); void Table$str_remove(Table_t *t, const char *key); diff --git a/builtins/text.c b/builtins/text.c index db62b848..c9244fa4 100644 --- a/builtins/text.c +++ b/builtins/text.c @@ -45,7 +45,7 @@ // AKA: LATIN CAPITAL LETTER H, LATIN SMALL LETTER E, COMBINING VERTICAL LINE BELOW // This would be stored as: (int32_t[]){0x48, -2} // Where -2 is used as a lookup in an array that holds the actual unicode codepoints: -// (uint32_t[]){0x65, 0x0309} +// (ucs4_t[]){0x65, 0x0309} #include <assert.h> #include <ctype.h> @@ -79,8 +79,8 @@ #include "siphash-internals.h" typedef struct { - uint32_t main_codepoint; - uint32_t *utf32_cluster; // length-prefixed + ucs4_t main_codepoint; + ucs4_t *utf32_cluster; // length-prefixed const uint8_t *utf8; } synthetic_grapheme_t; @@ -91,37 +91,38 @@ typedef struct { #define MAX_BACKREFS 100 // Synthetic grapheme clusters (clusters of more than one codepoint): -static Table_t grapheme_ids_by_codepoints = {}; // uint32_t* length-prefixed codepoints -> int32_t ID +static Table_t grapheme_ids_by_codepoints = {}; // ucs4_t* length-prefixed codepoints -> int32_t ID // This will hold a dynamically growing array of synthetic graphemes: static synthetic_grapheme_t *synthetic_graphemes = NULL; static int32_t synthetic_grapheme_capacity = 0; static int32_t num_synthetic_graphemes = 0; -#define MAIN_GRAPHEME_CODEPOINT(g) ((g) >= 0 ? (uint32_t)(g) : synthetic_graphemes[-(g)-1].main_codepoint) +#define MAIN_GRAPHEME_CODEPOINT(_g) ({ int32_t g = _g; (g) >= 0 ? (ucs4_t)(g) : synthetic_graphemes[-(g)-1].main_codepoint; }) #define NUM_GRAPHEME_CODEPOINTS(id) (synthetic_graphemes[-(id)-1].utf32_cluster[0]) #define GRAPHEME_CODEPOINTS(id) (&synthetic_graphemes[-(id)-1].utf32_cluster[1]) #define GRAPHEME_UTF8(id) (synthetic_graphemes[-(id)-1].utf8) static int32_t get_grapheme(Text_t text, int64_t index); -static int32_t _next_grapheme(Text_t text, text_iter_t *state, int64_t index); -static Text_t text_from_u32(uint32_t *codepoints, int64_t num_codepoints, bool normalize); +static int32_t _get_grapheme(Text_t text, text_iter_t *state, int64_t index); +#define _get_main_grapheme(...) MAIN_GRAPHEME_CODEPOINT(_get_grapheme(__VA_ARGS__)) +static Text_t text_from_u32(ucs4_t *codepoints, int64_t num_codepoints, bool normalize); -static bool graphemes_equal(uint32_t **a, uint32_t **b) { +PUREFUNC static bool graphemes_equal(ucs4_t **a, ucs4_t **b) { if ((*a)[0] != (*b)[0]) return false; for (int i = 0; i < (int)(*a)[0]; i++) if ((*a)[i] != (*b)[i]) return false; return true; } -static uint64_t grapheme_hash(uint32_t **g) { - uint32_t *cluster = *g; - return siphash24((void*)&cluster[1], sizeof(uint32_t[cluster[0]])); +PUREFUNC static uint64_t grapheme_hash(ucs4_t **g) { + ucs4_t *cluster = *g; + return siphash24((void*)&cluster[1], sizeof(ucs4_t[cluster[0]])); } static const TypeInfo GraphemeClusterInfo = { - .size=sizeof(uint32_t*), - .align=__alignof__(uint32_t*), + .size=sizeof(ucs4_t*), + .align=__alignof__(ucs4_t*), .tag=CustomInfo, .CustomInfo={.equal=(void*)graphemes_equal, .hash=(void*)grapheme_hash}, }; @@ -131,13 +132,14 @@ static const TypeInfo GraphemeIDLookupTableInfo = { .tag=TableInfo, .TableInfo={.key=&GraphemeClusterInfo, .value=&Int32$info}, }; -int32_t get_synthetic_grapheme(const uint32_t *codepoints, int64_t utf32_len) +#pragma GCC diagnostic ignored "-Wstack-protector" +int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_len) { - uint32_t length_prefixed[1+utf32_len] = {}; - length_prefixed[0] = (uint32_t)utf32_len; + ucs4_t length_prefixed[1+utf32_len] = {}; + length_prefixed[0] = (ucs4_t)utf32_len; for (int i = 0; i < utf32_len; i++) length_prefixed[i+1] = codepoints[i]; - uint32_t *ptr = &length_prefixed[0]; + ucs4_t *ptr = &length_prefixed[0]; // Optimization for common case of one frequently used synthetic grapheme: static int32_t last_grapheme = 0; @@ -162,18 +164,18 @@ int32_t get_synthetic_grapheme(const uint32_t *codepoints, int64_t utf32_len) // Get UTF8 representation: uint8_t u8_buf[64]; size_t u8_len = sizeof(u8_buf)/sizeof(u8_buf[0]); - uint8_t *u8 = u32_to_u8(codepoints, utf32_len, u8_buf, &u8_len); + uint8_t *u8 = u32_to_u8(codepoints, (size_t)utf32_len, u8_buf, &u8_len); // For performance reasons, use an arena allocator here to ensure that // synthetic graphemes store all of their information in a densely packed // area with good cache locality: static void *arena = NULL, *arena_end = NULL; // Eat up any space needed to make arena 32-bit aligned: - if ((long)arena % __alignof__(uint32_t) != 0) - arena += __alignof__(uint32_t) - ((long)arena % __alignof__(uint32_t)); + if ((size_t)arena % __alignof__(ucs4_t) != 0) + arena += __alignof__(ucs4_t) - ((size_t)arena % __alignof__(ucs4_t)); // If we have filled up this arena, allocate a new one: - size_t needed_memory = sizeof(uint32_t[1+utf32_len]) + sizeof(uint8_t[u8_len + 1]); + size_t needed_memory = sizeof(ucs4_t[1+utf32_len]) + sizeof(uint8_t[u8_len + 1]); if (arena + needed_memory > arena_end) { // Do reasonably big chunks at a time, so most synthetic codepoints are // nearby each other in memory and cache locality is good. This is a @@ -184,10 +186,10 @@ int32_t get_synthetic_grapheme(const uint32_t *codepoints, int64_t utf32_len) } // Copy length-prefixed UTF32 codepoints into the arena and store where they live: - uint32_t *codepoint_copy = arena; - mempcpy(codepoint_copy, length_prefixed, sizeof(uint32_t[1+utf32_len])); + ucs4_t *codepoint_copy = arena; + mempcpy(codepoint_copy, length_prefixed, sizeof(ucs4_t[1+utf32_len])); synthetic_graphemes[-grapheme_id-1].utf32_cluster = codepoint_copy; - arena += sizeof(uint32_t[1+utf32_len]); + arena += sizeof(ucs4_t[1+utf32_len]); // Copy UTF8 bytes into the arena and store where they live: uint8_t *utf8_final = arena; @@ -199,7 +201,7 @@ int32_t get_synthetic_grapheme(const uint32_t *codepoints, int64_t utf32_len) // Sickos at the unicode consortium decreed that you can have grapheme clusters // that begin with *prefix* modifiers, so we gotta check for that case: synthetic_graphemes[-grapheme_id-1].main_codepoint = length_prefixed[1]; - for (uint32_t i = 0; i < utf32_len; i++) { + for (ucs4_t i = 0; i < utf32_len; i++) { if (!__builtin_expect(uc_is_property_prepended_concatenation_mark(length_prefixed[1+i]), 0)) { synthetic_graphemes[-grapheme_id-1].main_codepoint = length_prefixed[1+i]; break; @@ -215,7 +217,7 @@ int32_t get_synthetic_grapheme(const uint32_t *codepoints, int64_t utf32_len) return grapheme_id; } -static inline int64_t num_subtexts(Text_t t) +PUREFUNC static inline int64_t num_subtexts(Text_t t) { if (t.tag != TEXT_SUBTEXT) return 1; int64_t len = t.length; @@ -259,8 +261,8 @@ public int Text$print(FILE *stream, Text_t t) if (t.length == 0) return 0; switch (t.tag) { - case TEXT_SHORT_ASCII: return fwrite(t.short_ascii, sizeof(char), t.length, stream); - case TEXT_ASCII: return fwrite(t.ascii, sizeof(char), t.length, stream); + case TEXT_SHORT_ASCII: return fwrite(t.short_ascii, sizeof(char), (size_t)t.length, stream); + case TEXT_ASCII: return fwrite(t.ascii, sizeof(char), (size_t)t.length, stream); case TEXT_GRAPHEMES: case TEXT_SHORT_GRAPHEMES: { const int32_t *graphemes = t.tag == TEXT_SHORT_GRAPHEMES ? t.short_graphemes : t.graphemes; int written = 0; @@ -269,13 +271,13 @@ public int Text$print(FILE *stream, Text_t t) if (grapheme >= 0) { uint8_t buf[8]; size_t len = sizeof(buf); - uint8_t *u8 = u32_to_u8((uint32_t*)&grapheme, 1, buf, &len); - written += fwrite(u8, sizeof(char), len, stream); + uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, buf, &len); + written += (int)fwrite(u8, sizeof(char), len, stream); if (u8 != buf) free(u8); } else { const uint8_t *u8 = GRAPHEME_UTF8(grapheme); assert(u8); - written += fwrite(u8, sizeof(uint8_t), strlen((char*)u8), stream); + written += (int)fwrite(u8, sizeof(uint8_t), strlen((char*)u8), stream); } } return written; @@ -309,10 +311,10 @@ static bool is_concat_stable(Text_t a, Text_t b) return true; // Do a normalization run for these two codepoints and see if it looks different: - uint32_t codepoints[2] = {(uint32_t)last_a, (uint32_t)first_b}; - uint32_t norm_buf[3*2]; // Normalization should not exceed 3x in the input length + ucs4_t codepoints[2] = {(ucs4_t)last_a, (ucs4_t)first_b}; + ucs4_t norm_buf[3*2]; // Normalization should not exceed 3x in the input length size_t norm_length = sizeof(norm_buf)/sizeof(norm_buf[0]); - uint32_t *normalized = u32_normalize(UNINORM_NFC, codepoints, 2, norm_buf, &norm_length); + ucs4_t *normalized = u32_normalize(UNINORM_NFC, codepoints, 2, norm_buf, &norm_length); if (norm_length != 2) { // Looks like these two codepoints merged into one (or maybe had a child, who knows?) if (normalized != norm_buf) free(normalized); @@ -387,14 +389,14 @@ static Text_t concat2(Text_t a, Text_t b) int32_t first_b = get_grapheme(b, 0); size_t utf32_len = (last_a >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(last_a)) + (first_b >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(first_b)); - uint32_t join_graphemes[utf32_len] = {}; - uint32_t *p = &join_graphemes[0]; + ucs4_t join_graphemes[utf32_len] = {}; + ucs4_t *p = &join_graphemes[0]; if (last_a < 0) p = mempcpy(p, GRAPHEME_CODEPOINTS(last_a), NUM_GRAPHEME_CODEPOINTS(last_a)); - else *(p++) = last_a; + else *(p++) = (ucs4_t)last_a; if (first_b < 0) p = mempcpy(p, GRAPHEME_CODEPOINTS(first_b), NUM_GRAPHEME_CODEPOINTS(first_b)); - else *(p++) = first_b; + else *(p++) = (ucs4_t)first_b; - Text_t glue = text_from_u32(join_graphemes, utf32_len, true); + Text_t glue = text_from_u32(join_graphemes, (int64_t)utf32_len, true); if (a.length == 1 && b.length == 1) return glue; @@ -510,7 +512,7 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) .tag=TEXT_SHORT_ASCII, .length=last - first + 1, }; - memcpy(ret.short_ascii, text.short_ascii + (first-1), ret.length); + memcpy(ret.short_ascii, text.short_ascii + (first-1), (size_t)ret.length); return ret; } case TEXT_ASCII: { @@ -575,15 +577,15 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) } } -Text_t text_from_u32(uint32_t *codepoints, int64_t num_codepoints, bool normalize) +Text_t text_from_u32(ucs4_t *codepoints, int64_t num_codepoints, bool normalize) { // Normalization is apparently guaranteed to never exceed 3x in the input length - uint32_t norm_buf[MIN(256, 3*num_codepoints)]; + ucs4_t norm_buf[MIN(256, 3*num_codepoints)]; if (normalize) { size_t norm_length = sizeof(norm_buf)/sizeof(norm_buf[0]); - uint32_t *normalized = u32_normalize(UNINORM_NFC, codepoints, num_codepoints, norm_buf, &norm_length); + ucs4_t *normalized = u32_normalize(UNINORM_NFC, codepoints, (size_t)num_codepoints, norm_buf, &norm_length); codepoints = normalized; - num_codepoints = norm_length; + num_codepoints = (int64_t)norm_length; } // char breaks[num_codepoints]; @@ -593,7 +595,7 @@ Text_t text_from_u32(uint32_t *codepoints, int64_t num_codepoints, bool normaliz .length=0, .tag=TEXT_SHORT_GRAPHEMES, }; - const uint32_t *src = codepoints; + const ucs4_t *src = codepoints; int32_t *graphemes = ret.short_graphemes; while (src < &codepoints[num_codepoints]) { if (ret.tag == TEXT_SHORT_GRAPHEMES && ret.length + 1 > 2) { @@ -605,7 +607,7 @@ Text_t text_from_u32(uint32_t *codepoints, int64_t num_codepoints, bool normaliz } // TODO: use grapheme breaks instead of u32_grapheme_next() - const uint32_t *next = u32_grapheme_next(src, &codepoints[num_codepoints]); + const ucs4_t *next = u32_grapheme_next(src, &codepoints[num_codepoints]); if (next == &src[1]) { graphemes[ret.length] = (int32_t)*src; } else { @@ -640,11 +642,11 @@ public Text_t Text$from_strn(const char *str, size_t len) if (u8_check((uint8_t*)str, len) != NULL) return Text(""); - uint32_t buf[128]; + ucs4_t buf[128]; size_t length = sizeof(buf)/sizeof(buf[0]); - uint32_t *codepoints = u8_to_u32((uint8_t*)str, ascii_span + strlen(str + ascii_span), buf, &length); - Text_t ret = text_from_u32(codepoints, length, true); + ucs4_t *codepoints = u8_to_u32((uint8_t*)str, (size_t)ascii_span + strlen(str + ascii_span), buf, &length); + Text_t ret = text_from_u32(codepoints, (int64_t)length, true); if (codepoints != buf) free(codepoints); return ret; } @@ -661,11 +663,11 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i case TEXT_ASCII: case TEXT_SHORT_ASCII: { if (*i + text.length > (int64_t)*capacity) { *capacity = *i + text.length + 1; - *buf = GC_REALLOC(*buf, *capacity); + *buf = GC_REALLOC(*buf, (size_t)*capacity); } const char *bytes = text.tag == TEXT_ASCII ? text.ascii : text.short_ascii; - memcpy(*buf + *i, bytes, text.length); + memcpy(*buf + *i, bytes, (size_t)text.length); *i += text.length; break; } @@ -675,26 +677,26 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i if (graphemes[g] >= 0) { uint8_t u8_buf[64]; size_t u8_len = sizeof(u8_buf); - uint8_t *u8 = u32_to_u8((uint32_t*)&graphemes[g], 1, u8_buf, &u8_len); + uint8_t *u8 = u32_to_u8((ucs4_t*)&graphemes[g], 1, u8_buf, &u8_len); if (*i + (int64_t)u8_len > (int64_t)*capacity) { - *capacity = *i + u8_len + 1; - *buf = GC_REALLOC(*buf, *capacity); + *capacity = *i + (int64_t)u8_len + 1; + *buf = GC_REALLOC(*buf, (size_t)*capacity); } memcpy(*buf + *i, u8, u8_len); - *i += u8_len; + *i += (int64_t)u8_len; if (u8 != u8_buf) free(u8); } else { const uint8_t *u8 = GRAPHEME_UTF8(graphemes[g]); size_t u8_len = u8_strlen(u8); if (*i + (int64_t)u8_len > (int64_t)*capacity) { - *capacity = *i + u8_len + 1; - *buf = GC_REALLOC(*buf, *capacity); + *capacity = *i + (int64_t)u8_len + 1; + *buf = GC_REALLOC(*buf, (size_t)*capacity); } memcpy(*buf + *i, u8, u8_len); - *i += u8_len; + *i += (int64_t)u8_len; } } break; @@ -713,19 +715,19 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i public char *Text$as_c_string(Text_t text) { int64_t capacity = text.length + 1; - char *buf = GC_MALLOC_ATOMIC(capacity); + char *buf = GC_MALLOC_ATOMIC((size_t)capacity); int64_t i = 0; u8_buf_append(text, &buf, &capacity, &i); if (i + 1 > (int64_t)capacity) { capacity = i + 1; - buf = GC_REALLOC(buf, capacity); + buf = GC_REALLOC(buf, (size_t)capacity); } buf[i] = '\0'; return buf; } -public uint64_t Text$hash(Text_t *text) +PUREFUNC public uint64_t Text$hash(Text_t *text) { if (text->hash != 0) return text->hash; siphash sh; @@ -819,7 +821,7 @@ public uint64_t Text$hash(Text_t *text) ++sub_i; } - text->hash = siphashfinish_last_part(&sh, leftover); + text->hash = siphashfinish_last_part(&sh, (uint64_t)leftover); break; } default: errx(1, "Invalid text"); @@ -831,7 +833,7 @@ public uint64_t Text$hash(Text_t *text) return text->hash; } -int32_t _next_grapheme(Text_t text, text_iter_t *state, int64_t index) +int32_t _get_grapheme(Text_t text, text_iter_t *state, int64_t index) { switch (text.tag) { case TEXT_ASCII: return index < text.length ? (int32_t)text.ascii[index] : 0; @@ -851,7 +853,7 @@ int32_t _next_grapheme(Text_t text, text_iter_t *state, int64_t index) } for (;;) { if (index < state->sum_of_previous_subtexts + text.subtexts[state->subtext].length) - return _next_grapheme(text.subtexts[state->subtext], NULL, index - state->sum_of_previous_subtexts); + return _get_grapheme(text.subtexts[state->subtext], NULL, index - state->sum_of_previous_subtexts); state->sum_of_previous_subtexts += text.subtexts[state->subtext].length; state->subtext += 1; } @@ -865,32 +867,32 @@ int32_t _next_grapheme(Text_t text, text_iter_t *state, int64_t index) int32_t get_grapheme(Text_t text, int64_t index) { text_iter_t state = {0, 0}; - return _next_grapheme(text, &state, index); + return _get_grapheme(text, &state, index); } -public int32_t Text$compare(const Text_t *a, const Text_t *b) +PUREFUNC public int32_t Text$compare(const Text_t *a, const Text_t *b) { if (a == b) return 0; int64_t len = MAX(a->length, b->length); text_iter_t a_state = {0, 0}, b_state = {0, 0}; for (int64_t i = 0; i < len; i++) { - int32_t ai = _next_grapheme(*a, &a_state, i); - int32_t bi = _next_grapheme(*b, &b_state, i); + int32_t ai = _get_grapheme(*a, &a_state, i); + int32_t bi = _get_grapheme(*b, &b_state, i); if (ai == bi) continue; int32_t cmp; if (ai > 0 && bi > 0) { - cmp = u32_cmp((uint32_t*)&ai, (uint32_t*)&bi, 1); + cmp = u32_cmp((ucs4_t*)&ai, (ucs4_t*)&bi, 1); } else if (ai > 0) { cmp = u32_cmp2( - (uint32_t*)&ai, 1, + (ucs4_t*)&ai, 1, GRAPHEME_CODEPOINTS(bi), NUM_GRAPHEME_CODEPOINTS(bi)); } else if (bi > 0) { cmp = u32_cmp2( GRAPHEME_CODEPOINTS(ai), NUM_GRAPHEME_CODEPOINTS(ai), - (uint32_t*)&bi, 1); + (ucs4_t*)&bi, 1); } else { cmp = u32_cmp2( GRAPHEME_CODEPOINTS(ai), @@ -903,7 +905,7 @@ public int32_t Text$compare(const Text_t *a, const Text_t *b) return 0; } -public bool Text$equal(const Text_t *a, const Text_t *b) +PUREFUNC public bool Text$equal(const Text_t *a, const Text_t *b) { if (a == b) return true; @@ -912,14 +914,14 @@ public bool Text$equal(const Text_t *a, const Text_t *b) int64_t len = a->length; text_iter_t a_state = {0, 0}, b_state = {0, 0}; for (int64_t i = 0; i < len; i++) { - int32_t ai = _next_grapheme(*a, &a_state, i); - int32_t bi = _next_grapheme(*b, &b_state, i); + int32_t ai = _get_grapheme(*a, &a_state, i); + int32_t bi = _get_grapheme(*b, &b_state, i); if (ai != bi) return false; } return true; } -public bool Text$equal_ignoring_case(Text_t a, Text_t b) +PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b) { if (a.length != b.length) return false; @@ -927,17 +929,17 @@ public bool Text$equal_ignoring_case(Text_t a, Text_t b) text_iter_t a_state = {0, 0}, b_state = {0, 0}; const char *language = uc_locale_language(); for (int64_t i = 0; i < len; i++) { - int32_t ai = _next_grapheme(a, &a_state, i); - int32_t bi = _next_grapheme(b, &b_state, i); + int32_t ai = _get_grapheme(a, &a_state, i); + int32_t bi = _get_grapheme(b, &b_state, i); if (ai != bi) { - const uint32_t *a_codepoints = ai >= 0 ? (uint32_t*)&ai : GRAPHEME_CODEPOINTS(ai); + const ucs4_t *a_codepoints = ai >= 0 ? (ucs4_t*)&ai : GRAPHEME_CODEPOINTS(ai); int64_t a_len = ai >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(ai); - const uint32_t *b_codepoints = bi >= 0 ? (uint32_t*)&bi : GRAPHEME_CODEPOINTS(bi); + const ucs4_t *b_codepoints = bi >= 0 ? (ucs4_t*)&bi : GRAPHEME_CODEPOINTS(bi); int64_t b_len = bi >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(bi); int cmp = 0; - (void)u32_casecmp(a_codepoints, a_len, b_codepoints, b_len, language, UNINORM_NFC, &cmp); + (void)u32_casecmp(a_codepoints, (size_t)a_len, b_codepoints, (size_t)b_len, language, UNINORM_NFC, &cmp); if (cmp != 0) return false; } @@ -950,10 +952,10 @@ public Text_t Text$upper(Text_t text) if (text.length == 0) return text; Array_t codepoints = Text$utf32_codepoints(text); const char *language = uc_locale_language(); - uint32_t buf[128]; + ucs4_t buf[128]; size_t out_len = sizeof(buf)/sizeof(buf[0]); - uint32_t *upper = u32_toupper(codepoints.data, codepoints.length, language, UNINORM_NFC, buf, &out_len); - Text_t ret = text_from_u32(upper, out_len, false); + ucs4_t *upper = u32_toupper(codepoints.data, (size_t)codepoints.length, language, UNINORM_NFC, buf, &out_len); + Text_t ret = text_from_u32(upper, (int64_t)out_len, false); if (upper != buf) free(upper); return ret; } @@ -963,10 +965,10 @@ public Text_t Text$lower(Text_t text) if (text.length == 0) return text; Array_t codepoints = Text$utf32_codepoints(text); const char *language = uc_locale_language(); - uint32_t buf[128]; + ucs4_t buf[128]; size_t out_len = sizeof(buf)/sizeof(buf[0]); - uint32_t *lower = u32_tolower(codepoints.data, codepoints.length, language, UNINORM_NFC, buf, &out_len); - Text_t ret = text_from_u32(lower, out_len, false); + ucs4_t *lower = u32_tolower(codepoints.data, (size_t)codepoints.length, language, UNINORM_NFC, buf, &out_len); + Text_t ret = text_from_u32(lower, (int64_t)out_len, false); if (lower != buf) free(lower); return ret; } @@ -976,10 +978,10 @@ public Text_t Text$title(Text_t text) if (text.length == 0) return text; Array_t codepoints = Text$utf32_codepoints(text); const char *language = uc_locale_language(); - uint32_t buf[128]; + ucs4_t buf[128]; size_t out_len = sizeof(buf)/sizeof(buf[0]); - uint32_t *title = u32_totitle(codepoints.data, codepoints.length, language, UNINORM_NFC, buf, &out_len); - Text_t ret = text_from_u32(title, out_len, false); + ucs4_t *title = u32_totitle(codepoints.data, (size_t)codepoints.length, language, UNINORM_NFC, buf, &out_len); + Text_t ret = text_from_u32(title, (int64_t)out_len, false); if (title != buf) free(title); return ret; } @@ -988,8 +990,8 @@ static inline void skip_whitespace(Text_t text, int64_t *i) { text_iter_t state = {0, 0}; while (*i < text.length) { - int32_t grapheme = _next_grapheme(text, &state, *i); - if (grapheme > 0 && !uc_is_property_white_space(grapheme)) + int32_t grapheme = _get_grapheme(text, &state, *i); + if (grapheme > 0 && !uc_is_property_white_space((ucs4_t)grapheme)) return; *i += 1; } @@ -1009,7 +1011,7 @@ static inline bool match_str(Text_t text, int64_t *i, const char *str) text_iter_t state = {0, 0}; int64_t matched = 0; while (matched[str]) { - if (*i + matched >= text.length || _next_grapheme(text, &state, *i + matched) != str[matched]) + if (*i + matched >= text.length || _get_grapheme(text, &state, *i + matched) != str[matched]) return false; matched += 1; } @@ -1022,9 +1024,7 @@ static inline bool match_property(Text_t text, int64_t *i, uc_property_t prop) if (*i >= text.length) return false; int32_t grapheme = get_grapheme(text, *i); // TODO: check every codepoint in the cluster? - grapheme = MAIN_GRAPHEME_CODEPOINT(grapheme); - - if (uc_is_property(grapheme, prop)) { + if (uc_is_property(MAIN_GRAPHEME_CODEPOINT(grapheme), prop)) { *i += 1; return true; } @@ -1036,9 +1036,8 @@ static int64_t parse_int(Text_t text, int64_t *i) text_iter_t state = {0, 0}; int64_t value = 0; for (;; *i += 1) { - int32_t grapheme = _next_grapheme(text, &state, *i); - grapheme = MAIN_GRAPHEME_CODEPOINT(grapheme); - int digit = uc_digit_value(grapheme); + ucs4_t grapheme = _get_main_grapheme(text, &state, *i); + int digit = uc_digit_value((ucs4_t)grapheme); if (digit < 0) break; if (value >= INT64_MAX/10) break; value = 10*value + digit; @@ -1053,7 +1052,7 @@ const char *get_property_name(Text_t text, int64_t *i) char *dest = name; text_iter_t state = {0, 0}; while (*i < text.length) { - int32_t grapheme = _next_grapheme(text, &state, *i); + int32_t grapheme = _get_grapheme(text, &state, *i); if (!(grapheme & ~0xFF) && (isalnum(grapheme) || grapheme == ' ' || grapheme == '_' || grapheme == '-')) { *dest = (char)grapheme; ++dest; @@ -1074,16 +1073,16 @@ const char *get_property_name(Text_t text, int64_t *i) } #define EAT1(text, state, index, cond) ({\ - int32_t grapheme = _next_grapheme(text, state, index); \ + int32_t grapheme = _get_grapheme(text, state, index); \ bool success = (cond); \ if (success) index += 1; \ success; }) #define EAT2(text, state, index, cond1, cond2) ({\ - int32_t grapheme = _next_grapheme(text, state, index); \ + int32_t grapheme = _get_grapheme(text, state, index); \ bool success = (cond1); \ if (success) { \ - grapheme = _next_grapheme(text, state, index + 1); \ + grapheme = _get_grapheme(text, state, index + 1); \ success = (cond2); \ if (success) \ index += 2; \ @@ -1102,9 +1101,8 @@ int64_t match_email(Text_t text, int64_t index) text_iter_t state = {0, 0}; if (index > 0) { - int32_t prev_codepoint = _next_grapheme(text, &state, index - 1); - prev_codepoint = MAIN_GRAPHEME_CODEPOINT(prev_codepoint); - if (uc_is_property_alphabetic(prev_codepoint)) + ucs4_t prev_codepoint = _get_main_grapheme(text, &state, index - 1); + if (uc_is_property_alphabetic((ucs4_t)prev_codepoint)) return -1; } @@ -1148,7 +1146,7 @@ int64_t match_ipv6(Text_t text, int64_t index) { text_iter_t state = {0, 0}; if (index > 0) { - int32_t prev_codepoint = _next_grapheme(text, &state, index - 1); + int32_t prev_codepoint = _get_grapheme(text, &state, index - 1); if ((prev_codepoint & ~0x7F) && (isxdigit(prev_codepoint) || prev_codepoint == ':')) return -1; } @@ -1184,7 +1182,7 @@ static int64_t match_ipv4(Text_t text, int64_t index) { text_iter_t state = {0, 0}; if (index > 0) { - int32_t prev_codepoint = _next_grapheme(text, &state, index - 1); + int32_t prev_codepoint = _get_grapheme(text, &state, index - 1); if ((prev_codepoint & ~0x7F) && (isdigit(prev_codepoint) || prev_codepoint == '.')) return -1; } @@ -1226,9 +1224,8 @@ int64_t match_uri(Text_t text, int64_t index) text_iter_t state = {0, 0}; if (index > 0) { - int32_t prev_codepoint = _next_grapheme(text, &state, index - 1); - prev_codepoint = MAIN_GRAPHEME_CODEPOINT(prev_codepoint); - if (uc_is_property_alphabetic(prev_codepoint)) + int32_t prev_codepoint = _get_grapheme(text, &state, index - 1); + if (uc_is_property_alphabetic(MAIN_GRAPHEME_CODEPOINT(prev_codepoint))) return -1; } @@ -1315,15 +1312,15 @@ int64_t match_url(Text_t text, int64_t index) int64_t match_id(Text_t text, int64_t index) { text_iter_t state = {0, 0}; - if (!EAT1(text, &state, index, uc_is_property(grapheme, UC_PROPERTY_XID_START))) + if (!EAT1(text, &state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_XID_START))) return -1; - return 1 + EAT_MANY(text, &state, index, uc_is_property(grapheme, UC_PROPERTY_XID_CONTINUE)); + return 1 + EAT_MANY(text, &state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_XID_CONTINUE)); } int64_t match_int(Text_t text, int64_t index) { text_iter_t state = {0, 0}; - int64_t len = EAT_MANY(text, &state, index, uc_is_property(grapheme, UC_PROPERTY_DECIMAL_DIGIT)); + int64_t len = EAT_MANY(text, &state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT)); return len >= 0 ? len : -1; } @@ -1332,10 +1329,10 @@ int64_t match_num(Text_t text, int64_t index) text_iter_t state = {0, 0}; bool negative = EAT1(text, &state, index, grapheme == '-') ? 1 : 0; int64_t pre_decimal = EAT_MANY(text, &state, index, - uc_is_property(grapheme, UC_PROPERTY_DECIMAL_DIGIT)); + uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT)); bool decimal = (EAT1(text, &state, index, grapheme == '.') == 1); int64_t post_decimal = decimal ? EAT_MANY(text, &state, index, - uc_is_property(grapheme, UC_PROPERTY_DECIMAL_DIGIT)) : 0; + uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT)) : 0; if (pre_decimal == 0 && post_decimal == 0) return -1; return negative + pre_decimal + decimal + post_decimal; @@ -1347,11 +1344,10 @@ int64_t match_newline(Text_t text, int64_t index) return -1; text_iter_t state = {0, 0}; - int32_t grapheme = index >= text.length ? 0 : _next_grapheme(text, &state, index); - grapheme = MAIN_GRAPHEME_CODEPOINT(grapheme); + ucs4_t grapheme = index >= text.length ? 0 : _get_main_grapheme(text, &state, index); if (grapheme == '\n') return 1; - if (grapheme == '\r' && _next_grapheme(text, &state, index + 1) == '\n') + if (grapheme == '\r' && _get_grapheme(text, &state, index + 1) == '\n') return 2; return -1; } @@ -1376,8 +1372,7 @@ typedef struct { int64_t match_pat(Text_t text, text_iter_t *state, int64_t index, pat_t pat) { - int32_t grapheme = index >= text.length ? 0 : _next_grapheme(text, state, index); - grapheme = MAIN_GRAPHEME_CODEPOINT(grapheme); + int32_t grapheme = index >= text.length ? 0 : _get_grapheme(text, state, index); switch (pat.tag) { case PAT_START: { @@ -1404,7 +1399,7 @@ int64_t match_pat(Text_t text, text_iter_t *state, int64_t index, pat_t pat) case PAT_PROPERTY: { if (index >= text.length) return -1; - else if (uc_is_property(grapheme, pat.property)) + else if (uc_is_property((ucs4_t)grapheme, pat.property)) return pat.negated ? -1 : 1; return pat.negated ? 1 : -1; } @@ -1424,7 +1419,7 @@ int64_t match_pat(Text_t text, text_iter_t *state, int64_t index, pat_t pat) if (index + match_len >= text.length) return pat.negated ? 1 : -1; - int32_t c = _next_grapheme(text, state, index + match_len); + int32_t c = _get_grapheme(text, state, index + match_len); if (c == open) depth += 1; else if (c == close) @@ -1443,7 +1438,7 @@ int64_t match_pat(Text_t text, text_iter_t *state, int64_t index, pat_t pat) int32_t close = pat.quote_graphemes[1]; for (int64_t i = index + 1; i < text.length; i++) { - int32_t c = _next_grapheme(text, state, i); + int32_t c = _get_grapheme(text, state, i); if (c == close) { return pat.negated ? -1 : (i - index) + 1; } else if (c == '\\' && index + 1 < text.length) { @@ -1458,6 +1453,7 @@ int64_t match_pat(Text_t text, text_iter_t *state, int64_t index, pat_t pat) return pat.negated ? -1 : match_len; return pat.negated ? 1 : -1; } + default: errx(1, "Invalid pattern"); } errx(1, "Unreachable"); } @@ -1465,12 +1461,12 @@ int64_t match_pat(Text_t text, text_iter_t *state, int64_t index, pat_t pat) pat_t parse_next_pat(Text_t pattern, text_iter_t *state, int64_t *index) { if (EAT2(pattern, state, *index, - uc_is_property(grapheme, UC_PROPERTY_QUOTATION_MARK), + uc_is_property((ucs4_t)grapheme, UC_PROPERTY_QUOTATION_MARK), grapheme == '?')) { // Quotations: "?", '?', etc - int32_t open = _next_grapheme(pattern, state, *index-2); + int32_t open = _get_grapheme(pattern, state, *index-2); int32_t close = open; - uc_mirror_char(open, (uint32_t*)&close); + uc_mirror_char((ucs4_t)open, (ucs4_t*)&close); if (!match_grapheme(pattern, index, close)) fail("Pattern's closing quote is missing: %k", &pattern); @@ -1480,12 +1476,12 @@ pat_t parse_next_pat(Text_t pattern, text_iter_t *state, int64_t *index) .quote_graphemes={open, close}, }; } else if (EAT2(pattern, state, *index, - uc_is_property(grapheme, UC_PROPERTY_PAIRED_PUNCTUATION), + uc_is_property((ucs4_t)grapheme, UC_PROPERTY_PAIRED_PUNCTUATION), grapheme == '?')) { // Nested punctuation: (?), [?], etc - int32_t open = _next_grapheme(pattern, state, *index-2); + int32_t open = _get_grapheme(pattern, state, *index-2); int32_t close = open; - uc_mirror_char(open, (uint32_t*)&close); + uc_mirror_char((ucs4_t)open, (ucs4_t*)&close); if (!match_grapheme(pattern, index, close)) fail("Pattern's closing brace is missing: %k", &pattern); @@ -1498,7 +1494,7 @@ pat_t parse_next_pat(Text_t pattern, text_iter_t *state, int64_t *index) grapheme == '{')) { // named patterns {id}, {2-3 hex}, etc. skip_whitespace(pattern, index); int64_t min, max; - if (uc_is_digit(_next_grapheme(pattern, state, *index))) { + if (uc_is_digit((ucs4_t)_get_grapheme(pattern, state, *index))) { min = parse_int(pattern, index); skip_whitespace(pattern, index); if (match_grapheme(pattern, index, '+')) { @@ -1526,7 +1522,7 @@ pat_t parse_next_pat(Text_t pattern, text_iter_t *state, int64_t *index) if (!prop_name) { // Literal character, e.g. {1?} skip_whitespace(pattern, index); - int32_t grapheme = _next_grapheme(pattern, state, (*index)++); + int32_t grapheme = _get_grapheme(pattern, state, (*index)++); if (!match_grapheme(pattern, index, '}')) fail("Missing closing '}' in pattern: %k", &pattern); return PAT(PAT_GRAPHEME, .grapheme=grapheme); @@ -1598,19 +1594,20 @@ pat_t parse_next_pat(Text_t pattern, text_iter_t *state, int64_t *index) return PAT(PAT_FUNCTION, .fn=match_url); } break; + default: break; } uc_property_t prop = uc_property_byname(prop_name); if (uc_property_is_valid(prop)) return PAT(PAT_PROPERTY, .property=prop); - uint32_t grapheme = unicode_name_character(prop_name); + ucs4_t grapheme = unicode_name_character(prop_name); if (grapheme == UNINAME_INVALID) fail("Not a valid property or character name: %s", prop_name); - return PAT(PAT_GRAPHEME, .grapheme=grapheme); + return PAT(PAT_GRAPHEME, .grapheme=(int32_t)grapheme); #undef PAT } else { - return (pat_t){.tag=PAT_GRAPHEME, .non_capturing=true, .min=1, .max=1, .grapheme=_next_grapheme(pattern, state, (*index)++)}; + return (pat_t){.tag=PAT_GRAPHEME, .non_capturing=true, .min=1, .max=1, .grapheme=_get_grapheme(pattern, state, (*index)++)}; } } @@ -1718,15 +1715,15 @@ static int64_t _find(Text_t text, Pattern_t pattern, int64_t first, int64_t last { int32_t first_grapheme = get_grapheme(pattern, 0); bool find_first = (first_grapheme != '{' - && !uc_is_property(first_grapheme, UC_PROPERTY_QUOTATION_MARK) - && !uc_is_property(first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK) + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); text_iter_t text_state = {0, 0}; for (int64_t i = first; i <= last; i++) { // Optimization: quickly skip ahead to first char in pattern: if (find_first) { - while (i < text.length && _next_grapheme(text, &text_state, i) != first_grapheme) + while (i < text.length && _get_grapheme(text, &text_state, i) != first_grapheme) ++i; } @@ -1753,13 +1750,13 @@ public Int_t Text$find(Text_t text, Pattern_t pattern, Int_t from_index, int64_t return I(found+1); } -public bool Text$has(Text_t text, Pattern_t pattern) +PUREFUNC public bool Text$has(Text_t text, Pattern_t pattern) { int64_t found = _find(text, pattern, 0, text.length-1, NULL); return (found >= 0); } -public bool Text$matches(Text_t text, Pattern_t pattern) +PUREFUNC public bool Text$matches(Text_t text, Pattern_t pattern) { int64_t m = match(text, 0, pattern, 0, NULL, 0); return m == text.length; @@ -1787,18 +1784,18 @@ static inline Text_t _quoted(Text_t text, bool colorize, char quote_char) { // TODO: optimize for ASCII and short strings Array_t graphemes = {.atomic=1}; -#define add_char(c) Array$insert_value(&graphemes, (uint32_t)c, I_small(0), sizeof(uint32_t)) -#define add_str(s) ({ for (char *_c = s; *_c; ++_c) Array$insert_value(&graphemes, (uint32_t)*_c, I_small(0), sizeof(uint32_t)); }) +#define add_char(c) Array$insert_value(&graphemes, (ucs4_t)c, I_small(0), sizeof(ucs4_t)) +#define add_str(s) ({ for (const char *_c = s; *_c; ++_c) Array$insert_value(&graphemes, (ucs4_t)*_c, I_small(0), sizeof(ucs4_t)); }) if (colorize) add_str("\x1b[35m"); - if (quote_char != '"' && quote_char != '\"' && quote_char != '`') + if (quote_char != '"' && quote_char != '\'' && quote_char != '`') add_char('$'); add_char(quote_char); #define add_escaped(str) ({ if (colorize) add_str("\x1b[34;1m"); add_char('\\'); add_str(str); if (colorize) add_str("\x1b[0;35m"); }) text_iter_t state = {0, 0}; for (int64_t i = 0; i < text.length; i++) { - int32_t g = _next_grapheme(text, &state, i); + int32_t g = _get_grapheme(text, &state, i); switch (g) { case '\a': add_escaped("a"); break; case '\b': add_escaped("b"); break; @@ -1886,8 +1883,8 @@ static Text_t apply_backrefs(Text_t text, Pattern_t original_pattern, Text_t rep int32_t first_grapheme = get_grapheme(backref_pat, 0); bool find_first = (first_grapheme != '{' - && !uc_is_property(first_grapheme, UC_PROPERTY_QUOTATION_MARK) - && !uc_is_property(first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK) + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); Text_t ret = Text(""); text_iter_t state = {0, 0}; @@ -1895,7 +1892,7 @@ static Text_t apply_backrefs(Text_t text, Pattern_t original_pattern, Text_t rep for (int64_t pos = 0; pos < replacement.length; ) { // Optimization: quickly skip ahead to first char in the backref pattern: if (find_first) { - while (pos < replacement.length && _next_grapheme(replacement, &state, pos) != first_grapheme) + while (pos < replacement.length && _get_grapheme(replacement, &state, pos) != first_grapheme) ++pos; } @@ -1914,7 +1911,7 @@ static Text_t apply_backrefs(Text_t text, Pattern_t original_pattern, Text_t rep if (backref < 0 || backref > 9) fail("Invalid backref index: %ld (only 0-%d are allowed)", backref, MAX_BACKREFS-1); backref_len = (after_backref - pos); - if (_next_grapheme(replacement, &state, pos + backref_len) == ';') + if (_get_grapheme(replacement, &state, pos + backref_len) == ';') backref_len += 1; // skip optional semicolon if (!captures[backref].occupied) @@ -1948,15 +1945,15 @@ public Text_t Text$replace(Text_t text, Pattern_t pattern, Text_t replacement, P int32_t first_grapheme = get_grapheme(pattern, 0); bool find_first = (first_grapheme != '{' - && !uc_is_property(first_grapheme, UC_PROPERTY_QUOTATION_MARK) - && !uc_is_property(first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK) + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); text_iter_t text_state = {0, 0}; int64_t nonmatching_pos = 0; for (int64_t pos = 0; pos < text.length; ) { // Optimization: quickly skip ahead to first char in pattern: if (find_first) { - while (pos < text.length && _next_grapheme(text, &text_state, pos) != first_grapheme) + while (pos < text.length && _get_grapheme(text, &text_state, pos) != first_grapheme) ++pos; } @@ -2015,8 +2012,8 @@ public Text_t Text$map(Text_t text, Pattern_t pattern, closure_t fn) int32_t first_grapheme = get_grapheme(pattern, 0); bool find_first = (first_grapheme != '{' - && !uc_is_property(first_grapheme, UC_PROPERTY_QUOTATION_MARK) - && !uc_is_property(first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK) + && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION)); text_iter_t text_state = {0, 0}; int64_t nonmatching_pos = 0; @@ -2025,7 +2022,7 @@ public Text_t Text$map(Text_t text, Pattern_t pattern, closure_t fn) for (int64_t pos = 0; pos < text.length; pos++) { // Optimization: quickly skip ahead to first char in pattern: if (find_first) { - while (pos < text.length && _next_grapheme(text, &text_state, pos) != first_grapheme) + while (pos < text.length && _get_grapheme(text, &text_state, pos) != first_grapheme) ++pos; } @@ -2130,6 +2127,7 @@ public Text_t Text$join(Text_t glue, Array_t pieces) return result; } +__attribute__((format(printf, 1, 2))) public Text_t Text$format(const char *fmt, ...) { va_list args; @@ -2146,8 +2144,8 @@ public Text_t Text$format(const char *fmt, ...) for (int i = 0; i < len; i++) ret.short_ascii[i] = buf[i]; } else { - char *str = GC_MALLOC_ATOMIC(len+1); - vsnprintf(str, len+1, fmt, args); + char *str = GC_MALLOC_ATOMIC((size_t)(len+1)); + vsnprintf(str, (size_t)(len+1), fmt, args); ret = Text$from_str(str); } va_end(args); @@ -2169,14 +2167,14 @@ public Array_t Text$utf32_codepoints(Text_t text) Array_t codepoints = {.atomic=1}; text_iter_t state = {0, 0}; for (int64_t i = 0; i < text.length; i++) { - int32_t grapheme = _next_grapheme(text, &state, i); + int32_t grapheme = _get_grapheme(text, &state, i); if (grapheme < 0) { for (int64_t c = 0; c < NUM_GRAPHEME_CODEPOINTS(grapheme); c++) { - int32_t subg = GRAPHEME_CODEPOINTS(grapheme)[c]; - Array$insert(&codepoints, &subg, I_small(0), sizeof(uint32_t)); + ucs4_t subg = GRAPHEME_CODEPOINTS(grapheme)[c]; + Array$insert(&codepoints, &subg, I_small(0), sizeof(ucs4_t)); } } else { - Array$insert(&codepoints, &grapheme, I_small(0), sizeof(uint32_t)); + Array$insert(&codepoints, &grapheme, I_small(0), sizeof(ucs4_t)); } } return codepoints; @@ -2188,7 +2186,7 @@ public Array_t Text$utf8_bytes(Text_t text) return (Array_t){.length=strlen(str), .stride=1, .atomic=1, .data=(void*)str}; } -static inline const char *codepoint_name(uint32_t c) +static inline const char *codepoint_name(ucs4_t c) { char *name = GC_MALLOC_ATOMIC(UNINAME_MAX); char *found_name = unicode_character_name(c, name); @@ -2204,16 +2202,16 @@ public Array_t Text$codepoint_names(Text_t text) Array_t names = {}; text_iter_t state = {0, 0}; for (int64_t i = 0; i < text.length; i++) { - int32_t grapheme = _next_grapheme(text, &state, i); + int32_t grapheme = _get_grapheme(text, &state, i); if (grapheme < 0) { for (int64_t c = 0; c < NUM_GRAPHEME_CODEPOINTS(grapheme); c++) { const char *name = codepoint_name(GRAPHEME_CODEPOINTS(grapheme)[c]); - Text_t name_text = (Text_t){.tag=TEXT_ASCII, .length=strlen(name), .ascii=name}; + Text_t name_text = (Text_t){.tag=TEXT_ASCII, .length=(int64_t)strlen(name), .ascii=name}; Array$insert(&names, &name_text, I_small(0), sizeof(Text_t)); } } else { - const char *name = codepoint_name(grapheme); - Text_t name_text = (Text_t){.tag=TEXT_ASCII, .length=strlen(name), .ascii=name}; + const char *name = codepoint_name((ucs4_t)grapheme); + Text_t name_text = (Text_t){.tag=TEXT_ASCII, .length=(int64_t)strlen(name), .ascii=name}; Array$insert(&names, &name_text, I_small(0), sizeof(Text_t)); } } @@ -2234,9 +2232,9 @@ public Text_t Text$from_codepoint_names(Array_t codepoint_names) for (int64_t i = 0; i < codepoint_names.length; i++) { Text_t *name = ((Text_t*)(codepoint_names.data + i*codepoint_names.stride)); const char *name_str = Text$as_c_string(*name); - uint32_t codepoint = unicode_name_character(name_str); + ucs4_t codepoint = unicode_name_character(name_str); if (codepoint != UNINAME_INVALID) - Array$insert(&codepoints, &codepoint, I_small(0), sizeof(uint32_t)); + Array$insert(&codepoints, &codepoint, I_small(0), sizeof(ucs4_t)); } return Text$from_codepoints(codepoints); } @@ -2256,8 +2254,8 @@ public Array_t Text$lines(Text_t text) Array_t lines = {}; text_iter_t state = {0, 0}; for (int64_t i = 0, line_start = 0; i < text.length; i++) { - int32_t grapheme = _next_grapheme(text, &state, i); - if (grapheme == '\r' && _next_grapheme(text, &state, i + 1) == '\n') { // CRLF + int32_t grapheme = _get_grapheme(text, &state, i); + if (grapheme == '\r' && _get_grapheme(text, &state, i + 1) == '\n') { // CRLF Text_t line = Text$slice(text, I(line_start+1), I(i)); Array$insert(&lines, &line, I_small(0), sizeof(Text_t)); i += 1; // skip one extra for CR @@ -2285,12 +2283,12 @@ public Pattern_t Pattern$escape_text(Text_t text) { // TODO: optimize for ASCII and short strings Array_t graphemes = {.atomic=1}; -#define add_char(c) Array$insert_value(&graphemes, (uint32_t)c, I_small(0), sizeof(uint32_t)) -#define add_str(s) ({ for (char *_c = s; *_c; ++_c) Array$insert_value(&graphemes, (uint32_t)*_c, I_small(0), sizeof(uint32_t)); }) +#define add_char(c) Array$insert_value(&graphemes, (ucs4_t)c, I_small(0), sizeof(ucs4_t)) +#define add_str(s) ({ for (const char *_c = s; *_c; ++_c) Array$insert_value(&graphemes, (ucs4_t)*_c, I_small(0), sizeof(ucs4_t)); }) text_iter_t state = {0, 0}; for (int64_t i = 0; i < text.length; i++) { - int32_t g = _next_grapheme(text, &state, i); - uint32_t g0 = g < 0 ? GRAPHEME_CODEPOINTS(g)[0] : (uint32_t)g; + int32_t g = _get_grapheme(text, &state, i); + ucs4_t g0 = g < 0 ? GRAPHEME_CODEPOINTS(g)[0] : (ucs4_t)g; if (g == '{') { add_str("{1{}"); diff --git a/builtins/text.h b/builtins/text.h index 56473e3a..a9fbf1a1 100644 --- a/builtins/text.h +++ b/builtins/text.h @@ -24,10 +24,10 @@ Text_t Text$_concat(int n, Text_t items[n]); Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int); Text_t Text$from_str(const char *str); Text_t Text$from_strn(const char *str, size_t len); -uint64_t Text$hash(Text_t *text); -int32_t Text$compare(const Text_t *a, const Text_t *b); -bool Text$equal(const Text_t *a, const Text_t *b); -bool Text$equal_ignoring_case(Text_t a, Text_t b); +PUREFUNC uint64_t Text$hash(Text_t *text); +PUREFUNC int32_t Text$compare(const Text_t *a, const Text_t *b); +PUREFUNC bool Text$equal(const Text_t *a, const Text_t *b); +PUREFUNC bool Text$equal_ignoring_case(Text_t a, Text_t b); Text_t Text$upper(Text_t text); Text_t Text$lower(Text_t text); Text_t Text$title(Text_t text); @@ -39,9 +39,10 @@ Array_t Text$split(Text_t text, Pattern_t pattern); Text_t Text$trim(Text_t text, Pattern_t pattern, bool trim_left, bool trim_right); Int_t Text$find(Text_t text, Pattern_t pattern, Int_t i, int64_t *match_length); Array_t Text$find_all(Text_t text, Pattern_t pattern); -bool Text$has(Text_t text, Pattern_t pattern); -bool Text$matches(Text_t text, Pattern_t pattern); +PUREFUNC bool Text$has(Text_t text, Pattern_t pattern); +PUREFUNC bool Text$matches(Text_t text, Pattern_t pattern); char *Text$as_c_string(Text_t text); +__attribute__((format(printf, 1, 2))) public Text_t Text$format(const char *fmt, ...); Array_t Text$clusters(Text_t text); Array_t Text$utf32_codepoints(Text_t text); diff --git a/builtins/types.h b/builtins/types.h index 0b48ab36..f06730a7 100644 --- a/builtins/types.h +++ b/builtins/types.h @@ -45,6 +45,7 @@ typedef struct TypeInfo { struct { const char *type_str; } TypeInfoInfo; +#pragma GCC diagnostic ignored "-Wpedantic" struct {} OpaqueInfo; struct { const char *name; diff --git a/builtins/util.c b/builtins/util.c index 4f108f04..20f60c01 100644 --- a/builtins/util.c +++ b/builtins/util.c @@ -12,6 +12,7 @@ public bool USE_COLOR; +__attribute__((format(printf, 1, 2))) public char *heap_strf(const char *fmt, ...) { va_list args; @@ -58,6 +59,7 @@ public char *mangle(const char *name) return mangled; } +__attribute__((format(printf, 1, 2))) public CORD CORD_asprintf(CORD fmt, ...) { va_list args; @@ -72,6 +74,7 @@ public CORD CORD_quoted(CORD str) { CORD quoted = "\""; CORD_pos i; +#pragma GCC diagnostic ignored "-Wsign-conversion" CORD_FOR(i, str) { char c = CORD_pos_fetch(i); switch (c) { diff --git a/builtins/util.h b/builtins/util.h index a3f5f2b4..01f9b269 100644 --- a/builtins/util.h +++ b/builtins/util.h @@ -27,9 +27,19 @@ #define public __attribute__ ((visibility ("default"))) #endif +#ifndef PUREFUNC +#define PUREFUNC __attribute__ ((pure)) +#endif + +#ifndef CONSTFUNC +#define CONSTFUNC __attribute__ ((const)) +#endif + extern bool USE_COLOR; +__attribute__((format(printf, 1, 2))) char *heap_strf(const char *fmt, ...); +__attribute__((format(printf, 1, 2))) CORD CORD_asprintf(CORD fmt, ...); CORD CORD_quoted(CORD str); CORD CORD_replace(CORD c, CORD to_replace, CORD replacement); @@ -1401,6 +1401,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t CORD code = CORD_EMPTY; env_t *default_scope = global_scope(env); for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) { + int64_t i = 1; // Find keyword: if (spec_arg->name) { for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { @@ -1428,7 +1429,6 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t } } // Find positional: - int64_t i = 1; for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { if (call_arg->name) continue; const char *pseudoname = heap_strf("%ld", i++); @@ -1555,6 +1555,7 @@ static CORD compile_string_literal(CORD literal) { CORD code = "\""; CORD_pos i; +#pragma GCC diagnostic ignored "-Wsign-conversion" CORD_FOR(i, literal) { char c = CORD_pos_fetch(i); switch (c) { @@ -2939,10 +2940,8 @@ CORD compile(env_t *env, ast_t *ast) case Declare: case Assign: case UpdateAssign: case For: case While: case StructDef: case LangDef: case EnumDef: case FunctionDef: case Skip: case Stop: case Pass: case Return: case DocTest: case PrintStatement: code_err(ast, "This is not a valid expression"); - case Unknown: code_err(ast, "Unknown AST"); + default: case Unknown: code_err(ast, "Unknown AST"); } - code_err(ast, "Unknown AST: %W", ast); - return CORD_EMPTY; } void compile_namespace(env_t *env, const char *ns_name, ast_t *block) @@ -12,7 +12,7 @@ #include "typecheck.h" #include "builtins/util.h" -static bool has_extra_data(tag_ast_t *tags) +PUREFUNC static bool has_extra_data(tag_ast_t *tags) { for (tag_ast_t *tag = tags; tag; tag = tag->next) { if (tag->fields) return true; diff --git a/environment.c b/environment.c index d09f0a65..be0db696 100644 --- a/environment.c +++ b/environment.c @@ -576,7 +576,8 @@ void set_binding(env_t *env, const char *name, binding_t *binding) Table$str_set(env->locals, name, binding); } -void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...) +__attribute__((format(printf, 4, 5))) +_Noreturn void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...) { if (isatty(STDERR_FILENO) && !getenv("NO_COLOR")) fputs("\x1b[31;7;1m", stderr); diff --git a/environment.h b/environment.h index 86b8cc6c..f54ecccc 100644 --- a/environment.h +++ b/environment.h @@ -71,8 +71,8 @@ env_t *global_scope(env_t *env); env_t *fresh_scope(env_t *env); env_t *for_scope(env_t *env, ast_t *ast); env_t *namespace_env(env_t *env, const char *namespace_name); -__attribute__((noreturn)) -void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...); +__attribute__((format(printf, 4, 5))) +_Noreturn void compiler_err(file_t *f, const char *start, const char *end, const char *fmt, ...); binding_t *get_binding(env_t *env, const char *name); binding_t *get_lang_escape_function(env_t *env, const char *lang_name, type_t *type_to_escape); void set_binding(env_t *env, const char *name, binding_t *binding); @@ -40,8 +40,6 @@ extern void builtin_fail(const char *fmt, ...); #define PARSER(name) ast_t *name(parse_ctx_t *ctx, const char *pos) -#define STUB_PARSER(name) PARSER(name) { (void)ctx; (void)pos; return NULL; } - int op_tightness[] = { [BINOP_POWER]=9, [BINOP_MULT]=8, [BINOP_DIVIDE]=8, [BINOP_MOD]=8, [BINOP_MOD1]=8, @@ -54,7 +52,6 @@ int op_tightness[] = { [BINOP_CMP]=2, [BINOP_AND]=1, [BINOP_OR]=1, [BINOP_XOR]=1, }; -#define MAX_TIGHTNESS 9 static const char *keywords[] = { "yes", "xor", "while", "when", "use", "struct", "stop", "skip", "return", @@ -122,8 +119,8 @@ static type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos); // // Print a parse error and exit (or use the on_err longjmp) // -__attribute__((noreturn)) -static void vparser_err(parse_ctx_t *ctx, const char *start, const char *end, const char *fmt, va_list args) { +__attribute__((noreturn, format(printf, 4, 0))) +static _Noreturn void vparser_err(parse_ctx_t *ctx, const char *start, const char *end, const char *fmt, va_list args) { if (isatty(STDERR_FILENO) && !getenv("NO_COLOR")) fputs("\x1b[31;1;7m", stderr); fprintf(stderr, "%s:%ld.%ld: ", ctx->file->relative_filename, get_line_number(ctx->file, start), @@ -149,8 +146,8 @@ static void vparser_err(parse_ctx_t *ctx, const char *start, const char *end, co // // Wrapper for vparser_err // -__attribute__((noreturn)) -static void parser_err(parse_ctx_t *ctx, const char *start, const char *end, const char *fmt, ...) { +__attribute__((noreturn, format(printf, 4, 5))) +static _Noreturn void parser_err(parse_ctx_t *ctx, const char *start, const char *end, const char *fmt, ...) { va_list args; va_start(args, fmt); vparser_err(ctx, start, end, fmt, args); @@ -160,10 +157,11 @@ static void parser_err(parse_ctx_t *ctx, const char *start, const char *end, con // // Convert an escape sequence like \n to a string // +#pragma GCC diagnostic ignored "-Wstack-protector" static const char *unescape(parse_ctx_t *ctx, const char **out) { const char **endpos = out; const char *escape = *out; - static const char *unescapes[256] = {['a']="\a",['b']="\b",['e']="\e",['f']="\f",['n']="\n",['r']="\r",['t']="\t",['v']="\v",['_']=" "}; + static const char *unescapes[256] = {['a']="\a",['b']="\b",['e']="\x1b",['f']="\f",['n']="\n",['r']="\r",['t']="\t",['v']="\v",['_']=" "}; assert(*escape == '\\'); if (unescapes[(int)escape[1]]) { *endpos = escape + 2; @@ -210,12 +208,12 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) { } } -static inline int64_t get_indent(parse_ctx_t *ctx, const char *pos) +PUREFUNC static inline int64_t get_indent(parse_ctx_t *ctx, const char *pos) { int64_t line_num = get_line_number(ctx->file, pos); const char *line = get_line(ctx->file, line_num); if (*line == ' ') { - int64_t spaces = strspn(line, " "); + int64_t spaces = (int64_t)strspn(line, " "); if (spaces % SPACES_PER_INDENT != 0) parser_err(ctx, line + spaces - (spaces % SPACES_PER_INDENT), line + spaces, "Indentation must be a multiple of 4 spaces, not %ld", spaces); @@ -224,7 +222,7 @@ static inline int64_t get_indent(parse_ctx_t *ctx, const char *pos) parser_err(ctx, line + indent, line + indent + 1, "This is a tab following spaces, and you can't mix tabs and spaces"); return indent; } else if (*line == '\t') { - int64_t indent = strspn(line, "\t"); + int64_t indent = (int64_t)strspn(line, "\t"); if (line[indent] == ' ') parser_err(ctx, line + indent, line + indent + 1, "This is a space following tabs, and you can't mix tabs and spaces"); return indent; @@ -283,6 +281,7 @@ static inline bool is_xid_continue_next(const char *pos) { // // Expect a string (potentially after whitespace) and emit a parser error if it's not there // +__attribute__((format(printf, 5, 6))) static void expect_str( parse_ctx_t *ctx, const char *start, const char **pos, const char *target, const char *fmt, ...) { spaces(pos); @@ -305,6 +304,7 @@ static void expect_str( // // Helper for matching closing parens with good error messages // +__attribute__((format(printf, 4, 5))) static void expect_closing( parse_ctx_t *ctx, const char **pos, const char *close_str, const char *fmt, ...) { const char *start = *pos; @@ -466,7 +466,7 @@ PARSER(parse_parens) { PARSER(parse_int) { const char *start = pos; (void)match(&pos, "-"); - if (!isdigit(*pos)) return false; + if (!isdigit(*pos)) return NULL; if (match(&pos, "0x")) { // Hex pos += strspn(pos, "0123456789abcdefABCDEF_"); } else if (match(&pos, "0b")) { // Binary @@ -2168,7 +2168,7 @@ PARSER(parse_doctest) { int64_t trailing_spaces = 0; while (output_end - trailing_spaces - 1 > output_start && (output_end[-trailing_spaces-1] == ' ' || output_end[-trailing_spaces-1] == '\t')) ++trailing_spaces; - output = GC_strndup(output_start, (size_t)(output_end - output_start) - trailing_spaces); + output = GC_strndup(output_start, (size_t)((output_end - output_start) - trailing_spaces)); pos = output_end; } else { pos = expr->end; @@ -73,7 +73,7 @@ void repl(void) printf("\n"); } -__attribute__((noreturn)) +__attribute__((noreturn, format(printf, 2, 3))) static void repl_err(ast_t *node, const char *fmt, ...) { bool color = isatty(STDERR_FILENO) && !getenv("NO_COLOR"); @@ -331,6 +331,7 @@ void run(env_t *env, ast_t *ast) } } +#pragma GCC diagnostic ignored "-Wstack-protector" void eval(env_t *env, ast_t *ast, void *dest) { type_t *t = get_type(env, ast); @@ -512,7 +513,7 @@ void eval(env_t *env, ast_t *ast, void *dest) char item_buf[item_size] = {}; for (ast_list_t *item = Match(ast, Array)->items; item; item = item->next) { eval(env, item->ast, item_buf); - Array$insert(&arr, item_buf, I(0), padded_type_size(Match(t, ArrayType)->item_type)); + Array$insert(&arr, item_buf, I(0), (int64_t)padded_type_size(Match(t, ArrayType)->item_type)); } memcpy(dest, &arr, sizeof(Array_t)); break; @@ -34,6 +34,7 @@ static int compile_object_file(const char *filename, bool force_recompile); static int compile_executable(env_t *base_env, const char *filename, CORD object_files); static void build_file_dependency_graph(const char *filename, Table_t *to_compile, Table_t *to_link); +#pragma GCC diagnostic ignored "-Wstack-protector" int main(int argc, char *argv[]) { mode_e mode = MODE_RUN; @@ -349,9 +350,7 @@ void build_file_dependency_graph(const char *filename, Table_t *to_compile, Tabl Table$str_set(to_link, lib, lib); break; } - case USE_HEADER: { - break; - } + default: case USE_HEADER: break; } } free(file_dir); diff --git a/typecheck.c b/typecheck.c index bde73ea5..70d94dbf 100644 --- a/typecheck.c +++ b/typecheck.c @@ -17,6 +17,7 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) { +#pragma GCC diagnostic ignored "-Wswitch-default" switch (ast->tag) { case VarTypeAST: { const char *name = Match(ast, VarTypeAST)->name; @@ -110,10 +111,10 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) } case UnknownTypeAST: code_err(ast, "I don't know how to get this type"); } - code_err(ast, "I don't know how to get this type"); + errx(1, "Unreachable"); } -type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t) +PUREFUNC type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t) { (void)env; switch (compare_precision(lhs_t, rhs_t)) { @@ -1300,7 +1301,7 @@ type_t *get_type(env_t *env, ast_t *ast) code_err(ast, "I can't figure out the type of: %W", ast); } -bool is_discardable(env_t *env, ast_t *ast) +PUREFUNC bool is_discardable(env_t *env, ast_t *ast) { switch (ast->tag) { case UpdateAssign: case Assign: case Declare: case FunctionDef: case StructDef: case EnumDef: @@ -1360,7 +1361,7 @@ type_t *get_arg_type(env_t *env, arg_t *arg) return get_type(env, arg->default_val); } -bool can_be_mutated(env_t *env, ast_t *ast) +PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast) { switch (ast->tag) { case Var: return true; @@ -1395,7 +1396,7 @@ type_t *parse_type_string(env_t *env, const char *str) return ast ? parse_type_ast(env, ast) : NULL; } -bool is_constant(env_t *env, ast_t *ast) +PUREFUNC bool is_constant(env_t *env, ast_t *ast) { switch (ast->tag) { case Bool: case Num: case Nil: case TextLiteral: return true; @@ -1414,6 +1415,7 @@ bool is_constant(env_t *env, ast_t *ast) CORD literal = Match(text->children->ast, TextLiteral)->cord; CORD_pos i; +#pragma GCC diagnostic ignored "-Wsign-conversion" CORD_FOR(i, literal) { if (!isascii(CORD_pos_fetch(i))) return false; // Non-ASCII requires grapheme logic, not constant diff --git a/typecheck.h b/typecheck.h index bca21ba8..d328f8b5 100644 --- a/typecheck.h +++ b/typecheck.h @@ -15,16 +15,16 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast); type_t *get_type(env_t *env, ast_t *ast); void prebind_statement(env_t *env, ast_t *statement); void bind_statement(env_t *env, ast_t *statement); -type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t); -bool is_discardable(env_t *env, ast_t *ast); +PUREFUNC type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t); +PUREFUNC bool is_discardable(env_t *env, ast_t *ast); type_t *get_file_type(env_t *env, const char *path); type_t *get_function_def_type(env_t *env, ast_t *ast); type_t *get_arg_type(env_t *env, arg_t *arg); type_t *get_arg_ast_type(env_t *env, arg_ast_t *arg); type_t *get_clause_type(env_t *env, type_t *subject_t, when_clause_t *clause); -bool can_be_mutated(env_t *env, ast_t *ast); +PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast); type_t *parse_type_string(env_t *env, const char *str); type_t *get_method_type(env_t *env, ast_t *self, const char *name); -bool is_constant(env_t *env, ast_t *ast); +PUREFUNC bool is_constant(env_t *env, ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -128,7 +128,7 @@ static type_t *non_optional(type_t *t) return ptr->is_optional ? Type(PointerType, .is_optional=false, .pointed=ptr->pointed) : t; } -type_t *value_type(type_t *t) +PUREFUNC type_t *value_type(type_t *t) { while (t->tag == PointerType) t = Match(t, PointerType)->pointed; @@ -156,7 +156,7 @@ type_t *type_or_type(type_t *a, type_t *b) return NULL; } -static inline double type_min_magnitude(type_t *t) +static PUREFUNC inline double type_min_magnitude(type_t *t) { switch (t->tag) { case BoolType: return (double)false; @@ -175,7 +175,7 @@ static inline double type_min_magnitude(type_t *t) } } -static inline double type_max_magnitude(type_t *t) +static PUREFUNC inline double type_max_magnitude(type_t *t) { switch (t->tag) { case BoolType: return (double)true; @@ -194,7 +194,7 @@ static inline double type_max_magnitude(type_t *t) } } -precision_cmp_e compare_precision(type_t *a, type_t *b) +PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b) { double a_min = type_min_magnitude(a), b_min = type_min_magnitude(b), @@ -209,7 +209,7 @@ precision_cmp_e compare_precision(type_t *a, type_t *b) else return NUM_PRECISION_INCOMPARABLE; } -bool has_heap_memory(type_t *t) +PUREFUNC bool has_heap_memory(type_t *t) { switch (t->tag) { case ArrayType: return true; @@ -236,7 +236,7 @@ bool has_heap_memory(type_t *t) } } -bool can_send_over_channel(type_t *t) +PUREFUNC bool can_send_over_channel(type_t *t) { switch (t->tag) { case ArrayType: return true; @@ -261,7 +261,7 @@ bool can_send_over_channel(type_t *t) } } -bool has_stack_memory(type_t *t) +PUREFUNC bool has_stack_memory(type_t *t) { switch (t->tag) { case PointerType: return Match(t, PointerType)->is_stack; @@ -269,7 +269,7 @@ bool has_stack_memory(type_t *t) } } -bool can_promote(type_t *actual, type_t *needed) +PUREFUNC bool can_promote(type_t *actual, type_t *needed) { // No promotion necessary: if (type_eq(actual, needed)) @@ -354,7 +354,7 @@ bool can_promote(type_t *actual, type_t *needed) return false; } -bool can_leave_uninitialized(type_t *t) +PUREFUNC bool can_leave_uninitialized(type_t *t) { switch (t->tag) { case PointerType: return Match(t, PointerType)->is_optional; @@ -379,7 +379,7 @@ bool can_leave_uninitialized(type_t *t) } } -static bool _can_have_cycles(type_t *t, Table_t *seen) +PUREFUNC static bool _can_have_cycles(type_t *t, Table_t *seen) { switch (t->tag) { case ArrayType: return _can_have_cycles(Match(t, ArrayType)->item_type, seen); @@ -408,18 +408,18 @@ static bool _can_have_cycles(type_t *t, Table_t *seen) } } -bool can_have_cycles(type_t *t) +PUREFUNC bool can_have_cycles(type_t *t) { Table_t seen = {0}; return _can_have_cycles(t, &seen); } -bool is_int_type(type_t *t) +PUREFUNC bool is_int_type(type_t *t) { return t->tag == IntType || t->tag == BigIntType; } -bool is_numeric_type(type_t *t) +PUREFUNC bool is_numeric_type(type_t *t) { return t->tag == IntType || t->tag == BigIntType || t->tag == NumType; } @@ -468,8 +468,9 @@ type_t *replace_type(type_t *t, type_t *target, type_t *replacement) #undef REPLACED_MEMBER } -size_t type_size(type_t *t) +PUREFUNC size_t type_size(type_t *t) { +#pragma GCC diagnostic ignored "-Wswitch-default" switch (t->tag) { case UnknownType: case AbortType: case ReturnType: case VoidType: return 0; case MemoryType: errx(1, "Memory has undefined type size"); @@ -531,7 +532,7 @@ size_t type_size(type_t *t) errx(1, "This should not be reachable"); } -size_t type_align(type_t *t) +PUREFUNC size_t type_align(type_t *t) { switch (t->tag) { case UnknownType: case AbortType: case ReturnType: case VoidType: return 0; @@ -580,7 +581,7 @@ size_t type_align(type_t *t) errx(1, "This should not be reachable"); } -size_t padded_type_size(type_t *t) +PUREFUNC size_t padded_type_size(type_t *t) { size_t size = type_size(t); size_t align = type_align(t); @@ -129,24 +129,24 @@ struct type_s { int printf_pointer_size(const struct printf_info *info, size_t n, int argtypes[n], int size[n]); int printf_type(FILE *stream, const struct printf_info *info, const void *const args[]); CORD type_to_cord(type_t *t); -bool type_eq(type_t *a, type_t *b); -bool type_is_a(type_t *t, type_t *req); +PUREFUNC bool type_eq(type_t *a, type_t *b); +PUREFUNC bool type_is_a(type_t *t, type_t *req); type_t *type_or_type(type_t *a, type_t *b); type_t *value_type(type_t *a); typedef enum {NUM_PRECISION_EQUAL, NUM_PRECISION_LESS, NUM_PRECISION_MORE, NUM_PRECISION_INCOMPARABLE} precision_cmp_e; -precision_cmp_e compare_precision(type_t *a, type_t *b); -bool has_heap_memory(type_t *t); -bool has_stack_memory(type_t *t); -bool can_send_over_channel(type_t *t); -bool can_promote(type_t *actual, type_t *needed); -bool can_leave_uninitialized(type_t *t); -bool can_have_cycles(type_t *t); -bool is_int_type(type_t *t); -bool is_numeric_type(type_t *t); +PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b); +PUREFUNC bool has_heap_memory(type_t *t); +PUREFUNC bool has_stack_memory(type_t *t); +PUREFUNC bool can_send_over_channel(type_t *t); +PUREFUNC bool can_promote(type_t *actual, type_t *needed); +PUREFUNC bool can_leave_uninitialized(type_t *t); +PUREFUNC bool can_have_cycles(type_t *t); +PUREFUNC bool is_int_type(type_t *t); +PUREFUNC bool is_numeric_type(type_t *t); type_t *replace_type(type_t *t, type_t *target, type_t *replacement); -size_t type_size(type_t *t); -size_t type_align(type_t *t); -size_t padded_type_size(type_t *t); +PUREFUNC size_t type_size(type_t *t); +PUREFUNC size_t type_align(type_t *t); +PUREFUNC size_t padded_type_size(type_t *t); type_t *get_field_type(type_t *t, const char *field_name); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 |
